Metal setup merge (#1616)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Alex Cristici <alex.cristici@gmail.com>
Co-authored-by: mwilsnd <mwilsnd@gmail.com>
Co-authored-by: Stefan Karschti <stefan.karschti@gmail.com>
Co-authored-by: Bart Louwers <bart@emeel.net>
Co-authored-by: Alex Cristici <alex@skoon.energy>
Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
Co-authored-by: Wei Chen <alanchenboy@gmail.com>
Co-authored-by: Siarhei Fedartsou <siarhei.fedartsou@gmail.com>
Co-authored-by: tdcosta100 <tdcosta100@gmail.com>
This commit is contained in:
Tim Sylvester
2023-09-13 11:35:20 -07:00
committed by GitHub
parent 085b0ced6d
commit 82ec59a2b0
284 changed files with 32357 additions and 1155 deletions

View File

@@ -3,6 +3,7 @@
#include <mbgl/gfx/debug_group.hpp>
#include <memory>
#include <string>
namespace mbgl {
namespace gfx {
@@ -26,8 +27,9 @@ public:
CommandEncoder& operator=(const CommandEncoder&) = delete;
DebugGroup<CommandEncoder> createDebugGroup(const char* name) { return {*this, name}; }
DebugGroup<CommandEncoder> createDebugGroup(std::string_view name) { return createDebugGroup(name.data()); }
virtual std::unique_ptr<UploadPass> createUploadPass(const char* name) = 0;
virtual std::unique_ptr<UploadPass> createUploadPass(const char* name, Renderable&) = 0;
virtual std::unique_ptr<RenderPass> createRenderPass(const char* name, const RenderPassDescriptor&) = 0;
virtual void present(Renderable&) = 0;
};

View File

@@ -167,6 +167,7 @@ void DrawableBuilder::setSegments(const gfx::DrawMode mode,
gfx::IndexVectorBasePtr indexes,
const SegmentBase* segments,
const std::size_t segmentCount) {
assert(indexes && indexes->elements());
impl->sharedIndexes = std::move(indexes);
for (std::size_t i = 0; i < segmentCount; ++i) {
const auto& seg = segments[i];

View File

@@ -3,8 +3,8 @@
#include <mbgl/gfx/draw_mode.hpp>
#include <mbgl/util/ignore.hpp>
#include <vector>
#include <memory>
#include <vector>
namespace mbgl {
namespace gfx {
@@ -84,6 +84,8 @@ protected:
bool released = false;
};
using IndexVectorBasePtr = std::shared_ptr<IndexVectorBase>;
template <class DrawMode>
class IndexVector final : public IndexVectorBase {
public:

View File

@@ -4,7 +4,6 @@
#include <mbgl/util/color.hpp>
#include <cstdint>
#include <optional>
namespace mbgl {
namespace gfx {
@@ -26,6 +25,7 @@ protected:
friend class DebugGroup<RenderPass>;
virtual void pushDebugGroup(const char* name) = 0;
virtual void popDebugGroup() = 0;
virtual void addDebugSignpost(const char*) {}
public:
virtual ~RenderPass() = default;

View File

@@ -15,6 +15,7 @@
#endif
#include <optional>
#include <string>
#include <vector>
namespace mbgl {
@@ -43,6 +44,7 @@ public:
UploadPass& operator=(const UploadPass&) = delete;
DebugGroup<UploadPass> createDebugGroup(const char* name) { return {*this, name}; }
DebugGroup<UploadPass> createDebugGroup(std::string_view name) { return createDebugGroup(name.data()); }
#if MLN_DRAWABLE_RENDERER
virtual Context& getContext() = 0;

View File

@@ -9,6 +9,10 @@
namespace mbgl {
namespace gfx {
namespace {
const UniqueVertexAttribute nullref;
} // namespace
std::size_t VertexAttribute::getCount() const {
return sharedRawData ? sharedRawData->getRawCount() : items.size();
}
@@ -90,5 +94,15 @@ void VertexAttributeArray::resolve(const VertexAttributeArray& overrides, Resolv
}
}
const UniqueVertexAttribute& VertexAttributeArray::add(std::string name, std::unique_ptr<VertexAttribute>&& attr) {
const auto result = attrs.insert(std::make_pair(std::move(name), std::unique_ptr<VertexAttribute>()));
if (result.second) {
result.first->second = std::move(attr);
return result.first->second;
} else {
return nullref;
}
}
} // namespace gfx
} // namespace mbgl

View File

@@ -2,8 +2,8 @@
#include <mbgl/util/ignore.hpp>
#include <vector>
#include <memory>
#include <vector>
namespace mbgl {
namespace gfx {

View File

@@ -16,7 +16,7 @@ CommandEncoder::~CommandEncoder() {
context.performCleanup();
}
std::unique_ptr<gfx::UploadPass> CommandEncoder::createUploadPass(const char* name) {
std::unique_ptr<gfx::UploadPass> CommandEncoder::createUploadPass(const char* name, gfx::Renderable&) {
return std::make_unique<gl::UploadPass>(*this, name);
}

View File

@@ -17,7 +17,7 @@ public:
friend class UploadPass;
friend class RenderPass;
std::unique_ptr<gfx::UploadPass> createUploadPass(const char* name) override;
std::unique_ptr<gfx::UploadPass> createUploadPass(const char* name, gfx::Renderable&) override;
std::unique_ptr<gfx::RenderPass> createRenderPass(const char* name, const gfx::RenderPassDescriptor&) override;
void present(gfx::Renderable&) override;

View File

@@ -480,8 +480,11 @@ gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t
gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) {
std::vector<std::string> emptyProperties(0);
return std::static_pointer_cast<gfx::ShaderProgramBase>(
shaders.getShaderGroup(name)->getOrCreateShader(*this, emptyProperties));
auto shaderGroup = shaders.getShaderGroup(name);
if (!shaderGroup) {
return nullptr;
}
return std::static_pointer_cast<gfx::ShaderProgramBase>(shaderGroup->getOrCreateShader(*this, emptyProperties));
}
TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) {

View File

@@ -17,6 +17,7 @@ DrawableGL::DrawableGL(std::string name_)
impl(std::make_unique<Impl>()) {}
DrawableGL::~DrawableGL() {
impl->indexBuffer = {0, nullptr};
impl->attributeBuffers.clear();
}

View File

@@ -40,6 +40,7 @@ public:
VertexAttributeArrayGL vertexAttributes;
gfx::IndexBuffer indexBuffer = {0, nullptr};
std::vector<gfx::UniqueVertexBufferResource> attributeBuffers;
UniformBufferArrayGL uniformBuffers;

View File

@@ -52,22 +52,32 @@ public:
static std::unique_ptr<Instance> createInstance(gl::Context& context,
const ProgramParameters& programParameters,
const std::string& additionalDefines) {
#if MLN_RENDER_BACKEND_OPENGL
constexpr auto backend = gfx::Backend::Type::OpenGL;
#elif MLN_RENDER_BACKEND_METAL
constexpr auto backend = gfx::Backend::Type::Metal;
#endif
#if MLN_RENDER_BACKEND_METAL
return std::make_unique<Instance>(context);
#else
// Compile the shader
std::initializer_list<const char*> vertexSource = {
"#version 300 es\n",
programParameters.getDefines().c_str(),
programParameters.getDefinesString().c_str(),
additionalDefines.c_str(),
shaders::ShaderSource<shaders::BuiltIn::Prelude, gfx::Backend::Type::OpenGL>::vertex,
shaders::ShaderSource<shaders::BuiltIn::Prelude, backend>::vertex,
programParameters.vertexSource(gfx::Backend::Type::OpenGL).c_str()};
std::initializer_list<const char*> fragmentSource = {
"#version 300 es\n",
programParameters.getDefines().c_str(),
programParameters.getDefinesString().c_str(),
additionalDefines.c_str(),
shaders::ShaderSource<shaders::BuiltIn::Prelude, gfx::Backend::Type::OpenGL>::fragment,
shaders::ShaderSource<shaders::BuiltIn::Prelude, backend>::fragment,
programParameters.fragmentSource(gfx::Backend::Type::OpenGL).c_str()};
return std::make_unique<Instance>(context, vertexSource, fragmentSource);
#endif
}
UniqueProgram program;

View File

@@ -28,7 +28,7 @@ UniformBufferGL::~UniformBufferGL() {
}
void UniformBufferGL::update(const void* data_, std::size_t size_) {
assert(size == size_); // && size == data.size());
assert(size == size_);
if (size != size_) {
Log::Error(
Event::General,

View File

@@ -0,0 +1,44 @@
#include <mbgl/mtl/buffer_resource.hpp>
#include <Metal/MTLDevice.hpp>
namespace mbgl {
namespace mtl {
BufferResource::BufferResource(MTLDevicePtr device_, const void* data, std::size_t size, MTL::ResourceOptions usage_)
: device(std::move(device_)),
usage(usage_) {
if (data && size) {
buffer = NS::TransferPtr(device->newBuffer(data, static_cast<NS::UInteger>(size), usage));
} else {
buffer = NS::TransferPtr(device->newBuffer(static_cast<NS::UInteger>(size), usage));
}
}
BufferResource::BufferResource(const BufferResource& other)
: device(other.device),
usage(other.usage) {
if (other.buffer) {
buffer = NS::TransferPtr(device->newBuffer(other.buffer->contents(), other.buffer->length(), other.usage));
}
}
BufferResource::BufferResource(BufferResource&& other)
: device(std::move(other.device)),
buffer(std::move(other.buffer)),
usage(other.usage) {}
void BufferResource::update(const void* data, std::size_t size, std::size_t offset) {
assert(buffer && (data || size == 0));
if (buffer && data && size > 0) {
assert(buffer->contents());
if (void* content = buffer->contents()) {
const auto size_ = std::min(size, static_cast<std::size_t>(buffer->length()) - offset);
assert(size == size_);
std::memcpy(static_cast<uint8_t*>(content) + offset, data, size_);
}
}
}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,92 @@
#include <mbgl/mtl/command_encoder.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/render_pass.hpp>
#include <mbgl/mtl/renderable_resource.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <Metal/Metal.hpp>
#include <cstring>
namespace mbgl {
namespace mtl {
CommandEncoder::CommandEncoder(Context& context_)
: context(context_) {}
CommandEncoder::~CommandEncoder() {
context.performCleanup();
}
std::unique_ptr<gfx::UploadPass> CommandEncoder::createUploadPass(const char* name, gfx::Renderable& renderable) {
return std::make_unique<UploadPass>(renderable, *this, name);
}
std::unique_ptr<gfx::RenderPass> CommandEncoder::createRenderPass(const char* name,
const gfx::RenderPassDescriptor& descriptor) {
return std::make_unique<RenderPass>(*this, name, descriptor);
}
void CommandEncoder::present(gfx::Renderable& renderable) {
renderable.getResource<RenderableResource>().swap();
}
void CommandEncoder::pushDebugGroup(const char* name) {
// Debug groups exist in MTLBuffer and MTLCommandEncoder, but these are associated with the
// renderable provided in the RenderPassDescriptor, and so may not have been created yet.
// Instead, maintain a stack of names and push them to each render pass as we create it.
debugGroupNames.push_back({name ? name : std::string(), renderPasses.size(), uploadPasses.size()});
// Apply it to any groups that are already active
for (auto* pass : renderPasses) {
renderDebugGroups.emplace_back(gfx::DebugGroup<gfx::RenderPass>{*pass, name});
}
for (auto* pass : uploadPasses) {
uploadDebugGroups.emplace_back(gfx::DebugGroup<gfx::UploadPass>{*pass, name});
}
}
void CommandEncoder::popDebugGroup() {
assert(!debugGroupNames.empty());
if (!debugGroupNames.empty()) {
// Pop the entries we added for each active encoder when this item was added
for (std::size_t i = 0; i < debugGroupNames.back().renderGroups; ++i) {
assert(!renderDebugGroups.empty());
if (!renderDebugGroups.empty()) {
renderDebugGroups.pop_back();
}
}
for (std::size_t i = 0; i < debugGroupNames.back().uploadGroups; ++i) {
assert(!uploadDebugGroups.empty());
if (!uploadDebugGroups.empty()) {
uploadDebugGroups.pop_back();
}
}
debugGroupNames.pop_back();
}
}
void CommandEncoder::trackRenderPass(RenderPass* pass) {
if (pass) {
renderPasses.insert(pass);
}
}
void CommandEncoder::forgetRenderPass(RenderPass* pass) {
renderPasses.erase(pass);
}
void CommandEncoder::trackUploadPass(UploadPass* pass) {
if (pass) {
uploadPasses.insert(pass);
}
}
void CommandEncoder::forgetUploadPass(UploadPass* pass) {
uploadPasses.erase(pass);
}
} // namespace mtl
} // namespace mbgl

210
src/mbgl/mtl/context.cpp Normal file
View File

@@ -0,0 +1,210 @@
#include <mbgl/mtl/context.hpp>
#include <mbgl/gfx/shader_registry.hpp>
#include <mbgl/mtl/command_encoder.hpp>
#include <mbgl/mtl/drawable_builder.hpp>
#include <mbgl/mtl/layer_group.hpp>
#include <mbgl/mtl/renderer_backend.hpp>
#include <mbgl/mtl/renderable_resource.hpp>
#include <mbgl/mtl/texture2d.hpp>
#include <mbgl/mtl/tile_layer_group.hpp>
#include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/programs/program_parameters.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/shaders/mtl/shader_program.hpp>
#include <mbgl/util/traits.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/logging.hpp>
#include <Foundation/Foundation.hpp>
#include <Metal/Metal.hpp>
#include <algorithm>
#include <cstring>
namespace mbgl {
namespace mtl {
// Maximum number of vertex attributes, per vertex descriptor
// 31 for Apple2-8, Mac2, per https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
constexpr uint32_t maximumVertexBindingCount = 31;
Context::Context(RendererBackend& backend_)
: gfx::Context(mtl::maximumVertexBindingCount),
backend(backend_),
stats() {}
Context::~Context() noexcept {
if (cleanupOnDestruction) {
performCleanup();
assert(stats.isZero());
}
}
std::unique_ptr<gfx::CommandEncoder> Context::createCommandEncoder() {
return std::make_unique<CommandEncoder>(*this);
}
BufferResource Context::createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const {
return {backend.getDevice(), data, size, MTL::ResourceStorageModeShared};
}
UniqueShaderProgram Context::createProgram(std::string name,
const std::string_view source,
const std::string_view vertexName,
const std::string_view fragmentName,
const ProgramParameters& programParameters,
const std::unordered_map<std::string, std::string>& additionalDefines) {
const auto pool = NS::TransferPtr(NS::AutoreleasePool::alloc()->init());
// No NSMutableDictionary?
const auto& programDefines = programParameters.getDefines();
const auto numDefines = programDefines.size() + additionalDefines.size();
std::vector<NS::Object*> rawDefines;
rawDefines.reserve(2 * numDefines);
const auto addDefine = [&rawDefines](const auto& pair) {
auto* nsKey = NS::String::string(pair.first.data(), NS::UTF8StringEncoding);
auto* nsVal = NS::String::string(pair.second.data(), NS::UTF8StringEncoding);
rawDefines.insert(std::next(rawDefines.begin(), rawDefines.size() / 2), nsKey);
rawDefines.insert(rawDefines.end(), nsVal);
};
std::for_each(programDefines.begin(), programDefines.end(), addDefine);
std::for_each(additionalDefines.begin(), additionalDefines.end(), addDefine);
const auto nsDefines = NS::Dictionary::dictionary(
&rawDefines[numDefines], rawDefines.data(), static_cast<NS::UInteger>(numDefines));
rawDefines.clear();
auto options = NS::TransferPtr(MTL::CompileOptions::alloc()->init());
options->setPreprocessorMacros(nsDefines);
options->setFastMathEnabled(true);
options->setLanguageVersion(MTL::LanguageVersion2_1);
// TODO: Compile common code into a `LibraryTypeDynamic` to be used by other shaders
// instead of duplicating that code in each and every shader compilation.
options->setLibraryType(MTL::LibraryTypeExecutable);
// Allows use of the [[invariant]] attribute on position outputs to
// guarantee that the GPU performs the calculations the same way.
options->setPreserveInvariance(true);
// TODO: Allow use of `LibraryOptimizationLevelSize` which "may also reduce compile time"
// requires a check for iOS 16+
// options->setOptimizationLevel(MTL::LibraryOptimizationLevelDefault);
NS::Error* error = nullptr;
NS::String* nsSource = NS::String::string(source.data(), NS::UTF8StringEncoding);
const auto& device = backend.getDevice();
MTL::Library* library = device->newLibrary(nsSource, options.get(), &error);
if (!library || error) {
const auto errPtr = error ? error->localizedDescription()->utf8String() : nullptr;
const auto errStr = (errPtr && errPtr[0]) ? ": " + std::string(errPtr) : std::string();
Log::Error(Event::Shader, name + " compile failed" + errStr);
assert(false);
return nullptr;
}
const auto nsVertName = NS::String::string(vertexName.data(), NS::UTF8StringEncoding);
NS::SharedPtr<MTL::Function> vertexFunction = NS::RetainPtr(library->newFunction(nsVertName));
if (!vertexFunction) {
Log::Error(Event::Shader, name + " missing vertex function " + vertexName.data());
assert(false);
return nullptr;
}
// fragment function is optional
NS::SharedPtr<MTL::Function> fragmentFunction;
if (!fragmentName.empty()) {
const auto nsFragName = NS::String::string(fragmentName.data(), NS::UTF8StringEncoding);
fragmentFunction = NS::RetainPtr(library->newFunction(nsFragName));
if (!fragmentFunction) {
Log::Error(Event::Shader, name + " missing fragment function " + fragmentName.data());
assert(false);
return nullptr;
}
}
return std::make_unique<ShaderProgram>(
std::move(name), backend, std::move(vertexFunction), std::move(fragmentFunction));
}
MTLTexturePtr Context::createMetalTexture(MTLTextureDescriptorPtr textureDescriptor) const {
return NS::TransferPtr(backend.getDevice()->newTexture(textureDescriptor.get()));
}
MTLSamplerStatePtr Context::createMetalSamplerState(MTLSamplerDescriptorPtr samplerDescriptor) const {
return NS::TransferPtr(backend.getDevice()->newSamplerState(samplerDescriptor.get()));
}
gfx::UniqueDrawableBuilder Context::createDrawableBuilder(std::string name) {
return std::make_unique<DrawableBuilder>(std::move(name));
}
gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size) {
return std::make_shared<UniformBuffer>(createBuffer(data, size, gfx::BufferUsageType::StaticDraw));
}
gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) {
std::vector<std::string> emptyProperties(0);
auto shaderGroup = shaders.getShaderGroup(name);
if (!shaderGroup) {
return nullptr;
}
return std::static_pointer_cast<gfx::ShaderProgramBase>(shaderGroup->getOrCreateShader(*this, emptyProperties));
}
TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) {
return std::make_shared<TileLayerGroup>(layerIndex, initialCapacity, std::move(name));
}
LayerGroupPtr Context::createLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) {
return std::make_shared<LayerGroup>(layerIndex, initialCapacity, name);
}
gfx::Texture2DPtr Context::createTexture2D() {
return std::make_shared<Texture2D>(*this);
}
RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) {
assert(false);
return nullptr;
}
void Context::resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) {}
void Context::setDirtyState() {}
std::unique_ptr<gfx::OffscreenTexture> Context::createOffscreenTexture(Size, gfx::TextureChannelDataType) {
assert(false);
return nullptr;
}
std::unique_ptr<gfx::TextureResource> Context::createTextureResource(Size,
gfx::TexturePixelType,
gfx::TextureChannelDataType) {
assert(false);
return nullptr;
}
std::unique_ptr<gfx::RenderbufferResource> Context::createRenderbufferResource(gfx::RenderbufferPixelType, Size size) {
return std::make_unique<RenderbufferResource>();
}
std::unique_ptr<gfx::DrawScopeResource> Context::createDrawScopeResource() {
assert(false);
return nullptr;
}
#if !defined(NDEBUG)
void Context::visualizeStencilBuffer() {}
void Context::visualizeDepthBuffer(float depthRangeSize) {}
#endif // !defined(NDEBUG)
void Context::clearStencilBuffer(int32_t) {}
} // namespace mtl
} // namespace mbgl

517
src/mbgl/mtl/drawable.cpp Normal file
View File

@@ -0,0 +1,517 @@
#include <mbgl/mtl/drawable.hpp>
#include <mbgl/gfx/color_mode.hpp>
#include <mbgl/mtl/command_encoder.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/drawable_impl.hpp>
#include <mbgl/mtl/index_buffer_resource.hpp>
#include <mbgl/mtl/render_pass.hpp>
#include <mbgl/mtl/renderable_resource.hpp>
#include <mbgl/mtl/texture2d.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/vertex_buffer_resource.hpp>
#include <mbgl/mtl/vertex_attribute.hpp>
#include <mbgl/programs/segment.hpp>
#include <mbgl/shaders/mtl/shader_program.hpp>
#include <mbgl/util/logging.hpp>
#include <Metal/Metal.hpp>
#include <simd/simd.h>
#include <cassert>
namespace mbgl {
namespace mtl {
struct IndexBuffer : public gfx::IndexBufferBase {
IndexBuffer(std::unique_ptr<gfx::IndexBuffer>&& buffer_)
: buffer(std::move(buffer_)) {}
~IndexBuffer() override = default;
std::unique_ptr<mbgl::gfx::IndexBuffer> buffer;
};
Drawable::Drawable(std::string name_)
: gfx::Drawable(std::move(name_)),
impl(std::make_unique<Impl>()) {}
Drawable::~Drawable() {}
namespace {
// Downcast a generic vertex buffer resource and extract the Metal buffer
MTL::Buffer* getMetalBuffer(const gfx::VertexBufferResource* resource_) {
if (const auto* resource = static_cast<const VertexBufferResource*>(resource_)) {
if (const auto& bufferResource = resource->get()) {
return bufferResource.getMetalBuffer().get();
}
}
return nullptr;
}
#if !defined(NDEBUG)
std::size_t getBufferSize(const gfx::VertexBufferResource* resource_) {
if (const auto* resource = static_cast<const VertexBufferResource*>(resource_)) {
if (const auto& bufferResource = resource->get()) {
return bufferResource.getSizeInBytes();
}
}
return 0UL;
}
#endif // !defined(NDEBUG)
MTL::PrimitiveType getPrimitiveType(const gfx::DrawModeType type) {
switch (type) {
default:
assert(false);
[[fallthrough]];
case gfx::DrawModeType::Points:
return MTL::PrimitiveType::PrimitiveTypePoint;
case gfx::DrawModeType::Lines:
return MTL::PrimitiveType::PrimitiveTypeLine;
case gfx::DrawModeType::Triangles:
return MTL::PrimitiveType::PrimitiveTypeTriangle;
}
}
#if !defined(NDEBUG)
std::string debugLabel(const gfx::Drawable& drawable) {
std::string result = drawable.getName();
if (const auto& tileID = drawable.getTileID()) {
result.append("/tile=").append(util::toString(*tileID));
}
return result;
}
#endif // !defined(NDEBUG)
MTL::Buffer* getMetalBuffer(const gfx::IndexVectorBasePtr& indexes) {
if (const auto* buf0 = indexes->getBuffer()) {
if (const auto* buf1 = static_cast<const IndexBuffer*>(buf0)->buffer.get()) {
const auto& buf2 = buf1->getResource<IndexBufferResource>().get();
return buf2.getMetalBuffer().get();
}
}
return nullptr;
}
} // namespace
void Drawable::draw(PaintParameters& parameters) const {
if (isCustom) {
return;
}
const auto& context = static_cast<Context&>(parameters.context);
const auto& renderPass = static_cast<RenderPass&>(*parameters.renderPass);
const auto& encoder = renderPass.getMetalEncoder();
if (!encoder) {
assert(false);
return;
}
if (!shader) {
Log::Warning(Event::General, "Missing shader for drawable " + util::toString(getID()) + "/" + getName());
assert(false);
return;
}
const auto& shaderMTL = static_cast<const ShaderProgram&>(*shader);
#if !defined(NDEBUG)
const auto debugGroup = parameters.encoder->createDebugGroup(debugLabel(*this));
#endif
/*
context.setDepthMode(getIs3D() ? parameters.depthModeFor3D()
: parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()));
// force disable depth test for debugging
// context.setDepthMode({gfx::DepthFunctionType::Always, gfx::DepthMaskType::ReadOnly, {0,1}});
// For 3D mode, stenciling is handled by the layer group
if (!is3D) {
context.setStencilMode(makeStencilMode(parameters));
}
context.setColorMode(getColorMode());
context.setCullFaceMode(getCullFaceMode());
*/
bindAttributes(renderPass);
bindUniformBuffers(renderPass);
bindTextures(renderPass);
const auto& renderPassDescriptor = renderPass.getDescriptor();
if (!impl->indexes->getBuffer() || impl->indexes->getDirty()) {
assert(!"Index buffer not uploaded");
return;
}
const auto* indexBuffer = getMetalBuffer(impl->indexes);
if (!indexBuffer || impl->indexes->getDirty()) {
assert(!"Index buffer not uploaded");
return;
}
if (!impl->vertexDesc) {
assert(!"Vertex descriptor missing");
}
for (const auto& seg_ : impl->segments) {
const auto& segment = static_cast<DrawSegment&>(*seg_);
const auto& mlSegment = segment.getSegment();
if (mlSegment.indexLength > 0) {
const auto& mode = segment.getMode();
if (auto state = shaderMTL.getRenderPipelineState(renderPassDescriptor, impl->vertexDesc, getColorMode())) {
encoder->setRenderPipelineState(state.get());
} else {
assert(!"Failed to create render pipeline state");
continue;
}
const auto primitiveType = getPrimitiveType(mode.type);
constexpr auto indexType = MTL::IndexType::IndexTypeUInt16;
constexpr auto indexSize = sizeof(std::uint16_t);
constexpr NS::UInteger instanceCount = 1;
constexpr NS::UInteger baseInstance = 0;
const NS::UInteger indexOffset = static_cast<NS::UInteger>(indexSize *
mlSegment.indexOffset); // in bytes, not indexes
const NS::Integer baseVertex = static_cast<NS::Integer>(mlSegment.vertexOffset);
encoder->drawIndexedPrimitives(primitiveType,
mlSegment.indexLength,
indexType,
indexBuffer,
indexOffset,
instanceCount,
baseVertex,
baseInstance);
}
}
unbindTextures(renderPass);
unbindUniformBuffers(renderPass);
unbindAttributes(renderPass);
}
void Drawable::setIndexData(gfx::IndexVectorBasePtr indexes, std::vector<UniqueDrawSegment> segments) {
assert(indexes && indexes->elements());
impl->indexes = std::move(indexes);
impl->segments = std::move(segments);
}
void Drawable::setVertices(std::vector<uint8_t>&& data, std::size_t count, gfx::AttributeDataType type) {
impl->vertexCount = count;
impl->vertexType = type;
if (count && type != gfx::AttributeDataType::Invalid && !data.empty() && !impl->vertexAttrName.empty()) {
if (auto& attrib = impl->vertexAttributes.getOrAdd(impl->vertexAttrName, /*index=*/-1, type)) {
attrib->setRawData(std::move(data));
attrib->setStride(VertexAttribute::getStrideOf(type));
} else {
Log::Warning(Event::General, "Vertex attribute type mismatch: " + name + " / " + impl->vertexAttrName);
assert(false);
}
}
}
const gfx::VertexAttributeArray& Drawable::getVertexAttributes() const {
return impl->vertexAttributes;
}
gfx::VertexAttributeArray& Drawable::mutableVertexAttributes() {
return impl->vertexAttributes;
}
void Drawable::setVertexAttributes(const gfx::VertexAttributeArray& value) {
impl->vertexAttributes = static_cast<const VertexAttributeArray&>(value);
}
void Drawable::setVertexAttributes(gfx::VertexAttributeArray&& value) {
impl->vertexAttributes = std::move(static_cast<VertexAttributeArray&&>(value));
}
const gfx::UniformBufferArray& Drawable::getUniformBuffers() const {
return impl->uniformBuffers;
}
gfx::UniformBufferArray& Drawable::mutableUniformBuffers() {
return impl->uniformBuffers;
}
void Drawable::setVertexAttrName(std::string value) {
impl->vertexAttrName = std::move(value);
}
void Drawable::bindAttributes(const RenderPass& renderPass) const {
const auto& encoder = renderPass.getMetalEncoder();
NS::UInteger attributeIndex = 0;
for (const auto& binding : attributeBindings) {
if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) {
assert(getBufferSize(binding->vertexBufferResource) == binding->vertexStride * impl->vertexCount);
encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex);
} else if (const auto buffer = getMetalBuffer(impl->noBindingBuffer.get())) {
encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex);
}
attributeIndex += 1;
}
}
void Drawable::unbindAttributes(const RenderPass& renderPass) const {
const auto& encoder = renderPass.getMetalEncoder();
NS::UInteger attributeIndex = 0;
for (const auto& binding : attributeBindings) {
encoder->setVertexBuffer(nullptr, /*offset=*/0, attributeIndex);
attributeIndex += 1;
}
}
void Drawable::bindUniformBuffers(const RenderPass& renderPass) const {
if (shader) {
const auto& shaderMTL = static_cast<const ShaderProgram&>(*shader);
const auto& encoder = renderPass.getMetalEncoder();
for (const auto& element : shaderMTL.getUniformBlocks().getMap()) {
const auto& uniformBuffer = getUniformBuffers().get(element.first);
if (!uniformBuffer) {
using namespace std::string_literals;
Log::Error(Event::General,
"Drawable::bindUniformBuffers: UBO "s + element.first + " not found. skipping.");
assert(false);
continue;
}
const auto& buffer = static_cast<UniformBuffer&>(*uniformBuffer.get());
const auto& bufferMTL = buffer.getBufferResource().getMetalBuffer().get();
const auto& block = static_cast<const UniformBlock&>(*element.second);
const auto index = block.getIndex();
if (block.getBindVertex()) {
encoder->setVertexBuffer(bufferMTL, /*offset=*/0, index);
}
if (block.getBindFragment()) {
encoder->setFragmentBuffer(bufferMTL, /*offset=*/0, index);
}
}
}
}
void Drawable::unbindUniformBuffers(const RenderPass& renderPass) const {
if (shader) {
const auto& shaderMTL = static_cast<const ShaderProgram&>(*shader);
const auto& encoder = renderPass.getMetalEncoder();
for (const auto& element : shaderMTL.getUniformBlocks().getMap()) {
const auto index = element.second->getIndex();
encoder->setVertexBuffer(nullptr, 0, index);
}
}
}
void Drawable::bindTextures(const RenderPass& renderPass) const {
for (const auto& pair : textures) {
if (const auto& tex = pair.second) {
const auto& location = pair.first;
std::static_pointer_cast<mtl::Texture2D>(tex)->bind(renderPass, location);
}
}
}
void Drawable::unbindTextures(const RenderPass& renderPass) const {
for (const auto& pair : textures) {
if (const auto& tex = pair.second) {
const auto& location = pair.first;
std::static_pointer_cast<mtl::Texture2D>(tex)->unbind(renderPass, location);
}
}
}
void Drawable::uploadTextures() const {
for (const auto& pair : textures) {
if (const auto& tex = pair.second) {
std::static_pointer_cast<mtl::Texture2D>(tex)->upload();
}
}
}
namespace {
MTL::VertexFormat mtlVertexTypeOf(gfx::AttributeDataType type) {
switch (type) {
case gfx::AttributeDataType::Byte:
return MTL::VertexFormatChar;
case gfx::AttributeDataType::Byte2:
return MTL::VertexFormatChar2;
case gfx::AttributeDataType::Byte3:
return MTL::VertexFormatChar3;
case gfx::AttributeDataType::Byte4:
return MTL::VertexFormatChar4;
case gfx::AttributeDataType::UByte:
return MTL::VertexFormatUChar;
case gfx::AttributeDataType::UByte2:
return MTL::VertexFormatUChar2;
case gfx::AttributeDataType::UByte3:
return MTL::VertexFormatUChar3;
case gfx::AttributeDataType::UByte4:
return MTL::VertexFormatUChar4;
case gfx::AttributeDataType::Short:
return MTL::VertexFormatShort;
case gfx::AttributeDataType::Short2:
return MTL::VertexFormatShort2;
case gfx::AttributeDataType::Short3:
return MTL::VertexFormatShort3;
case gfx::AttributeDataType::Short4:
return MTL::VertexFormatShort4;
case gfx::AttributeDataType::UShort:
return MTL::VertexFormatUShort;
case gfx::AttributeDataType::UShort2:
return MTL::VertexFormatUShort2;
case gfx::AttributeDataType::UShort3:
return MTL::VertexFormatUShort3;
case gfx::AttributeDataType::UShort4:
return MTL::VertexFormatUShort4;
// case gfx::AttributeDataType::UShort8: return MTL::VertexFormatUShort8;
case gfx::AttributeDataType::Int:
return MTL::VertexFormatInt;
case gfx::AttributeDataType::Int2:
return MTL::VertexFormatInt2;
case gfx::AttributeDataType::Int3:
return MTL::VertexFormatInt3;
case gfx::AttributeDataType::Int4:
return MTL::VertexFormatInt4;
case gfx::AttributeDataType::UInt:
return MTL::VertexFormatUInt;
case gfx::AttributeDataType::UInt2:
return MTL::VertexFormatUInt2;
case gfx::AttributeDataType::UInt3:
return MTL::VertexFormatUInt3;
case gfx::AttributeDataType::UInt4:
return MTL::VertexFormatUInt4;
case gfx::AttributeDataType::Float:
return MTL::VertexFormatFloat;
case gfx::AttributeDataType::Float2:
return MTL::VertexFormatFloat2;
case gfx::AttributeDataType::Float3:
return MTL::VertexFormatFloat3;
case gfx::AttributeDataType::Float4:
return MTL::VertexFormatFloat4;
default:
assert(!"Unsupported vertex attribute format");
return MTL::VertexFormatInvalid;
}
}
} // namespace
void Drawable::upload(gfx::UploadPass& uploadPass_) {
if (!shader) {
Log::Warning(Event::General, "Missing shader for drawable " + util::toString(getID()) + "/" + getName());
assert(false);
return;
}
const auto& shaderMTL = static_cast<const ShaderProgram&>(*shader);
const auto& shaderUniforms = shaderMTL.getUniformBlocks();
auto& uploadPass = static_cast<UploadPass&>(uploadPass_);
auto& contextBase = uploadPass.getContext();
auto& context = static_cast<Context&>(contextBase);
constexpr auto usage = gfx::BufferUsageType::StaticDraw;
if (!impl->indexes || !impl->indexes->bytes()) {
assert(!"Missing index data");
return;
}
if (impl->indexes->getDirty()) {
auto indexBufferResource{
uploadPass.createIndexBufferResource(impl->indexes->data(), impl->indexes->bytes(), usage)};
auto indexBuffer = std::make_unique<gfx::IndexBuffer>(impl->indexes->elements(),
std::move(indexBufferResource));
auto buffer = std::make_unique<IndexBuffer>(std::move(indexBuffer));
impl->indexes->setBuffer(std::move(buffer));
impl->indexes->setDirty(false);
}
const bool buildAttribs = impl->vertexAttributes.isDirty() || !impl->vertexDesc;
if (buildAttribs) {
#if !defined(NDEBUG)
const auto debugGroup = uploadPass.createDebugGroup(debugLabel(*this));
#endif
// Apply drawable values to shader defaults
std::vector<std::unique_ptr<gfx::VertexBufferResource>> vertexBuffers;
attributeBindings = uploadPass.buildAttributeBindings(impl->vertexCount,
impl->vertexType,
/*vertexAttributeIndex=*/-1,
/*vertexData=*/{},
shader->getVertexAttributes(),
impl->vertexAttributes,
usage,
vertexBuffers);
impl->attributeBuffers = std::move(vertexBuffers);
impl->vertexAttributes.visitAttributes(
[](const auto&, gfx::VertexAttribute& attrib) { attrib.setDirty(false); });
// Create a layout descriptor for each attribute
auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor());
NS::UInteger index = 0;
for (auto& binding : attributeBindings) {
if (!binding) {
assert("Missing attribute binding");
continue;
}
if (!binding->vertexBufferResource && !impl->noBindingBuffer) {
impl->noBindingBuffer = uploadPass.createVertexBufferResource(
nullptr, 64, gfx::BufferUsageType::StaticDraw);
}
auto attribDesc = NS::TransferPtr(MTL::VertexAttributeDescriptor::alloc()->init());
attribDesc->setBufferIndex(index);
attribDesc->setOffset(static_cast<NS::UInteger>(binding->attribute.offset));
attribDesc->setFormat(mtlVertexTypeOf(binding->attribute.dataType));
assert(binding->vertexStride > 0);
auto layoutDesc = NS::TransferPtr(MTL::VertexBufferLayoutDescriptor::alloc()->init());
layoutDesc->setStride(static_cast<NS::UInteger>(binding->vertexStride));
layoutDesc->setStepFunction(binding->vertexBufferResource ? MTL::VertexStepFunctionPerVertex
: MTL::VertexStepFunctionConstant);
layoutDesc->setStepRate(binding->vertexBufferResource ? 1 : 0);
vertDesc->attributes()->setObject(attribDesc.get(), index);
vertDesc->layouts()->setObject(layoutDesc.get(), index);
index += 1;
}
impl->vertexDesc = std::move(vertDesc);
}
const bool texturesNeedUpload = std::any_of(
textures.begin(), textures.end(), [](const auto& pair) { return pair.second && pair.second->needsUpload(); });
if (texturesNeedUpload) {
uploadTextures();
}
}
/*
gfx::ColorMode Drawable::makeColorMode(PaintParameters& parameters) const {
return enableColor ? parameters.colorModeForRenderPass() : gfx::ColorMode::disabled();
}
gfx::StencilMode Drawable::makeStencilMode(PaintParameters& parameters) const {
if (enableStencil) {
if (!is3D && tileID) {
return parameters.stencilModeForClipping(tileID->toUnwrapped());
}
assert(false);
}
return gfx::StencilMode::disabled();
}
*/
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,49 @@
#include <mbgl/mtl/drawable_builder.hpp>
#include <mbgl/gfx/drawable_builder_impl.hpp>
#include <mbgl/gfx/drawable_impl.hpp>
#include <mbgl/mtl/drawable.hpp>
#include <mbgl/mtl/drawable_impl.hpp>
#include <mbgl/util/convert.hpp>
#include <cstring>
namespace mbgl {
namespace mtl {
gfx::UniqueDrawable DrawableBuilder::createDrawable() const {
return std::make_unique<Drawable>(drawableName.empty() ? name : drawableName);
};
std::unique_ptr<gfx::Drawable::DrawSegment> DrawableBuilder::createSegment(gfx::DrawMode mode, SegmentBase&& seg) {
return std::make_unique<Drawable::DrawSegment>(mode, std::move(seg));
}
void DrawableBuilder::init() {
auto& drawable = static_cast<Drawable&>(*currentDrawable);
drawable.setVertexAttrName(vertexAttrName);
if (impl->rawVerticesCount) {
auto raw = impl->rawVertices;
drawable.setVertices(std::move(raw), impl->rawVerticesCount, impl->rawVerticesType);
} else {
const auto& verts = impl->vertices.vector();
constexpr auto vertSize = sizeof(std::remove_reference<decltype(verts)>::type::value_type);
std::vector<uint8_t> raw(verts.size() * vertSize);
std::memcpy(raw.data(), verts.data(), raw.size());
drawable.setVertices(std::move(raw), verts.size(), gfx::AttributeDataType::Short2);
}
if (!impl->sharedIndexes && !impl->buildIndexes.empty()) {
impl->sharedIndexes = std::make_shared<gfx::IndexVectorBase>(std::move(impl->buildIndexes));
}
drawable.setIndexData(std::move(impl->sharedIndexes), std::move(impl->segments));
impl->buildIndexes.clear();
impl->segments.clear();
impl->vertices.clear();
}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,68 @@
#pragma once
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/drawable_impl.hpp>
#include <mbgl/gfx/index_buffer.hpp>
#include <mbgl/gfx/program.hpp>
#include <mbgl/gfx/uniform.hpp>
#include <mbgl/gfx/uniform_buffer.hpp>
#include <mbgl/gfx/vertex_attribute.hpp>
#include <mbgl/mtl/mtl_fwd.hpp>
#include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/programs/segment.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/util/mat4.hpp>
#include <Foundation/NSSharedPtr.hpp>
#include <Metal/MTLVertexDescriptor.hpp>
#include <cstdint>
#include <memory>
#include <vector>
namespace mbgl {
namespace mtl {
using namespace platform;
class Drawable::Impl final {
public:
Impl() = default;
~Impl() = default;
std::vector<UniqueDrawSegment> segments;
MTLVertexDescriptorPtr vertexDesc;
/*
std::vector<TextureID> textures;
*/
gfx::IndexVectorBasePtr indexes;
std::size_t vertexCount = 0;
gfx::AttributeDataType vertexType = gfx::AttributeDataType::Invalid;
gfx::VertexAttributeArray vertexAttributes;
std::vector<gfx::UniqueVertexBufferResource> attributeBuffers;
UniformBufferArray uniformBuffers;
gfx::DepthMode depthMode = gfx::DepthMode::disabled();
gfx::StencilMode stencilMode;
gfx::CullFaceMode cullFaceMode;
// GLfloat pointSize = 0.0f;
std::string vertexAttrName = "a_pos";
gfx::UniqueVertexBufferResource noBindingBuffer;
};
struct Drawable::DrawSegment final : public gfx::Drawable::DrawSegment {
DrawSegment(gfx::DrawMode mode_, SegmentBase&& segment_)
: gfx::Drawable::DrawSegment(mode_, std::move(segment_)) {}
~DrawSegment() override = default;
protected:
};
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,60 @@
#include <mbgl/mtl/layer_group.hpp>
#include <mbgl/gfx/drawable_tweaker.hpp>
#include <mbgl/gfx/render_pass.hpp>
#include <mbgl/gfx/renderable.hpp>
#include <mbgl/gfx/renderer_backend.hpp>
#include <mbgl/gfx/upload_pass.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/drawable.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/shaders/mtl/shader_program.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
namespace mtl {
LayerGroup::LayerGroup(int32_t layerIndex_, std::size_t initialCapacity, std::string name_)
: mbgl::LayerGroup(layerIndex_, initialCapacity, std::move(name_)) {}
void LayerGroup::upload(gfx::UploadPass& uploadPass) {
if (!enabled) {
return;
}
#if !defined(NDEBUG)
const auto debugGroup = uploadPass.createDebugGroup(getName() + "-upload");
#endif
visitDrawables([&](gfx::Drawable& drawable) {
if (drawable.getEnabled()) {
auto& drawableMTL = static_cast<mtl::Drawable&>(drawable);
drawableMTL.upload(uploadPass);
}
});
}
void LayerGroup::render(RenderOrchestrator&, PaintParameters& parameters) {
if (!enabled) {
return;
}
#if !defined(NDEBUG)
const auto debugGroup = parameters.encoder->createDebugGroup(getName() + "-render");
#endif
visitDrawables([&](gfx::Drawable& drawable) {
if (!drawable.getEnabled() || !drawable.hasRenderPass(parameters.pass)) {
return;
}
for (const auto& tweaker : drawable.getTweakers()) {
tweaker->execute(drawable, parameters);
}
drawable.draw(parameters);
});
}
} // namespace mtl
} // namespace mbgl

9
src/mbgl/mtl/mtl.cpp Normal file
View File

@@ -0,0 +1,9 @@
// metal-cpp is a header-only library.
// To generate the implementation,
// add the following code in one of your .cpp files:
#define NS_PRIVATE_IMPLEMENTATION
#define CA_PRIVATE_IMPLEMENTATION
#define MTL_PRIVATE_IMPLEMENTATION
#include <Foundation/Foundation.hpp>
#include <Metal/Metal.hpp>
#include <QuartzCore/QuartzCore.hpp>

View File

@@ -0,0 +1,94 @@
#include <mbgl/mtl/render_pass.hpp>
#include <mbgl/mtl/command_encoder.hpp>
#include <mbgl/mtl/renderable_resource.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/util/logging.hpp>
#include <Metal/Metal.hpp>
namespace mbgl {
namespace mtl {
RenderPass::RenderPass(CommandEncoder& commandEncoder_, const char* name, const gfx::RenderPassDescriptor& descriptor)
: descriptor(descriptor),
commandEncoder(commandEncoder_) {
auto& resource = descriptor.renderable.getResource<RenderableResource>();
if (!resource.getCommandBuffer()) {
resource.bind();
}
if (const auto& buffer = resource.getCommandBuffer()) {
if (auto rpd = resource.getRenderPassDescriptor()) {
if (descriptor.clearColor) {
if (auto copy = NS::TransferPtr(rpd->copy())) {
if (auto* colorTarget = copy->colorAttachments()->object(0)) {
const auto& c = *descriptor.clearColor;
colorTarget->setClearColor(MTL::ClearColor::Make(c.r, c.g, c.b, c.a));
rpd = copy;
}
}
}
encoder = NS::RetainPtr(buffer->renderCommandEncoder(rpd.get()));
}
}
assert(encoder);
// Push the groups already accumulated by the encoder
commandEncoder.visitDebugGroups([this](const auto& group) {
debugGroups.emplace_back(gfx::DebugGroup<gfx::RenderPass>{*this, group.c_str()});
});
// Push the group for the name provided
debugGroups.emplace_back(gfx::DebugGroup<gfx::RenderPass>{*this, name});
// Let the encoder pass along any groups pushed to it after this
commandEncoder.trackRenderPass(this);
}
RenderPass::~RenderPass() {
commandEncoder.forgetRenderPass(this);
endEncoding();
}
void RenderPass::endEncoding() {
debugGroups.clear();
if (encoder) {
encoder->endEncoding();
encoder.reset();
}
}
namespace {
constexpr auto missing = "<none>";
NS::String* toNSString(const char* str) {
return NS::String::string(str ? str : missing, NS::UTF8StringEncoding);
}
} // namespace
void RenderPass::pushDebugGroup(const char* name) {
assert(encoder);
if (encoder) {
encoder->pushDebugGroup(toNSString(name));
}
}
void RenderPass::popDebugGroup() {
assert(encoder);
if (encoder) {
encoder->popDebugGroup();
}
}
void RenderPass::addDebugSignpost(const char* name) {
assert(encoder);
if (encoder) {
encoder->insertDebugSignpost(toNSString(name));
}
}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,138 @@
#include <mbgl/mtl/renderer_backend.hpp>
#include <mbgl/gfx/backend_scope.hpp>
#include <mbgl/gfx/shader_registry.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/shaders/background_layer_ubo.hpp>
#include <mbgl/shaders/mtl/shader_group.hpp>
#include <mbgl/shaders/mtl/shader_program.hpp>
#include <mbgl/shaders/shader_manifest.hpp>
#include <mbgl/util/logging.hpp>
// ... shader_manifest.hpp
#include <mbgl/shaders/mtl/background.hpp>
#include <mbgl/shaders/mtl/background_pattern.hpp>
#include <mbgl/shaders/mtl/circle.hpp>
#include <mbgl/shaders/mtl/line.hpp>
#include <mbgl/shaders/mtl/line_gradient.hpp>
#include <mbgl/shaders/mtl/fill.hpp>
#include <mbgl/shaders/mtl/raster.hpp>
#include <cassert>
#include <string>
namespace mbgl {
namespace mtl {
RendererBackend::RendererBackend(const gfx::ContextMode contextMode_)
: gfx::RendererBackend(contextMode_),
device(NS::TransferPtr(MTL::CreateSystemDefaultDevice())),
commandQueue(NS::TransferPtr(device->newCommandQueue())) {
assert(device);
assert(commandQueue);
}
RendererBackend::~RendererBackend() = default;
std::unique_ptr<gfx::Context> RendererBackend::createContext() {
return std::make_unique<mtl::Context>(*this);
}
PremultipliedImage RendererBackend::readFramebuffer(const Size& size) {
return PremultipliedImage(size);
// return getContext<mtl::Context>().readFramebuffer<PremultipliedImage>(size);
}
void RendererBackend::assumeFramebufferBinding(const mtl::FramebufferID fbo) {
/*getContext<mtl::Context>().bindFramebuffer.setCurrentValue(fbo);
if (fbo != ImplicitFramebufferBinding) {
assert(mtl::value::BindFramebuffer::Get() == getContext<mtl::Context>().bindFramebuffer.getCurrentValue());
}*/
}
void RendererBackend::assumeViewport(int32_t x, int32_t y, const Size& size) {
/*getContext<mtl::Context>().viewport.setCurrentValue({x, y, size});
assert(mtl::value::Viewport::Get() == getContext<mtl::Context>().viewport.getCurrentValue());*/
}
void RendererBackend::assumeScissorTest(bool enabled) {
/*getContext<mtl::Context>().scissorTest.setCurrentValue(enabled);
assert(mtl::value::ScissorTest::Get() == getContext<mtl::Context>().scissorTest.getCurrentValue());*/
}
bool RendererBackend::implicitFramebufferBound() {
return false;
// return getContext<mtl::Context>().bindFramebuffer.getCurrentValue() == ImplicitFramebufferBinding;
}
void RendererBackend::setFramebufferBinding(const mtl::FramebufferID fbo) {
/*getContext<mtl::Context>().bindFramebuffer = fbo;
if (fbo != ImplicitFramebufferBinding) {
assert(mtl::value::BindFramebuffer::Get() == getContext<mtl::Context>().bindFramebuffer.getCurrentValue());
}*/
}
void RendererBackend::setViewport(int32_t x, int32_t y, const Size& size) {
/*getContext<mtl::Context>().viewport = {x, y, size};
assert(mtl::value::Viewport::Get() == getContext<mtl::Context>().viewport.getCurrentValue());*/
}
void RendererBackend::setScissorTest(bool enabled) {
/*getContext<mtl::Context>().scissorTest = enabled;
assert(mtl::value::ScissorTest::Get() == getContext<mtl::Context>().scissorTest.getCurrentValue());*/
}
/// @brief Register a list of types with a shader registry instance
/// @tparam ...ShaderID Pack of BuiltIn:: shader IDs
/// @param registry A shader registry instance
/// @param programParameters ProgramParameters used to initialize each instance
template <shaders::BuiltIn... ShaderID>
void registerTypes(gfx::ShaderRegistry& registry, const ProgramParameters& programParameters) {
/// The following fold expression will create a shader for every type
/// in the parameter pack and register it with the shader registry.
/// Registration calls are wrapped in a lambda that throws on registration
/// failure, we shouldn't expect registration to faill unless the shader
/// registry instance provided already has conflicting programs present.
(
[&]() {
using namespace std::string_literals;
using ShaderClass = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>;
auto group = std::make_shared<ShaderGroup<ShaderID>>(programParameters);
if (!registry.registerShaderGroup(std::move(group), ShaderClass::name)) {
assert(!"duplicate shader group");
throw std::runtime_error("Failed to register "s + ShaderClass::name + " with shader registry!");
}
}(),
...);
}
void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramParameters& programParameters) {
registerTypes<shaders::BuiltIn::BackgroundShader,
shaders::BuiltIn::BackgroundPatternShader,
shaders::BuiltIn::CircleShader,
shaders::BuiltIn::LineShader,
shaders::BuiltIn::LineGradientShader,
shaders::BuiltIn::RasterShader,
shaders::BuiltIn::FillShader,
shaders::BuiltIn::FillOutlineShader,
shaders::BuiltIn::FillOutlinePatternShader,
shaders::BuiltIn::FillPatternShader/*,
shaders::BuiltIn::LineSDFShader,
shaders::BuiltIn::LinePatternShader,
shaders::BuiltIn::LineGradientShader,
shaders::BuiltIn::FillExtrusionShader,
shaders::BuiltIn::FillExtrusionPatternShader,
shaders::BuiltIn::HeatmapShader,
shaders::BuiltIn::HeatmapTextureShader,
shaders::BuiltIn::HillshadePrepareShader,
shaders::BuiltIn::HillshadeShader,
shaders::BuiltIn::SymbolIconShader,
shaders::BuiltIn::SymbolSDFTextShader,
shaders::BuiltIn::SymbolSDFIconShader,
shaders::BuiltIn::SymbolTextAndIconShader*/>(shaders, programParameters);
}
} // namespace mtl
} // namespace mbgl

201
src/mbgl/mtl/texture2d.cpp Normal file
View File

@@ -0,0 +1,201 @@
#include <mbgl/mtl/texture2d.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/render_pass.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <Metal/MTLDevice.hpp>
#include <Metal/MTLRenderCommandEncoder.hpp>
#include <Metal/MTLSampler.hpp>
#include <Metal/MTLTexture.hpp>
namespace mbgl {
namespace mtl {
Texture2D::Texture2D(Context& context_)
: context(context_) {}
Texture2D::~Texture2D() {}
gfx::Texture2D& Texture2D::setSamplerConfiguration(const SamplerState& samplerState_) noexcept {
samplerState = samplerState_;
samplerStateDirty = true;
return *this;
}
gfx::Texture2D& Texture2D::setFormat(gfx::TexturePixelType pixelFormat_,
gfx::TextureChannelDataType channelType_) noexcept {
if (pixelFormat_ == pixelFormat && channelType_ == channelType) {
return *this;
}
pixelFormat = pixelFormat_;
channelType = channelType_;
textureDirty = true;
return *this;
}
gfx::Texture2D& Texture2D::setSize(mbgl::Size size_) noexcept {
if (size_ == size) {
return *this;
}
size = size_;
textureDirty = true;
return *this;
}
gfx::Texture2D& Texture2D::setImage(std::shared_ptr<PremultipliedImage> image_) noexcept {
image = std::move(image_);
return *this;
}
size_t Texture2D::getDataSize() const noexcept {
return size.width * size.height * getPixelStride();
}
size_t Texture2D::getPixelStride() const noexcept {
switch (channelType) {
case gfx::TextureChannelDataType::UnsignedByte:
return 1 * numChannels();
case gfx::TextureChannelDataType::HalfFloat:
return 2 * numChannels();
}
}
size_t Texture2D::numChannels() const noexcept {
switch (pixelFormat) {
case gfx::TexturePixelType::RGBA:
return 4;
case gfx::TexturePixelType::Alpha:
return 1;
default:
return 0;
}
}
MTL::PixelFormat Texture2D::getMetalPixelFormat() const noexcept {
switch (channelType) {
case gfx::TextureChannelDataType::UnsignedByte:
switch (pixelFormat) {
case gfx::TexturePixelType::RGBA:
return MTL::PixelFormat::PixelFormatRGBA8Unorm;
case gfx::TexturePixelType::Alpha:
return MTL::PixelFormat::PixelFormatA8Unorm;
default:
assert(false);
return MTL::PixelFormat::PixelFormatInvalid;
}
case gfx::TextureChannelDataType::HalfFloat:
switch (pixelFormat) {
case gfx::TexturePixelType::RGBA:
return MTL::PixelFormat::PixelFormatRGBA16Float;
case gfx::TexturePixelType::Alpha:
return MTL::PixelFormat::PixelFormatR16Float;
default:
assert(false);
return MTL::PixelFormat::PixelFormatInvalid;
}
default:
assert(false);
return MTL::PixelFormat::PixelFormatInvalid;
}
}
void Texture2D::createMetalTexture() noexcept {
if (size == Size{0, 0}) {
return;
}
metalTexture.reset();
const auto format = getMetalPixelFormat();
if (format == MTL::PixelFormat::PixelFormatInvalid) {
return;
}
// Create a new texture object
if (auto textureDescriptor = NS::RetainPtr(
MTL::TextureDescriptor::texture2DDescriptor(format, size.width, size.height, /*mipmapped=*/false))) {
metalTexture = context.createMetalTexture(std::move(textureDescriptor));
}
if (metalTexture) {
textureDirty = false;
context.renderingStats().memTextures += getDataSize();
}
}
void Texture2D::create() noexcept {
if (textureDirty) {
createMetalTexture();
}
if (samplerStateDirty) {
updateSamplerConfiguration();
}
}
void Texture2D::updateSamplerConfiguration() noexcept {
auto samplerDescriptor = NS::RetainPtr(MTL::SamplerDescriptor::alloc()->init());
samplerDescriptor->setMinFilter(samplerState.filter == gfx::TextureFilterType::Nearest
? MTL::SamplerMinMagFilterNearest
: MTL::SamplerMinMagFilterLinear);
samplerDescriptor->setMagFilter(samplerState.filter == gfx::TextureFilterType::Nearest
? MTL::SamplerMinMagFilterNearest
: MTL::SamplerMinMagFilterLinear);
samplerDescriptor->setSAddressMode(samplerState.wrapU == gfx::TextureWrapType::Clamp
? MTL::SamplerAddressModeClampToEdge
: MTL::SamplerAddressModeRepeat);
samplerDescriptor->setTAddressMode(samplerState.wrapV == gfx::TextureWrapType::Clamp
? MTL::SamplerAddressModeClampToEdge
: MTL::SamplerAddressModeRepeat);
metalSamplerState = context.createMetalSamplerState(samplerDescriptor);
}
void Texture2D::bind(const RenderPass& renderPass, int32_t location) noexcept {
assert(!textureDirty);
const auto& encoder = renderPass.getMetalEncoder();
// Update the sampler state if it was changed after resource creation
if (samplerStateDirty) {
updateSamplerConfiguration();
}
encoder->setFragmentTexture(metalTexture.get(), location);
encoder->setFragmentSamplerState(metalSamplerState.get(), location);
}
void Texture2D::unbind(const RenderPass& renderPass, int32_t location) noexcept {
const auto& encoder = renderPass.getMetalEncoder();
encoder->setFragmentTexture(nullptr, location);
encoder->setFragmentSamplerState(nullptr, location);
}
void Texture2D::upload(const void* pixelData, const Size& size_) noexcept {
setSize(size_);
if (textureDirty) {
createMetalTexture();
}
if (samplerStateDirty) {
updateSamplerConfiguration();
}
if (pixelData) {
uploadSubRegion(pixelData, size, 0, 0);
}
}
void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16_t xOffset, uint16_t yOffset) noexcept {
assert(metalTexture.get());
assert(!textureDirty);
MTL::Region region = MTL::Region::Make2D(xOffset, yOffset, size_.width, size_.height);
NS::UInteger bytesPerRow = size_.width * getPixelStride();
metalTexture->replaceRegion(region, 0, pixelData, bytesPerRow);
}
void Texture2D::upload() noexcept {
if (image && image->valid()) {
setFormat(gfx::TexturePixelType::RGBA, gfx::TextureChannelDataType::UnsignedByte);
upload(image->data.get(), image->size);
image.reset();
}
}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,113 @@
#include <mbgl/mtl/tile_layer_group.hpp>
#include <mbgl/gfx/drawable_tweaker.hpp>
#include <mbgl/gfx/render_pass.hpp>
#include <mbgl/gfx/renderable.hpp>
#include <mbgl/gfx/renderer_backend.hpp>
#include <mbgl/gfx/upload_pass.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/drawable.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
namespace mtl {
TileLayerGroup::TileLayerGroup(int32_t layerIndex_, std::size_t initialCapacity, std::string name_)
: mbgl::TileLayerGroup(layerIndex_, initialCapacity, std::move(name_)) {}
void TileLayerGroup::upload(gfx::UploadPass& uploadPass) {
if (!enabled || !getDrawableCount()) {
return;
}
#if !defined(NDEBUG)
const auto debugGroup = uploadPass.createDebugGroup(getName() + "-upload");
#endif
visitDrawables([&](gfx::Drawable& drawable) {
if (drawable.getEnabled()) {
auto& drawableMTL = static_cast<Drawable&>(drawable);
drawableMTL.upload(uploadPass);
}
});
}
void TileLayerGroup::render(RenderOrchestrator&, PaintParameters& parameters) {
if (!enabled || !getDrawableCount()) {
return;
}
auto& context = static_cast<Context&>(parameters.context);
// `stencilModeFor3D` uses a different stencil mask value each time its called, so if the
// drawables in this layer use 3D stencil mode, we need to set it up here so that all the
// drawables end up using the same mode value.
// 2D and 3D features in the same layer group is not supported.
bool features3d = false;
bool stencil3d = false;
gfx::StencilMode stencilMode3d;
// Collect the tile IDs relevant to stenciling and update the stencil buffer, if necessary.
std::set<UnwrappedTileID> tileIDs;
std::size_t numEnabled = 0;
visitDrawables([&](const gfx::Drawable& drawable) {
if (!drawable.getEnabled() || !drawable.hasRenderPass(parameters.pass)) {
return;
}
numEnabled += 1;
if (drawable.getIs3D()) {
features3d = true;
if (drawable.getEnableStencil()) {
stencil3d = true;
}
}
if (!features3d && drawable.getEnableStencil() && drawable.getTileID()) {
tileIDs.emplace(drawable.getTileID()->toUnwrapped());
}
});
if (!numEnabled) {
return;
}
#if !defined(NDEBUG)
const auto debugGroupRender = parameters.encoder->createDebugGroup(getName() + "-render");
#endif
// If we're doing 3D stenciling and have any features
// to draw, set up the single-value stencil mask.
// If we're doing 2D stenciling and have any drawables with tile IDs,
// render each tile into the stencil buffer with a different value.
if (features3d) {
stencilMode3d = stencil3d ? parameters.stencilModeFor3D() : gfx::StencilMode::disabled();
} else if (!tileIDs.empty()) {
#if !defined(NDEBUG)
const auto debugGroup = parameters.encoder->createDebugGroup("tile-clip-masks");
#endif
parameters.renderTileClippingMasks(tileIDs);
}
visitDrawables([&](gfx::Drawable& drawable) {
if (!drawable.getEnabled() || !drawable.hasRenderPass(parameters.pass)) {
return;
}
for (const auto& tweaker : drawable.getTweakers()) {
tweaker->execute(drawable, parameters);
}
// For layer groups with 3D features, enable either the single-value
// stencil mode for features with stencil enabled or disable stenciling.
// 2D drawables will set their own stencil mode within `draw`.
// if (features3d) {
// context.setStencilMode(drawable.getEnableStencil() ? stencilMode3d : gfx::StencilMode::disabled());
//}
drawable.draw(parameters);
});
}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,17 @@
#include <mbgl/mtl/uniform_block.hpp>
#include <mbgl/mtl/uniform_buffer.hpp>
#include <cassert>
namespace mbgl {
namespace mtl {
void UniformBlock::bindBuffer(const gfx::UniformBuffer& uniformBuffer) {
assert(size == uniformBuffer.getSize());
}
void UniformBlock::unbindBuffer() {}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,30 @@
#include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/util/logging.hpp>
#include <cassert>
namespace mbgl {
namespace mtl {
UniformBuffer::UniformBuffer(BufferResource&& buffer_)
: gfx::UniformBuffer(buffer_.getSizeInBytes()),
buffer(std::move(buffer_)) {}
UniformBuffer::UniformBuffer(UniformBuffer&& other)
: gfx::UniformBuffer(std::move(other)),
buffer(std::move(other.buffer)) {}
void UniformBuffer::update(const void* data, std::size_t size_) {
assert(size == size_);
if (size != size_ || size != buffer.getSizeInBytes()) {
Log::Error(
Event::General,
"Mismatched size given to UBO update, expected " + std::to_string(size) + ", got " + std::to_string(size_));
return;
}
buffer.update(data, size, /*offset=*/0);
}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,268 @@
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/command_encoder.hpp>
#include <mbgl/mtl/index_buffer_resource.hpp>
#include <mbgl/mtl/renderable_resource.hpp>
#include <mbgl/mtl/vertex_attribute.hpp>
#include <mbgl/mtl/vertex_buffer_resource.hpp>
#include <mbgl/util/logging.hpp>
#include <Metal/Metal.hpp>
#include <algorithm>
namespace mbgl {
namespace mtl {
UploadPass::UploadPass(gfx::Renderable& renderable, CommandEncoder& commandEncoder_, const char* name)
: commandEncoder(commandEncoder_) {
auto& resource = renderable.getResource<RenderableResource>();
if (!resource.getCommandBuffer()) {
resource.bind();
}
if (const auto& buffer_ = resource.getCommandBuffer()) {
buffer = buffer_;
if (auto upd = resource.getUploadPassDescriptor()) {
encoder = NS::RetainPtr(buffer->blitCommandEncoder(upd.get()));
}
}
assert(encoder);
// Push the groups already accumulated by the encoder
commandEncoder.visitDebugGroups([this](const auto& group) {
debugGroups.emplace_back(gfx::DebugGroup<gfx::UploadPass>{*this, group.c_str()});
});
// Push the group for the name provided
debugGroups.emplace_back(gfx::DebugGroup<gfx::UploadPass>{*this, name});
// Let the encoder pass along any groups pushed to it after this
commandEncoder.trackUploadPass(this);
}
UploadPass::~UploadPass() {
commandEncoder.forgetUploadPass(this);
endEncoding();
}
void UploadPass::endEncoding() {
debugGroups.clear();
if (encoder) {
encoder->endEncoding();
encoder.reset();
}
}
std::unique_ptr<gfx::VertexBufferResource> UploadPass::createVertexBufferResource(const void* data,
const std::size_t size,
const gfx::BufferUsageType usage) {
return std::make_unique<VertexBufferResource>(commandEncoder.context.createBuffer(data, size, usage));
}
void UploadPass::updateVertexBufferResource(gfx::VertexBufferResource& resource, const void* data, std::size_t size) {
static_cast<VertexBufferResource&>(resource).get().update(data, size, /*offset=*/0);
}
std::unique_ptr<gfx::IndexBufferResource> UploadPass::createIndexBufferResource(const void* data,
const std::size_t size,
const gfx::BufferUsageType usage) {
return std::make_unique<IndexBufferResource>(commandEncoder.context.createBuffer(data, size, usage));
}
void UploadPass::updateIndexBufferResource(gfx::IndexBufferResource& resource, const void* data, std::size_t size) {
static_cast<IndexBufferResource&>(resource).get().update(data, size, /*offset=*/0);
}
std::unique_ptr<gfx::TextureResource> UploadPass::createTextureResource(const Size size,
const void* data,
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
assert(false);
throw std::runtime_error("UploadPass::createTextureResource not implemented on Metal!");
}
void UploadPass::updateTextureResource(gfx::TextureResource& resource,
const Size size,
const void* data,
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
assert(false);
throw std::runtime_error("UploadPass::updateTextureResource not implemented on Metal!");
}
void UploadPass::updateTextureResourceSub(gfx::TextureResource& resource,
const uint16_t xOffset,
const uint16_t yOffset,
const Size size,
const void* data,
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
assert(false);
throw std::runtime_error("UploadPass::updateTextureResourceSub not implemented on Metal!");
}
struct VertexBuffer : public gfx::VertexBufferBase {
~VertexBuffer() override = default;
std::unique_ptr<gfx::VertexBufferResource> resource;
};
namespace {
const std::unique_ptr<gfx::VertexBufferResource> noBuffer;
}
const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVectorBasePtr& vec,
const gfx::BufferUsageType usage) {
if (vec) {
const auto* rawBufPtr = vec->getRawData();
const auto rawBufSize = vec->getRawCount() * vec->getRawSize();
// If we already have a buffer...
if (auto* rawData = static_cast<VertexBuffer*>(vec->getBuffer()); rawData && rawData->resource) {
auto& resource = static_cast<VertexBufferResource&>(*rawData->resource);
// If it's changed, update it
if (rawBufSize <= resource.getSizeInBytes()) {
if (vec->getDirty()) {
updateVertexBufferResource(resource, rawBufPtr, rawBufSize);
vec->setDirty(false);
}
return rawData->resource;
}
}
// Otherwise, create a new one
if (rawBufSize > 0) {
auto buffer = std::make_unique<VertexBuffer>();
buffer->resource = createVertexBufferResource(rawBufPtr, rawBufSize, usage);
vec->setBuffer(std::move(buffer));
vec->setDirty(false);
return static_cast<VertexBuffer*>(vec->getBuffer())->resource;
}
}
return noBuffer;
}
gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
const std::size_t vertexCount,
const gfx::AttributeDataType vertexType,
const std::size_t vertexAttributeIndex,
const std::vector<std::uint8_t>& vertexData,
const gfx::VertexAttributeArray& defaults,
const gfx::VertexAttributeArray& overrides,
const gfx::BufferUsageType usage,
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>& outBuffers) {
gfx::AttributeBindingArray bindings;
bindings.resize(defaults.size());
constexpr std::size_t align = 16;
constexpr std::uint8_t padding = 0;
std::vector<std::uint8_t> allData;
allData.reserve((defaults.getTotalSize() + align) * vertexCount);
uint32_t vertexStride = 0;
// For each attribute in the program, with the corresponding default and optional override...
const auto resolveAttr = [&](const std::string& name, auto& default_, auto& override_) -> void {
auto& effectiveAttr = override_ ? *override_ : default_;
const auto& defaultAttr = static_cast<const VertexAttribute&>(default_);
const auto stride = defaultAttr.getStride();
const auto offset = static_cast<uint32_t>(allData.size());
const auto index = static_cast<std::size_t>(defaultAttr.getIndex());
bindings.resize(std::max(bindings.size(), index + 1));
if (!override_) {
bindings[index] = {
/*.attribute = */ {defaultAttr.getDataType(), /*offset=*/0},
/*.vertexStride = */ static_cast<uint32_t>(VertexAttribute::getStrideOf(defaultAttr.getDataType())),
/*.vertexBufferResource = */ nullptr,
/*.vertexOffset = */ 0,
};
return;
}
// If the attribute references data shared with a bucket, get the corresponding buffer.
if (const auto& buffer = getBuffer(effectiveAttr.getSharedRawData(), usage)) {
bindings[index] = {
/*.attribute = */ {effectiveAttr.getSharedType(), effectiveAttr.getSharedOffset()},
/*.vertexStride = */ effectiveAttr.getSharedStride(),
/*.vertexBufferResource = */ buffer.get(),
/*.vertexOffset = */ effectiveAttr.getSharedVertexOffset(),
};
return;
}
assert(effectiveAttr.getStride() > 0);
// Otherwise, turn the data managed by the attribute into a buffer.
if (const auto& buffer = VertexAttribute::getBuffer(effectiveAttr, *this, gfx::BufferUsageType::StaticDraw)) {
bindings[index] = {
/*.attribute = */ {effectiveAttr.getDataType(), /*offset=*/0},
/*.vertexStride = */ static_cast<uint32_t>(effectiveAttr.getStride()),
/*.vertexBufferResource = */ buffer.get(),
/*.vertexOffset = */ 0,
};
return;
}
assert(false);
};
defaults.resolve(overrides, resolveAttr);
assert(vertexStride * vertexCount <= allData.size());
if (!allData.empty()) {
if (auto vertBuf = createVertexBufferResource(allData.data(), allData.size(), usage)) {
// Fill in the buffer in each binding that was generated without its own buffer
std::for_each(bindings.begin(), bindings.end(), [&](auto& b) {
if (b && !b->vertexBufferResource) {
b->vertexBufferResource = vertBuf.get();
}
});
outBuffers.emplace_back(std::move(vertBuf));
} else {
assert(false);
return {};
}
}
return bindings;
}
namespace {
constexpr auto missing = "<none>";
NS::String* toNSString(const char* str) {
return NS::String::string(str ? str : missing, NS::UTF8StringEncoding);
}
} // namespace
void UploadPass::pushDebugGroup(const char* name) {
assert(encoder);
if (encoder) {
encoder->pushDebugGroup(toNSString(name));
}
}
void UploadPass::popDebugGroup() {
assert(encoder);
if (encoder) {
encoder->popDebugGroup();
}
}
gfx::Context& UploadPass::getContext() {
return commandEncoder.context;
}
const gfx::Context& UploadPass::getContext() const {
return commandEncoder.context;
}
} // namespace mtl
} // namespace mbgl

View File

@@ -0,0 +1,100 @@
#include <mbgl/mtl/vertex_attribute.hpp>
#include <mbgl/gfx/vertex_vector.hpp>
#include <mbgl/mtl/buffer_resource.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/util/logging.hpp>
#include <cstring>
#include <sstream>
namespace mbgl {
namespace mtl {
std::size_t VertexAttribute::getStrideOf(gfx::AttributeDataType type) {
switch (type) {
case gfx::AttributeDataType::Byte:
return 1;
case gfx::AttributeDataType::Byte2:
return 2;
case gfx::AttributeDataType::Byte3:
return 3;
case gfx::AttributeDataType::Byte4:
return 4;
case gfx::AttributeDataType::UByte:
return 1;
case gfx::AttributeDataType::UByte2:
return 2;
case gfx::AttributeDataType::UByte3:
return 3;
case gfx::AttributeDataType::UByte4:
return 4;
case gfx::AttributeDataType::Short:
return 2;
case gfx::AttributeDataType::Short2:
return 4;
case gfx::AttributeDataType::Short3:
return 6;
case gfx::AttributeDataType::Short4:
return 8;
case gfx::AttributeDataType::UShort:
return 2;
case gfx::AttributeDataType::UShort2:
return 4;
case gfx::AttributeDataType::UShort3:
return 6;
case gfx::AttributeDataType::UShort4:
return 8;
case gfx::AttributeDataType::UShort8:
return 16;
case gfx::AttributeDataType::Int:
return 4;
case gfx::AttributeDataType::Int2:
return 8;
case gfx::AttributeDataType::Int3:
return 12;
case gfx::AttributeDataType::Int4:
return 16;
case gfx::AttributeDataType::UInt:
return 4;
case gfx::AttributeDataType::UInt2:
return 8;
case gfx::AttributeDataType::UInt3:
return 12;
case gfx::AttributeDataType::UInt4:
return 16;
case gfx::AttributeDataType::Float:
return 4;
case gfx::AttributeDataType::Float2:
return 8;
case gfx::AttributeDataType::Float3:
return 12;
case gfx::AttributeDataType::Float4:
return 16;
default:
assert(false);
return 0;
}
}
const gfx::UniqueVertexBufferResource& VertexAttribute::getBuffer(gfx::VertexAttribute& attrib_,
UploadPass& uploadPass,
const gfx::BufferUsageType usage) {
if (!attrib_.getBuffer()) {
auto& attrib = static_cast<VertexAttribute&>(attrib_);
if (attrib.sharedRawData) {
return uploadPass.getBuffer(attrib.sharedRawData, usage);
} else if (!attrib.rawData.empty()) {
auto buffer = uploadPass.createVertexBufferResource(attrib.rawData.data(), attrib.rawData.size(), usage);
attrib.setBuffer(std::move(buffer));
attrib.setRawData({});
} else {
// TODO: vertex building
assert(false);
}
}
return attrib_.getBuffer();
}
} // namespace mtl
} // namespace mbgl

View File

@@ -14,7 +14,7 @@
#include <unordered_map>
#include <mbgl/shaders/shader_manifest.hpp>
#ifdef MBGL_RENDER_BACKEND_OPENGL
#if !MLN_RENDER_BACKEND_METAL
#include <mbgl/gl/program.hpp>
#endif
@@ -54,7 +54,11 @@ public:
Program(const ProgramParameters& programParameters) {
switch (gfx::Backend::GetType()) {
#ifdef MBGL_RENDER_BACKEND_OPENGL
#if MLN_RENDER_BACKEND_METAL
case gfx::Backend::Type::Metal: {
break;
}
#else // MLN_RENDER_BACKEND_OPENGL
case gfx::Backend::Type::OpenGL: {
program = std::make_unique<gl::Program<Name>>(programParameters.withDefaultSource(
{gfx::Backend::Type::OpenGL,

View File

@@ -1,22 +1,19 @@
#include <mbgl/programs/program_parameters.hpp>
#include <mbgl/util/string.hpp>
#include <string_view>
#include <stdexcept>
namespace mbgl {
ProgramParameters::ProgramParameters(const float pixelRatio, const bool overdraw)
: defines([&] {
std::string result;
result.reserve(32);
result += "#define DEVICE_PIXEL_RATIO ";
result += util::toString(pixelRatio, true);
result += '\n';
if (overdraw) {
result += "#define OVERDRAW_INSPECTOR\n";
}
return result;
}()) {}
: defines(2) {
defines["DEVICE_PIXEL_RATIO"] = util::toString(pixelRatio, true);
if (overdraw) {
defines["OVERDRAW_INSPECTOR"] = std::string();
}
}
ProgramParameters ProgramParameters::withShaderSource(const ProgramSource& source) const noexcept {
assert(gfx::Backend::Type::TYPE_MAX != source.backend);
@@ -34,8 +31,19 @@ ProgramParameters ProgramParameters::withDefaultSource(const ProgramSource& sour
return params;
}
const std::string& ProgramParameters::getDefines() const {
return defines;
const std::string& ProgramParameters::getDefinesString() const {
if (definesStr.empty() && !defines.empty()) {
definesStr.assign(defines.size() * 32, '\0');
definesStr.clear();
for (const auto& pair : defines) {
definesStr.append("#define ").append(pair.first);
if (!pair.second.empty()) {
definesStr.append(" ").append(pair.second);
}
definesStr.append("\n");
}
}
return definesStr;
}
const std::string& ProgramParameters::vertexSource(gfx::Backend::Type backend) const {

View File

@@ -5,6 +5,7 @@
#include <array>
#include <cassert>
#include <string>
#include <unordered_map>
namespace mbgl {
@@ -18,8 +19,7 @@ public:
ProgramSource() = default;
/// @brief Construct a new ProgramSource object
/// @param forBackend The provided source code is intended for use with the give
/// rendering backend.
/// @param forBackend The provided source code is intended for use with the given rendering backend.
/// @param vertex_ The vertex shader source code, or empty string if not provided.
/// @param fragment_ The fragment shader source code, or empty string if not provided.
ProgramSource(gfx::Backend::Type forBackend, const std::string& vertex_, const std::string& fragment_)
@@ -45,7 +45,11 @@ public:
/// @brief Get a list of built-in shader preprocessor defines
/// @return Shader source string
/// @todo With the addition of future backends, defines should also be backend-aware
const std::string& getDefines() const;
const std::string& getDefinesString() const;
/// @brief Get a list of built-in shader preprocessor defines
/// @return Map of key-value pairs representing preprocessor definitions
const std::unordered_map<std::string, std::string>& getDefines() const { return defines; }
/// @brief Get source code for the vertex shader compatible with the requested backend
/// @param backend Backend type
@@ -58,7 +62,10 @@ public:
const std::string& fragmentSource(gfx::Backend::Type backend) const;
private:
std::string defines;
std::unordered_map<std::string, std::string> defines;
// cached value of `defines` converted to string format
mutable std::string definesStr;
std::array<ProgramSource, static_cast<size_t>(gfx::Backend::Type::TYPE_MAX)> defaultSources;
std::array<ProgramSource, static_cast<size_t>(gfx::Backend::Type::TYPE_MAX)> userSources;

View File

@@ -18,7 +18,7 @@
#include <array>
#include <mbgl/shaders/shader_manifest.hpp>
#ifdef MBGL_RENDER_BACKEND_OPENGL
#if !MLN_RENDER_BACKEND_METAL
#include <mbgl/gl/program.hpp>
#endif
@@ -263,7 +263,7 @@ public:
SymbolProgram(const ProgramParameters& programParameters) {
switch (gfx::Backend::GetType()) {
#ifdef MBGL_RENDER_BACKEND_OPENGL
#if !MLN_RENDER_BACKEND_METAL
case gfx::Backend::Type::OpenGL: {
program = std::make_unique<gl::Program<Name>>(programParameters.withDefaultSource(
{gfx::Backend::Type::OpenGL,

View File

@@ -6,10 +6,17 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/util/mat4.hpp>
#if MLN_RENDER_BACKEND_METAL
#include <mbgl/shaders/layer_ubo.hpp>
#include <mbgl/util/monotonic_timer.hpp>
#include <chrono>
#endif // MLN_RENDER_BACKEND_METAL
namespace mbgl {
LayerTweaker::LayerTweaker(Immutable<style::LayerProperties> properties)
: evaluatedProperties(std::move(properties)) {}
LayerTweaker::LayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: id(std::move(id_)),
evaluatedProperties(std::move(properties)) {}
mat4 LayerTweaker::getTileMatrix(const UnwrappedTileID& tileID,
const RenderTree& renderTree,
@@ -33,4 +40,41 @@ mat4 LayerTweaker::getTileMatrix(const UnwrappedTileID& tileID,
return RenderTile::translateVtxMatrix(tileID, tileMatrix, translation, anchor, state, inViewportPixelUnits);
}
#if MLN_RENDER_BACKEND_METAL
shaders::ExpressionInputsUBO LayerTweaker::buildExpressionUBO(double zoom, uint64_t frameCount) {
const auto time = util::MonotonicTimer::now();
const auto time_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(time).count();
return {/* .time_lo = */ static_cast<uint32_t>(time_ns),
/* .time_hi = */ static_cast<uint32_t>(time_ns >> 32),
/* .frame_lo = */ static_cast<uint32_t>(frameCount),
/* .frame_hi = */ static_cast<uint32_t>(frameCount >> 32),
/* .zoom = */ static_cast<float>(zoom),
/* .zoom_frac = */ static_cast<float>(zoom - static_cast<float>(zoom)),
/* .pad = */ 0,
0};
}
void LayerTweaker::setPropertiesAsUniforms(std::vector<std::string> props) {
if (props != propertiesAsUniforms) {
propertiesAsUniforms = std::move(props);
propertiesChanged = true;
}
}
bool LayerTweaker::hasPropertyAsUniform(const std::string_view attrName) const {
// `attrName` is expected to have the "a_" prefix, while the values in `propertiesAsUniforms`
// do not. Search for the former within the latter without allocating temporary strings.
return propertiesAsUniforms.end() !=
std::find_if(propertiesAsUniforms.begin(), propertiesAsUniforms.end(), [&](const auto& name) {
return name.size() + 2 == attrName.size() && 0 == std::strcmp(name.data(), attrName.data() + 2);
});
}
#endif // MLN_RENDER_BACKEND_METAL
void LayerTweaker::enableOverdrawInspector(bool value) {
if (overdrawInspector != value) {
overdrawInspector = value;
propertiesChanged = true;
}
}
} // namespace mbgl

View File

@@ -5,6 +5,7 @@
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/pattern_atlas.hpp>
#include <mbgl/shaders/background_layer_ubo.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/style/layers/background_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
@@ -12,45 +13,9 @@
namespace mbgl {
using namespace style;
using namespace shaders;
struct alignas(16) BackgroundDrawableUBO {
std::array<float, 4 * 4> matrix;
};
static_assert(sizeof(BackgroundDrawableUBO) % 16 == 0);
struct alignas(16) BackgroundLayerUBO {
/* 0 */ Color color;
/* 16 */ float opacity;
/* 20 */ float pad1, pad2, pad3;
/* 32 */
};
static_assert(sizeof(BackgroundLayerUBO) == 32);
struct alignas(16) BackgroundPatternLayerUBO {
/* 0 */ std::array<float, 2> pattern_tl_a;
/* 8 */ std::array<float, 2> pattern_br_a;
/* 16 */ std::array<float, 2> pattern_tl_b;
/* 24 */ std::array<float, 2> pattern_br_b;
/* 32 */ std::array<float, 2> texsize;
/* 40 */ std::array<float, 2> pattern_size_a;
/* 48 */ std::array<float, 2> pattern_size_b;
/* 56 */ std::array<float, 2> pixel_coord_upper;
/* 64 */ std::array<float, 2> pixel_coord_lower;
/* 72 */ float tile_units_to_pixels;
/* 76 */ float scale_a;
/* 80 */ float scale_b;
/* 84 */ float mix;
/* 88 */ float opacity;
/* 92 */ float pad;
/* 96 */
};
static_assert(sizeof(BackgroundPatternLayerUBO) == 96);
#if !defined(NDEBUG)
static constexpr auto BackgroundPatternShaderName = "BackgroundPatternShader";
#endif
static constexpr auto BackgroundDrawableUBOName = "BackgroundDrawableUBO";
static constexpr auto BackgroundLayerUBOName = "BackgroundLayerUBO";
static constexpr auto texUniformName = "u_image";
void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTree&, const PaintParameters& parameters) {
@@ -96,7 +61,7 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre
const BackgroundDrawableUBO drawableUBO = {/* .matrix = */ util::cast<float>(matrix)};
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.createOrUpdate(BackgroundDrawableUBOName, &drawableUBO, context);
uniforms.createOrUpdate("BackgroundDrawableUBO", &drawableUBO, context);
if (hasPattern) {
if (!samplerLocation.has_value()) {
@@ -138,7 +103,7 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre
/* .opacity = */ evaluated.get<BackgroundOpacity>(),
/* .pad = */ 0,
};
uniforms.createOrUpdate(BackgroundLayerUBOName, &layerUBO, context);
uniforms.createOrUpdate("BackgroundLayerUBO", &layerUBO, context);
} else {
// UBOs can be shared
if (!backgroundLayerBuffer) {
@@ -149,7 +114,7 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre
0};
backgroundLayerBuffer = context.createUniformBuffer(&layerUBO, sizeof(layerUBO));
}
uniforms.addOrReplace(BackgroundLayerUBOName, backgroundLayerBuffer);
uniforms.addOrReplace("BackgroundLayerUBO", backgroundLayerBuffer);
}
});
}

View File

@@ -19,8 +19,8 @@ using UniformBufferPtr = std::shared_ptr<UniformBuffer>;
*/
class BackgroundLayerTweaker : public LayerTweaker {
public:
BackgroundLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
BackgroundLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~BackgroundLayerTweaker() override = default;

View File

@@ -5,44 +5,22 @@
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/shaders/circle_layer_ubo.hpp>
#include <mbgl/shaders/shader_source.hpp>
#include <mbgl/style/layers/circle_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
#if MLN_RENDER_BACKEND_METAL
#include <mbgl/shaders/mtl/circle.hpp>
#endif
#include <cstring>
namespace mbgl {
using namespace style;
struct alignas(16) CircleDrawableUBO {
std::array<float, 4 * 4> matrix;
std::array<float, 2> extrude_scale;
std::array<float, 2> padding;
};
static_assert(sizeof(CircleDrawableUBO) % 16 == 0);
struct alignas(16) CirclePaintParamsUBO {
float camera_to_center_distance;
float device_pixel_ratio;
std::array<float, 2> padding;
};
static_assert(sizeof(CirclePaintParamsUBO) % 16 == 0);
struct alignas(16) CircleEvaluatedPropsUBO {
Color color;
Color stroke_color;
float radius;
float blur;
float opacity;
float stroke_width;
float stroke_opacity;
int scale_with_map;
int pitch_with_map;
float padding;
};
static_assert(sizeof(CircleEvaluatedPropsUBO) % 16 == 0);
static constexpr std::string_view CircleDrawableUBOName = "CircleDrawableUBO";
static constexpr std::string_view CirclePaintParamsUBOName = "CirclePaintParamsUBO";
static constexpr std::string_view CircleEvaluatedPropsUBOName = "CircleEvaluatedPropsUBO";
using namespace shaders;
void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
const RenderTree& renderTree,
@@ -63,7 +41,8 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
const CirclePaintParamsUBO paintParamsUBO = {
/* .camera_to_center_distance = */ parameters.state.getCameraToCenterDistance(),
/* .device_pixel_ratio = */ parameters.pixelRatio,
/* .padding = */ {0}};
/* .padding = */ 0,
0};
if (!paintParamsUniformBuffer) {
paintParamsUniformBuffer = context.createUniformBuffer(&paintParamsUBO, sizeof(paintParamsUBO));
@@ -71,20 +50,56 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
paintParamsUniformBuffer->update(&paintParamsUBO, sizeof(CirclePaintParamsUBO));
}
const bool scaleWithMap = evaluated.get<CirclePitchScale>() == CirclePitchScaleType::Map;
const auto zoom = parameters.state.getZoom();
#if MLN_RENDER_BACKEND_METAL
using ShaderClass = shaders::ShaderSource<BuiltIn::CircleShader, gfx::Backend::Type::Metal>;
if (propertiesChanged) {
const auto source = [this](const std::string_view& attrName) {
return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex;
};
const CirclePermutationUBO permutationUBO = {
/* .color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}},
/* .radius = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}},
/* .blur = */ {/*.source=*/source(ShaderClass::attributes[3].name), /*.expression=*/{}},
/* .opacity = */ {/*.source=*/source(ShaderClass::attributes[4].name), /*.expression=*/{}},
/* .stroke_color = */ {/*.source=*/source(ShaderClass::attributes[5].name), /*.expression=*/{}},
/* .stroke_width = */ {/*.source=*/source(ShaderClass::attributes[6].name), /*.expression=*/{}},
/* .stroke_opacity = */ {/*.source=*/source(ShaderClass::attributes[7].name), /*.expression=*/{}},
/* .overdrawInspector = */ overdrawInspector,
/* .pad = */ 0,
0,
0,
0};
if (permutationUniformBuffer) {
permutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO));
} else {
permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO));
}
propertiesChanged = false;
}
if (!expressionUniformBuffer) {
const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount);
expressionUniformBuffer = context.createUniformBuffer(&expressionUBO, sizeof(expressionUBO));
}
#endif
const bool pitchWithMap = evaluated.get<CirclePitchAlignment>() == AlignmentType::Map;
const bool scaleWithMap = evaluated.get<CirclePitchScale>() == CirclePitchScaleType::Map;
// Updated only with evaluated properties
if (!evaluatedPropsUniformBuffer) {
const CircleEvaluatedPropsUBO evaluatedPropsUBO = {
/* .color = */ evaluated.get<CircleColor>().constantOr(CircleColor::defaultValue()),
/* .stroke_color = */ evaluated.get<CircleStrokeColor>().constantOr(CircleStrokeColor::defaultValue()),
/* .radius = */ evaluated.get<CircleRadius>().constantOr(CircleRadius::defaultValue()),
/* .blur = */ evaluated.get<CircleBlur>().constantOr(CircleBlur::defaultValue()),
/* .opacity = */ evaluated.get<CircleOpacity>().constantOr(CircleOpacity::defaultValue()),
/* .stroke_width = */ evaluated.get<CircleStrokeWidth>().constantOr(CircleStrokeWidth::defaultValue()),
/* .stroke_opacity = */
evaluated.get<CircleStrokeOpacity>().constantOr(CircleStrokeOpacity::defaultValue()),
/* .color = */ constOrDefault<CircleColor>(evaluated),
/* .stroke_color = */ constOrDefault<CircleStrokeColor>(evaluated),
/* .radius = */ constOrDefault<CircleRadius>(evaluated),
/* .blur = */ constOrDefault<CircleBlur>(evaluated),
/* .opacity = */ constOrDefault<CircleOpacity>(evaluated),
/* .stroke_width = */ constOrDefault<CircleStrokeWidth>(evaluated),
/* .stroke_opacity = */ constOrDefault<CircleStrokeOpacity>(evaluated),
/* .scale_with_map = */ scaleWithMap,
/* .pitch_with_map = */ pitchWithMap,
/* .padding = */ 0};
@@ -93,10 +108,11 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
layerGroup.visitDrawables([&](gfx::Drawable& drawable) {
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.addOrReplace(CirclePaintParamsUBOName, paintParamsUniformBuffer);
uniforms.addOrReplace(CircleEvaluatedPropsUBOName, evaluatedPropsUniformBuffer);
uniforms.addOrReplace("CirclePaintParamsUBO", paintParamsUniformBuffer);
uniforms.addOrReplace("CircleEvaluatedPropsUBO", evaluatedPropsUniformBuffer);
if (!drawable.getTileID()) {
assert(!"Circles only render with tiles");
return;
}
const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped();
@@ -108,16 +124,20 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
const auto matrix = getTileMatrix(
tileID, renderTree, parameters.state, translation, anchor, nearClipped, inViewportPixelUnits);
const auto pixelsToTileUnits = tileID.pixelsToTileUnits(1.0f, static_cast<float>(parameters.state.getZoom()));
const auto pixelsToTileUnits = tileID.pixelsToTileUnits(1.0f, static_cast<float>(zoom));
const auto extrudeScale = pitchWithMap ? std::array<float, 2>{pixelsToTileUnits, pixelsToTileUnits}
: parameters.pixelsToGLUnits;
// Updated for each drawable on each frame
const CircleDrawableUBO drawableUBO = {
/* .matrix = */ util::cast<float>(matrix),
/* .extrude_scale = */
pitchWithMap ? std::array<float, 2>{{pixelsToTileUnits, pixelsToTileUnits}} : parameters.pixelsToGLUnits,
/* .padding = */ {0}};
const CircleDrawableUBO drawableUBO = {/* .matrix = */ util::cast<float>(matrix),
/* .extrude_scale = */ extrudeScale,
/* .padding = */ 0};
uniforms.createOrUpdate("CircleDrawableUBO", &drawableUBO, context);
uniforms.createOrUpdate(CircleDrawableUBOName, &drawableUBO, context);
#if MLN_RENDER_BACKEND_METAL
uniforms.addOrReplace("ExpressionInputsUBO", expressionUniformBuffer);
uniforms.addOrReplace("CirclePermutationUBO", permutationUniformBuffer);
#endif // MLN_RENDER_BACKEND_METAL
});
}

View File

@@ -2,6 +2,9 @@
#include <mbgl/renderer/layer_tweaker.hpp>
#include <string>
#include <vector>
namespace mbgl {
/**
@@ -9,10 +12,8 @@ namespace mbgl {
*/
class CircleLayerTweaker : public LayerTweaker {
public:
CircleLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
public:
CircleLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
~CircleLayerTweaker() override = default;
void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override;
@@ -20,6 +21,11 @@ public:
protected:
gfx::UniformBufferPtr paintParamsUniformBuffer;
gfx::UniformBufferPtr evaluatedPropsUniformBuffer;
#if MLN_RENDER_BACKEND_METAL
gfx::UniformBufferPtr permutationUniformBuffer;
gfx::UniformBufferPtr expressionUniformBuffer;
#endif // MLN_RENDER_BACKEND_METAL
};
} // namespace mbgl

View File

@@ -11,8 +11,8 @@ namespace mbgl {
*/
class CollisionLayerTweaker : public LayerTweaker {
public:
CollisionLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
CollisionLayerTweaker(std::string name, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(name), properties) {}
public:
~CollisionLayerTweaker() override = default;

View File

@@ -9,6 +9,7 @@
#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/paint_property_binder.hpp>
#include <mbgl/shaders/layer_ubo.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
@@ -49,16 +50,8 @@ struct alignas(16) FillExtrusionDrawablePropsUBO {
};
static_assert(sizeof(FillExtrusionDrawablePropsUBO) == 5 * 16);
constexpr auto FillExtrusionDrawableUBOName = "FillExtrusionDrawableUBO";
constexpr auto FillExtrusionDrawablePropsUBOName = "FillExtrusionDrawablePropsUBO";
constexpr auto texUniformName = "u_image";
template <typename T, class... Is, class... Ts>
auto constOrDefault(const IndexedTuple<TypeList<Is...>, TypeList<Ts...>>& evaluated) {
return evaluated.template get<T>().constantOr(T::defaultValue());
}
} // namespace
void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup,
@@ -103,7 +96,7 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup,
layerGroup.visitDrawables([&](gfx::Drawable& drawable) {
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.addOrReplace(FillExtrusionDrawablePropsUBOName, propsBuffer);
uniforms.addOrReplace("FillExtrusionDrawablePropsUBO", propsBuffer);
if (!drawable.getTileID()) {
return;
@@ -147,7 +140,7 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup,
/* .height_factor = */ heightFactor,
/* .pad = */ 0};
uniforms.createOrUpdate(FillExtrusionDrawableUBOName, &drawableUBO, context);
uniforms.createOrUpdate("FillExtrusionDrawableUBO", &drawableUBO, context);
});
}

View File

@@ -11,8 +11,8 @@ namespace mbgl {
*/
class FillExtrusionLayerTweaker : public LayerTweaker {
public:
FillExtrusionLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
FillExtrusionLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~FillExtrusionLayerTweaker() override = default;

View File

@@ -8,38 +8,21 @@
#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/paint_property_binder.hpp>
#include <mbgl/shaders/shader_source.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/shaders/fill_layer_ubo.hpp>
#include <mbgl/style/layers/fill_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
#include <mbgl/util/std.hpp>
#if MLN_RENDER_BACKEND_METAL
#include <mbgl/shaders/mtl/fill.hpp>
#endif
namespace mbgl {
using namespace style;
struct alignas(16) FillDrawableUBO {
/* 0 */ std::array<float, 4 * 4> matrix;
/* 64 */ std::array<float, 4> scale;
/* 80 */ std::array<float, 2> world;
/* 88 */ std::array<float, 2> pixel_coord_upper;
/* 96 */ std::array<float, 2> pixel_coord_lower;
/* 104 */ std::array<float, 2> texsize;
/* 112 */
};
static_assert(sizeof(FillDrawableUBO) == 112);
/// Evaluated properties that do not depend on the tile
struct alignas(16) FillDrawablePropsUBO {
/* 0 */ Color color;
/* 16 */ Color outline_color;
/* 32 */ float opacity;
/* 36 */ float pad1, pad2, pad3;
/* 48 */
};
static_assert(sizeof(FillDrawablePropsUBO) == 48);
static constexpr std::string_view FillDrawableUBOName = "FillDrawableUBO";
static constexpr std::string_view FillDrawablePropsUBOName = "FillDrawablePropsUBO";
using namespace shaders;
void FillLayerTweaker::execute(LayerGroupBase& layerGroup,
const RenderTree& renderTree,
@@ -58,24 +41,186 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup,
const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str());
#endif
if (!propsBuffer) {
const FillDrawablePropsUBO paramsUBO = {
/* .color = */ evaluated.get<FillColor>().constantOr(FillColor::defaultValue()),
/* .outline_color = */ evaluated.get<FillOutlineColor>().constantOr(FillOutlineColor::defaultValue()),
/* .opacity = */ evaluated.get<FillOpacity>().constantOr(FillOpacity::defaultValue()),
/* .padding = */ 0,
0,
0};
propsBuffer = context.createUniformBuffer(&paramsUBO, sizeof(paramsUBO));
#if MLN_RENDER_BACKEND_METAL
const auto source = [this](const std::string_view& attrName) {
return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex;
};
#endif
bool fillUniformBufferUpdated = false;
bool fillOutlineUniformBufferUpdated = false;
bool fillPatternUniformBufferUpdated = false;
bool fillOutlinePatternUniformBufferUpdated = false;
auto UpdateFillUniformBuffers = [&]() {
if (fillUniformBufferUpdated) return;
#if MLN_RENDER_BACKEND_METAL
using ShaderClass = ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal>;
if (propertiesChanged || !fillPermutationUniformBuffer) {
const FillPermutationUBO permutationUBO = {
/* .color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}},
/* .opacity = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}},
/* .overdrawInspector = */ overdrawInspector,
0,
0,
0,
0,
0,
0,
};
if (fillPermutationUniformBuffer) {
fillPermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO));
} else {
fillPermutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO));
}
fillUniformBufferUpdated = true;
}
#endif
if (!fillPropsUniformBuffer) {
const FillEvaluatedPropsUBO paramsUBO = {
/* .color = */ evaluated.get<FillColor>().constantOr(FillColor::defaultValue()),
/* .opacity = */ evaluated.get<FillOpacity>().constantOr(FillOpacity::defaultValue()),
0,
0,
0,
};
fillPropsUniformBuffer = context.createUniformBuffer(&paramsUBO, sizeof(paramsUBO));
}
};
auto UpdateFillOutlineUniformBuffers = [&]() {
if (fillOutlineUniformBufferUpdated) return;
#if MLN_RENDER_BACKEND_METAL
using ShaderClass = ShaderSource<BuiltIn::FillOutlineShader, gfx::Backend::Type::Metal>;
if (propertiesChanged || !fillOutlinePermutationUniformBuffer) {
const FillOutlinePermutationUBO permutationUBO = {
/* .outline_color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}},
/* .opacity = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}},
/* .overdrawInspector = */ overdrawInspector,
0,
0,
0,
0,
0,
0,
};
if (fillOutlinePermutationUniformBuffer) {
fillOutlinePermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO));
} else {
fillOutlinePermutationUniformBuffer = context.createUniformBuffer(&permutationUBO,
sizeof(permutationUBO));
}
}
#endif
if (!fillOutlinePropsUniformBuffer) {
const FillOutlineEvaluatedPropsUBO paramsUBO = {
/* .outline_color = */ evaluated.get<FillOutlineColor>().constantOr(FillOutlineColor::defaultValue()),
/* .opacity = */ evaluated.get<FillOpacity>().constantOr(FillOpacity::defaultValue()),
0,
0,
0,
};
fillOutlinePropsUniformBuffer = context.createUniformBuffer(&paramsUBO, sizeof(paramsUBO));
}
fillOutlineUniformBufferUpdated = true;
};
auto UpdateFillPatternUniformBuffers = [&]() {
if (fillPatternUniformBufferUpdated) return;
#if MLN_RENDER_BACKEND_METAL
using ShaderClass = ShaderSource<BuiltIn::FillOutlinePatternShader, gfx::Backend::Type::Metal>;
if (propertiesChanged || !fillPatternPermutationUniformBuffer) {
const FillPatternPermutationUBO permutationUBO = {
/* .pattern_from = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}},
/* .pattern_to = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}},
/* .opacity = */ {/*.source=*/source(ShaderClass::attributes[3].name), /*.expression=*/{}},
/* .overdrawInspector = */ overdrawInspector,
0,
0,
0,
0,
};
if (fillPatternPermutationUniformBuffer) {
fillPatternPermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO));
} else {
fillPatternPermutationUniformBuffer = context.createUniformBuffer(&permutationUBO,
sizeof(permutationUBO));
}
}
#endif
if (!fillPatternPropsUniformBuffer) {
const FillPatternEvaluatedPropsUBO paramsUBO = {
/* .opacity = */ evaluated.get<FillOpacity>().constantOr(FillOpacity::defaultValue()),
/* .fade = */ crossfade.t,
0,
0,
};
fillPatternPropsUniformBuffer = context.createUniformBuffer(&paramsUBO, sizeof(paramsUBO));
}
fillPatternUniformBufferUpdated = true;
};
auto UpdateFillOutlinePatternUniformBuffers = [&]() {
if (fillOutlinePatternUniformBufferUpdated) return;
#if MLN_RENDER_BACKEND_METAL
using ShaderClass = ShaderSource<BuiltIn::FillOutlinePatternShader, gfx::Backend::Type::Metal>;
if (propertiesChanged || !fillOutlinePermutationUniformBuffer) {
const FillOutlinePatternPermutationUBO permutationUBO = {
/* .pattern_from = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}},
/* .pattern_to = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}},
/* .opacity = */ {/*.source=*/source(ShaderClass::attributes[3].name), /*.expression=*/{}},
/* .overdrawInspector = */ overdrawInspector,
0,
0,
0,
0,
};
if (fillOutlinePatternPermutationUniformBuffer) {
fillOutlinePatternPermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO));
} else {
fillOutlinePatternPermutationUniformBuffer = context.createUniformBuffer(&permutationUBO,
sizeof(permutationUBO));
}
}
#endif
if (!fillOutlinePatternPropsUniformBuffer) {
const FillOutlinePatternEvaluatedPropsUBO paramsUBO = {
/* .opacity = */ evaluated.get<FillOpacity>().constantOr(FillOpacity::defaultValue()),
/* .fade = */ crossfade.t,
0,
0,
};
fillOutlinePatternPropsUniformBuffer = context.createUniformBuffer(&paramsUBO, sizeof(paramsUBO));
}
fillOutlinePatternUniformBufferUpdated = true;
};
#if MLN_RENDER_BACKEND_METAL
if (!expressionUniformBuffer) {
const auto zoom = parameters.state.getZoom();
const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount);
expressionUniformBuffer = context.createUniformBuffer(&expressionUBO, sizeof(expressionUBO));
}
#endif
layerGroup.visitDrawables([&](gfx::Drawable& drawable) {
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.addOrReplace(FillDrawablePropsUBOName, propsBuffer);
if (!drawable.getTileID()) {
return;
}
// auto& drawableType = drawable.getShader()->typeName();
const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped();
@@ -106,18 +251,80 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup,
}
}
}
if (!drawable.getTileID()) {
return;
}
const FillDrawableUBO drawableUBO = {
/*.matrix=*/util::cast<float>(matrix),
/*.scale=*/{pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale},
/*.world=*/{(float)renderableSize.width, (float)renderableSize.height},
/*.pixel_coord_upper=*/{static_cast<float>(pixelX >> 16), static_cast<float>(pixelY >> 16)},
/*.pixel_coord_lower=*/{static_cast<float>(pixelX & 0xFFFF), static_cast<float>(pixelY & 0xFFFF)},
/*.texsize=*/{static_cast<float>(textureSize.width), static_cast<float>(textureSize.height)},
};
if (uniforms.get("FillInterpolateUBO")) {
UpdateFillUniformBuffers();
uniforms.createOrUpdate(FillDrawableUBOName, &drawableUBO, context);
uniforms.addOrReplace("FillEvaluatedPropsUBO", fillPropsUniformBuffer);
const FillDrawableUBO drawableUBO = {/*.matrix=*/util::cast<float>(matrix)};
uniforms.createOrUpdate("FillDrawableUBO", &drawableUBO, context);
#if MLN_RENDER_BACKEND_METAL
uniforms.addOrReplace("FillPermutationUBO", fillPermutationUniformBuffer);
#endif // MLN_RENDER_BACKEND_METAL
} else if (uniforms.get("FillOutlineInterpolateUBO")) {
UpdateFillOutlineUniformBuffers();
uniforms.addOrReplace("FillOutlineEvaluatedPropsUBO", fillOutlinePropsUniformBuffer);
const FillOutlineDrawableUBO drawableUBO = {
/*.matrix=*/util::cast<float>(matrix),
/*.world=*/{(float)renderableSize.width, (float)renderableSize.height},
};
uniforms.createOrUpdate("FillOutlineDrawableUBO", &drawableUBO, context);
#if MLN_RENDER_BACKEND_METAL
uniforms.addOrReplace("FillOutlinePermutationUBO", fillOutlinePermutationUniformBuffer);
#endif // MLN_RENDER_BACKEND_METAL
} else if (uniforms.get("FillPatternInterpolateUBO")) {
UpdateFillPatternUniformBuffers();
uniforms.addOrReplace("FillPatternEvaluatedPropsUBO", fillPatternPropsUniformBuffer);
const FillPatternDrawableUBO drawableUBO = {
/*.matrix=*/util::cast<float>(matrix),
/*.scale=*/{pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale},
/*.pixel_coord_upper=*/{static_cast<float>(pixelX >> 16), static_cast<float>(pixelY >> 16)},
/*.pixel_coord_lower=*/{static_cast<float>(pixelX & 0xFFFF), static_cast<float>(pixelY & 0xFFFF)},
/*.texsize=*/{static_cast<float>(textureSize.width), static_cast<float>(textureSize.height)},
0,
0,
};
uniforms.createOrUpdate("FillPatternDrawableUBO", &drawableUBO, context);
#if MLN_RENDER_BACKEND_METAL
uniforms.addOrReplace("FillPatternPermutationUBO", fillPatternPermutationUniformBuffer);
#endif // MLN_RENDER_BACKEND_METAL
} else if (uniforms.get("FillOutlinePatternInterpolateUBO")) {
UpdateFillOutlinePatternUniformBuffers();
uniforms.addOrReplace("FillOutlinePatternEvaluatedPropsUBO", fillOutlinePatternPropsUniformBuffer);
const FillOutlinePatternDrawableUBO drawableUBO = {
/*.matrix=*/util::cast<float>(matrix),
/*.scale=*/{pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale},
/*.world=*/{(float)renderableSize.width, (float)renderableSize.height},
/*.pixel_coord_upper=*/{static_cast<float>(pixelX >> 16), static_cast<float>(pixelY >> 16)},
/*.pixel_coord_lower=*/{static_cast<float>(pixelX & 0xFFFF), static_cast<float>(pixelY & 0xFFFF)},
/*.texsize=*/{static_cast<float>(textureSize.width), static_cast<float>(textureSize.height)},
};
uniforms.createOrUpdate("FillOutlinePatternDrawableUBO", &drawableUBO, context);
#if MLN_RENDER_BACKEND_METAL
uniforms.addOrReplace("FillOutlinePatternPermutationUBO", fillOutlinePatternPermutationUniformBuffer);
#endif // MLN_RENDER_BACKEND_METAL
}
#if MLN_RENDER_BACKEND_METAL
uniforms.addOrReplace("ExpressionInputsUBO", expressionUniformBuffer);
#endif // MLN_RENDER_BACKEND_METAL
});
propertiesChanged = false;
}
} // namespace mbgl

View File

@@ -11,40 +11,27 @@ namespace mbgl {
*/
class FillLayerTweaker : public LayerTweaker {
public:
FillLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
FillLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~FillLayerTweaker() override = default;
void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override;
static constexpr std::string_view FillTilePropsUBOName = "FillDrawableTilePropsUBO";
static constexpr std::string_view FillInterpolateUBOName = "FillInterpolateUBO";
private:
gfx::UniformBufferPtr propsBuffer;
};
gfx::UniformBufferPtr fillPropsUniformBuffer;
gfx::UniformBufferPtr fillOutlinePropsUniformBuffer;
gfx::UniformBufferPtr fillPatternPropsUniformBuffer;
gfx::UniformBufferPtr fillOutlinePatternPropsUniformBuffer;
/// Evaluated properties that depend on the tile
struct alignas(16) FillDrawableTilePropsUBO {
/* 0 */ std::array<float, 4> pattern_from;
/* 16 */ std::array<float, 4> pattern_to;
/* 32 */
gfx::UniformBufferPtr fillPermutationUniformBuffer;
gfx::UniformBufferPtr fillOutlinePermutationUniformBuffer;
gfx::UniformBufferPtr fillPatternPermutationUniformBuffer;
gfx::UniformBufferPtr fillOutlinePatternPermutationUniformBuffer;
#if MLN_RENDER_BACKEND_METAL
gfx::UniformBufferPtr expressionUniformBuffer;
#endif // MLN_RENDER_BACKEND_METAL
};
static_assert(sizeof(FillDrawableTilePropsUBO) == 32);
/// Attribute interpolations
struct alignas(16) FillInterpolateUBO {
/* 0 */ float color_t;
/* 4 */ float opacity_t;
/* 8 */ float outline_color_t;
/* 12 */ float pattern_from_t;
/* 16 */ float pattern_to_t;
/* 20 */ float fade;
/* 24 */ float pad1, pad2;
/* 32 */
};
static_assert(sizeof(FillInterpolateUBO) == 32);
} // namespace mbgl

View File

@@ -9,8 +9,8 @@ namespace mbgl {
*/
class HeatmapLayerTweaker : public LayerTweaker {
public:
HeatmapLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
HeatmapLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~HeatmapLayerTweaker() override = default;

View File

@@ -9,8 +9,8 @@ namespace mbgl {
*/
class HeatmapTextureLayerTweaker : public LayerTweaker {
public:
HeatmapTextureLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
HeatmapTextureLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~HeatmapTextureLayerTweaker() override = default;

View File

@@ -9,8 +9,8 @@ namespace mbgl {
*/
class HillshadeLayerTweaker : public LayerTweaker {
public:
HillshadeLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
HillshadeLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~HillshadeLayerTweaker() override = default;

View File

@@ -9,8 +9,8 @@ namespace mbgl {
*/
class HillshadePrepareLayerTweaker : public LayerTweaker {
public:
HillshadePrepareLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
HillshadePrepareLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~HillshadePrepareLayerTweaker() override = default;

View File

@@ -1,121 +1,28 @@
#include <mbgl/renderer/layers/line_layer_tweaker.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/style/layers/line_layer_properties.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/util/convert.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/gfx/line_drawable_data.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/shaders/line_layer_ubo.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/style/layers/line_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/math.hpp>
#if MLN_RENDER_BACKEND_METAL
#include <mbgl/shaders/mtl/line.hpp>
#endif // MLN_RENDER_BACKEND_METAL
namespace mbgl {
using namespace style;
struct alignas(16) LineUBO {
std::array<float, 4 * 4> matrix;
std::array<float, 2> units_to_pixels;
float ratio;
float device_pixel_ratio;
};
static_assert(sizeof(LineUBO) % 16 == 0);
static constexpr std::string_view LineUBOName = "LineUBO";
struct alignas(16) LinePropertiesUBO {
Color color;
float blur;
float opacity;
float gapwidth;
float offset;
float width;
float pad1;
std::array<float, 2> pad2;
};
static_assert(sizeof(LinePropertiesUBO) % 16 == 0);
static constexpr std::string_view LinePropertiesUBOName = "LinePropertiesUBO";
struct alignas(16) LineGradientUBO {
std::array<float, 4 * 4> matrix;
std::array<float, 2> units_to_pixels;
float ratio;
float device_pixel_ratio;
};
static_assert(sizeof(LineGradientUBO) % 16 == 0);
static constexpr std::string_view LineGradientUBOName = "LineGradientUBO";
struct alignas(16) LineGradientPropertiesUBO {
float blur;
float opacity;
float gapwidth;
float offset;
float width;
float pad1;
std::array<float, 2> pad2;
};
static_assert(sizeof(LineGradientPropertiesUBO) % 16 == 0);
static constexpr std::string_view LineGradientPropertiesUBOName = "LineGradientPropertiesUBO";
struct alignas(16) LinePatternUBO {
std::array<float, 4 * 4> matrix;
std::array<float, 4> scale;
std::array<float, 2> texsize;
std::array<float, 2> units_to_pixels;
float ratio;
float device_pixel_ratio;
float fade;
float pad1;
};
static_assert(sizeof(LinePatternUBO) % 16 == 0);
static constexpr std::string_view LinePatternUBOName = "LinePatternUBO";
struct alignas(16) LinePatternPropertiesUBO {
float blur;
float opacity;
float offset;
float gapwidth;
float width;
float pad1;
std::array<float, 2> pad2;
};
static_assert(sizeof(LinePatternPropertiesUBO) % 16 == 0);
static constexpr std::string_view LinePatternPropertiesUBOName = "LinePatternPropertiesUBO";
struct alignas(16) LineSDFUBO {
std::array<float, 4 * 4> matrix;
std::array<float, 2> units_to_pixels;
std::array<float, 2> patternscale_a;
std::array<float, 2> patternscale_b;
float ratio;
float device_pixel_ratio;
float tex_y_a;
float tex_y_b;
float sdfgamma;
float mix;
};
static_assert(sizeof(LineSDFUBO) % 16 == 0);
static constexpr std::string_view LineSDFUBOName = "LineSDFUBO";
struct alignas(16) LineSDFPropertiesUBO {
Color color;
float blur;
float opacity;
float gapwidth;
float offset;
float width;
float floorwidth;
std::array<float, 2> pad1;
};
static_assert(sizeof(LineSDFPropertiesUBO) % 16 == 0);
static constexpr std::string_view LineSDFPropertiesUBOName = "LineSDFPropertiesUBO";
using namespace shaders;
void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
const RenderTree& renderTree,
@@ -124,6 +31,8 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
const auto& evaluated = static_cast<const LineLayerProperties&>(*evaluatedProperties).evaluated;
const auto& crossfade = static_cast<const LineLayerProperties&>(*evaluatedProperties).crossfade;
const auto zoom = parameters.state.getZoom();
const auto getLinePropsBuffer = [&]() {
if (!linePropertiesBuffer) {
const LinePropertiesUBO linePropertiesUBO{
@@ -134,7 +43,8 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
/*offset =*/evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue()),
/*width =*/evaluated.get<LineWidth>().constantOr(LineWidth::defaultValue()),
0,
{0, 0}};
0,
0};
linePropertiesBuffer = context.createUniformBuffer(&linePropertiesUBO, sizeof(linePropertiesUBO));
}
return linePropertiesBuffer;
@@ -148,7 +58,8 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
/*offset =*/evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue()),
/*width =*/evaluated.get<LineWidth>().constantOr(LineWidth::defaultValue()),
0,
{0, 0}};
0,
0};
lineGradientPropertiesBuffer = context.createUniformBuffer(&lineGradientPropertiesUBO,
sizeof(lineGradientPropertiesUBO));
}
@@ -163,7 +74,8 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
/*gapwidth =*/evaluated.get<LineGapWidth>().constantOr(LineGapWidth::defaultValue()),
/*width =*/evaluated.get<LineWidth>().constantOr(LineWidth::defaultValue()),
0,
{0, 0}};
0,
0};
linePatternPropertiesBuffer = context.createUniformBuffer(&linePatternPropertiesUBO,
sizeof(linePatternPropertiesUBO));
}
@@ -179,12 +91,49 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
/*offset =*/evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue()),
/*width =*/evaluated.get<LineWidth>().constantOr(LineWidth::defaultValue()),
/*floorwidth =*/evaluated.get<LineFloorWidth>().constantOr(LineFloorWidth::defaultValue()),
{0, 0}};
0,
0};
lineSDFPropertiesBuffer = context.createUniformBuffer(&lineSDFPropertiesUBO, sizeof(lineSDFPropertiesUBO));
}
return lineSDFPropertiesBuffer;
};
#if MLN_RENDER_BACKEND_METAL
using LineShaderClass = shaders::ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal>;
if (propertiesChanged) {
const auto source = [this](const std::string_view& attrName) {
return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex;
};
const LinePermutationUBO permutationUBO = {
/* .color = */ {/*.source=*/source(LineShaderClass::attributes[2].name), /*.expression=*/{}},
/* .blur = */ {/*.source=*/source(LineShaderClass::attributes[3].name), /*.expression=*/{}},
/* .opacity = */ {/*.source=*/source(LineShaderClass::attributes[4].name), /*.expression=*/{}},
/* .gapwidth = */ {/*.source=*/source(LineShaderClass::attributes[5].name), /*.expression=*/{}},
/* .offset = */ {/*.source=*/source(LineShaderClass::attributes[6].name), /*.expression=*/{}},
/* .width = */ {/*.source=*/source(LineShaderClass::attributes[7].name), /*.expression=*/{}},
/* .floorwidth = */ {/*.source=*/AttributeSource::Constant, /*.expression=*/{}},
/* .pattern_from = */ {/*.source=*/AttributeSource::Constant, /*.expression=*/{}},
/* .pattern_to = */ {/*.source=*/AttributeSource::Constant, /*.expression=*/{}},
/* .overdrawInspector = */ overdrawInspector,
/* .pad = */ 0,
0,
0,
0};
if (permutationUniformBuffer) {
permutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO));
} else {
permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO));
}
propertiesChanged = false;
}
if (!expressionUniformBuffer) {
const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount);
expressionUniformBuffer = context.createUniformBuffer(&expressionUBO, sizeof(expressionUBO));
}
#endif
layerGroup.visitDrawables([&](gfx::Drawable& drawable) {
const auto shader = drawable.getShader();
if (!drawable.getTileID() || !shader) {
@@ -201,37 +150,31 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
const auto matrix = getTileMatrix(
tileID, renderTree, parameters.state, translation, anchor, nearClipped, inViewportPixelUnits);
LineType type = static_cast<LineType>(drawable.getType());
const LineType type = static_cast<LineType>(drawable.getType());
switch (type) {
case LineType::Simple: {
// main UBO
const LineUBO lineUBO{
/*matrix = */ util::cast<float>(matrix),
/*units_to_pixels = */ {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]},
/*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast<float>(parameters.state.getZoom())),
/*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast<float>(zoom)),
/*device_pixel_ratio = */ parameters.pixelRatio};
uniforms.createOrUpdate(LineUBOName, &lineUBO, context);
// properties UBO
uniforms.addOrReplace(LinePropertiesUBOName, getLinePropsBuffer());
uniforms.createOrUpdate("LineUBO", &lineUBO, context);
uniforms.addOrReplace("LinePropertiesUBO", getLinePropsBuffer());
} break;
case LineType::Gradient: {
// main UBO
const LineGradientUBO lineGradientUBO{
/*matrix = */ util::cast<float>(matrix),
/*units_to_pixels = */ {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]},
/*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast<float>(parameters.state.getZoom())),
/*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast<float>(zoom)),
/*device_pixel_ratio = */ parameters.pixelRatio};
uniforms.createOrUpdate(LineGradientUBOName, &lineGradientUBO, context);
// properties UBO
uniforms.addOrReplace(LineGradientPropertiesUBOName, getLineGradientPropsBuffer());
uniforms.createOrUpdate("LineGradientUBO", &lineGradientUBO, context);
uniforms.addOrReplace("LineGradientPropertiesUBO", getLineGradientPropsBuffer());
} break;
case LineType::Pattern: {
// main UBO
Size textureSize{0, 0};
if (const auto index = shader->getSamplerLocation("u_image")) {
if (const auto& texture = drawable.getTexture(index.value())) {
@@ -240,21 +183,19 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
}
const LinePatternUBO linePatternUBO{
/*matrix =*/util::cast<float>(matrix),
/*scale =*/
{parameters.pixelRatio,
1 / tileID.pixelsToTileUnits(1, parameters.state.getIntegerZoom()),
crossfade.fromScale,
crossfade.toScale},
/*texsize =*/{static_cast<float>(textureSize.width), static_cast<float>(textureSize.height)},
/*units_to_pixels =*/{1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]},
/*ratio =*/1.0f / tileID.pixelsToTileUnits(1.0f, static_cast<float>(parameters.state.getZoom())),
/*ratio =*/1.0f / tileID.pixelsToTileUnits(1.0f, static_cast<float>(zoom)),
/*device_pixel_ratio =*/parameters.pixelRatio,
/*fade =*/crossfade.t,
0};
uniforms.createOrUpdate(LinePatternUBOName, &linePatternUBO, context);
uniforms.createOrUpdate("LinePatternUBO", &linePatternUBO, context);
// properties UBO
uniforms.addOrReplace(LinePatternPropertiesUBOName, getLinePatternPropsBuffer());
uniforms.addOrReplace("LinePatternPropertiesUBO", getLinePatternPropsBuffer());
} break;
case LineType::SDF: {
@@ -265,7 +206,6 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
evaluated.get<LineDasharray>().to,
lineData.linePatternCap);
// texture
if (const auto index = shader->getSamplerLocation("u_image")) {
if (!drawable.getTexture(index.value())) {
const auto& texture = dashPatternTexture.getTexture();
@@ -276,16 +216,13 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
}
}
// main UBO
const LinePatternPos& posA = dashPatternTexture.getFrom();
const LinePatternPos& posB = dashPatternTexture.getTo();
const float widthA = posA.width * crossfade.fromScale;
const float widthB = posB.width * crossfade.toScale;
const LineSDFUBO lineSDFUBO{
/* matrix = */ util::cast<float>(matrix),
/* units_to_pixels = */
{1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]},
/* patternscale_a = */
{1.0f / tileID.pixelsToTileUnits(widthA, parameters.state.getIntegerZoom()),
-posA.height / 2.0f},
/* patternscale_b = */
@@ -299,10 +236,9 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
/* sdfgamma = */ static_cast<float>(dashPatternTexture.getSize().width) /
(std::min(widthA, widthB) * 256.0f * parameters.pixelRatio) / 2.0f,
/* mix = */ crossfade.t};
uniforms.createOrUpdate(LineSDFUBOName, &lineSDFUBO, context);
uniforms.createOrUpdate("LineSDFUBO", &lineSDFUBO, context);
// properties UBO
uniforms.addOrReplace(LineSDFPropertiesUBOName, getLineSDFPropsBuffer());
uniforms.addOrReplace("LineSDFPropertiesUBO", getLineSDFPropsBuffer());
}
} break;
@@ -312,6 +248,11 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup,
"LineLayerTweaker: unknown line type: "s + std::to_string(mbgl::underlying_type(type)));
} break;
}
#if MLN_RENDER_BACKEND_METAL
uniforms.addOrReplace("ExpressionInputsUBO", expressionUniformBuffer);
uniforms.addOrReplace("LinePermutationUBO", permutationUniformBuffer);
#endif // MLN_RENDER_BACKEND_METAL
});
}

View File

@@ -23,9 +23,8 @@ public:
SDF
};
public:
LineLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
LineLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
~LineLayerTweaker() override = default;
@@ -36,6 +35,11 @@ protected:
gfx::UniformBufferPtr lineGradientPropertiesBuffer;
gfx::UniformBufferPtr linePatternPropertiesBuffer;
gfx::UniformBufferPtr lineSDFPropertiesBuffer;
#if MLN_RENDER_BACKEND_METAL
gfx::UniformBufferPtr permutationUniformBuffer;
gfx::UniformBufferPtr expressionUniformBuffer;
#endif // MLN_RENDER_BACKEND_METAL
};
} // namespace mbgl

View File

@@ -5,6 +5,7 @@
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/shaders/raster_layer_ubo.hpp>
#include <mbgl/style/layers/raster_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
#include <mbgl/gfx/image_drawable_data.hpp>
@@ -14,23 +15,7 @@ namespace mbgl {
using namespace style;
struct alignas(16) RasterDrawableUBO {
std::array<float, 4 * 4> matrix;
std::array<float, 4> spin_weights;
std::array<float, 2> tl_parent;
float scale_parent;
float buffer_scale;
float fade_t;
float opacity;
float brightness_low;
float brightness_high;
float saturation_factor;
float contrast_factor;
float pad1;
float pad2;
};
static_assert(sizeof(RasterDrawableUBO) == 128);
static_assert(sizeof(RasterDrawableUBO) % 16 == 0);
using namespace shaders;
void RasterLayerTweaker::execute([[maybe_unused]] LayerGroupBase& layerGroup,
[[maybe_unused]] const RenderTree& renderTree,
@@ -90,6 +75,9 @@ void RasterLayerTweaker::execute([[maybe_unused]] LayerGroupBase& layerGroup,
/*.brightness_high = */ evaluated.get<RasterBrightnessMax>(),
/*.saturation_factor = */ saturationFactor(evaluated.get<RasterSaturation>()),
/*.contrast_factor = */ contrastFactor(evaluated.get<RasterContrast>()),
/* .overdrawInspector = */ overdrawInspector,
0,
0,
0,
0};
auto& uniforms = drawable.mutableUniformBuffers();

View File

@@ -14,8 +14,8 @@ using UniformBufferPtr = std::shared_ptr<UniformBuffer>;
*/
class RasterLayerTweaker : public LayerTweaker {
public:
RasterLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
RasterLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~RasterLayerTweaker() override = default;

View File

@@ -67,7 +67,7 @@ void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters& paramet
#if MLN_DRAWABLE_RENDERER
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<BackgroundLayerTweaker>(evaluatedProperties));
layerGroup->setLayerTweaker(std::make_shared<BackgroundLayerTweaker>(getID(), evaluatedProperties));
}
#endif
}
@@ -216,6 +216,7 @@ static constexpr std::string_view BackgroundPatternShaderName = "BackgroundPatte
void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
const std::shared_ptr<UpdateParameters>&,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
@@ -249,7 +250,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
if (!layerGroup) {
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->setLayerTweaker(std::make_shared<BackgroundLayerTweaker>(evaluatedProperties));
layerGroup_->setLayerTweaker(std::make_shared<BackgroundLayerTweaker>(getID(), evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
}
}

View File

@@ -28,6 +28,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif

View File

@@ -1,23 +1,26 @@
#include <mbgl/renderer/layers/render_circle_layer.hpp>
#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/circle_program.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/shader_group.hpp>
#include <mbgl/gfx/shader_registry.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/circle_program.hpp>
#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/intersection_tests.hpp>
#if MLN_DRAWABLE_RENDERER
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/renderer/layers/circle_layer_tweaker.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/shaders/circle_layer_ubo.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#endif
namespace mbgl {
@@ -88,10 +91,8 @@ void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters)
evaluatedProperties = std::move(properties);
#if MLN_DRAWABLE_RENDERER
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<CircleLayerTweaker>(evaluatedProperties));
}
#endif
updateLayerTweaker();
#endif // MLN_DRAWABLE_RENDERER
}
bool RenderCircleLayer::hasTransition() const {
@@ -265,27 +266,30 @@ bool RenderCircleLayer::queryIntersectsFeature(const GeometryCoordinates& queryG
#if MLN_DRAWABLE_RENDERER
namespace {
struct alignas(16) CircleInterpolateUBO {
float color_t;
float radius_t;
float blur_t;
float opacity_t;
float stroke_color_t;
float stroke_width_t;
float stroke_opacity_t;
float padding;
};
static_assert(sizeof(CircleInterpolateUBO) % 16 == 0);
constexpr auto CircleShaderGroupName = "CircleShader";
constexpr auto CircleInterpolateUBOName = "CircleInterpolateUBO";
constexpr auto VertexAttribName = "a_pos";
} // namespace
using namespace shaders;
#if MLN_DRAWABLE_RENDERER
void RenderCircleLayer::updateLayerTweaker() {
if (layerGroup) {
tweaker = std::make_shared<CircleLayerTweaker>(getID(), evaluatedProperties);
#if MLN_RENDER_BACKEND_METAL
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
#endif // MLN_RENDER_BACKEND_METAL
tweaker->enableOverdrawInspector(overdrawInspector);
layerGroup->setLayerTweaker(tweaker);
}
}
#endif // MLN_DRAWABLE_RENDERER
void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
[[maybe_unused]] const std::shared_ptr<UpdateParameters>& updateParameters,
[[maybe_unused]] const RenderTree& renderTree,
UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
@@ -298,7 +302,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
// Set up a layer group
if (!layerGroup) {
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->setLayerTweaker(std::make_shared<CircleLayerTweaker>(evaluatedProperties));
layerGroup_->setLayerTweaker(std::make_shared<CircleLayerTweaker>(getID(), evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
}
}
@@ -312,6 +316,14 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
return;
}
const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw);
if (overdrawInspector != overdraw) {
overdrawInspector = overdraw;
if (tweaker) {
tweaker->enableOverdrawInspector(overdrawInspector);
}
}
std::unique_ptr<gfx::DrawableBuilder> circleBuilder;
constexpr auto renderPass = RenderPass::Translucent;
@@ -361,7 +373,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
// If there are already drawables for this tile, update their UBOs and move on to the next tile.
auto updateExisting = [&](gfx::Drawable& drawable) {
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.createOrUpdate(CircleInterpolateUBOName, &interpolateUBO, context);
uniforms.createOrUpdate("CircleInterpolateUBO", &interpolateUBO, context);
};
if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) {
continue;
@@ -370,20 +382,30 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
const auto interpBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO));
gfx::VertexAttributeArray circleVertexAttrs;
const auto propertiesAsUniforms = circleVertexAttrs.readDataDrivenPaintProperties<CircleColor,
CircleRadius,
CircleBlur,
CircleOpacity,
CircleStrokeColor,
CircleStrokeWidth,
CircleStrokeOpacity>(
auto propertiesAsUniforms_ = circleVertexAttrs.readDataDrivenPaintProperties<CircleColor,
CircleRadius,
CircleBlur,
CircleOpacity,
CircleStrokeColor,
CircleStrokeWidth,
CircleStrokeOpacity>(
paintPropertyBinders, evaluated);
const auto circleShader = circleShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
if (!circleShaderGroup) {
continue;
}
const auto circleShader = circleShaderGroup->getOrCreateShader(context, propertiesAsUniforms_);
if (!circleShader) {
continue;
}
#if MLN_RENDER_BACKEND_METAL
propertiesAsUniforms = std::move(propertiesAsUniforms_);
if (tweaker) {
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
}
#endif // MLN_RENDER_BACKEND_METAL
if (const auto& attr = circleVertexAttrs.add(VertexAttribName)) {
attr->setSharedRawData(bucket.sharedVertices,
offsetof(CircleLayoutVertex, a1),
@@ -411,7 +433,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
drawable->setTileID(tileID);
auto& uniforms = drawable->mutableUniformBuffers();
uniforms.addOrReplace(CircleInterpolateUBOName, interpBuffer);
uniforms.addOrReplace("CircleInterpolateUBO", interpBuffer);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;

View File

@@ -6,7 +6,14 @@
namespace mbgl {
#if MLN_LEGACY_RENDERER
class CircleProgram;
#endif // MLN_LEGACY_RENDERER
#if MLN_DRAWABLE_RENDERER
class CircleLayerTweaker;
using CircleLayerTweakerPtr = std::shared_ptr<CircleLayerTweaker>;
#endif // MLN_DRAWABLE_RENDERER
class RenderCircleLayer final : public RenderLayer {
public:
@@ -18,6 +25,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif
@@ -29,10 +37,6 @@ private:
bool hasTransition() const override;
bool hasCrossfade() const override;
#if MLN_LEGACY_RENDERER
void render(PaintParameters&) override;
#endif
bool queryIntersectsFeature(const GeometryCoordinates&,
const GeometryTileFeature&,
float,
@@ -41,6 +45,15 @@ private:
const mat4&,
const FeatureState&) const override;
#if MLN_LEGACY_RENDERER
void render(PaintParameters&) override;
#endif // MLN_LEGACY_RENDERER
#if MLN_DRAWABLE_RENDERER
void updateLayerTweaker();
#endif // MLN_DRAWABLE_RENDERER
private:
// Paint properties
style::CirclePaintProperties::Unevaluated unevaluated;
@@ -48,8 +61,16 @@ private:
// Programs
std::shared_ptr<CircleProgram> circleProgram;
#endif
#if MLN_DRAWABLE_RENDERER
gfx::ShaderGroupPtr circleShaderGroup;
CircleLayerTweakerPtr tweaker;
#if MLN_RENDER_BACKEND_METAL
std::vector<std::string> propertiesAsUniforms;
#endif // MLN_RENDER_BACKEND_METAL
bool overdrawInspector = false;
#endif
};

View File

@@ -122,6 +122,7 @@ void RenderCustomLayer::render(PaintParameters& paintParameters) {
void RenderCustomLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaders,
gfx::Context& context,
[[maybe_unused]] const TransformState& state,
const std::shared_ptr<UpdateParameters>&,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);

View File

@@ -15,6 +15,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif

View File

@@ -76,7 +76,7 @@ void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& para
#if MLN_DRAWABLE_RENDERER
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<FillExtrusionLayerTweaker>(evaluatedProperties));
layerGroup->setLayerTweaker(std::make_shared<FillExtrusionLayerTweaker>(getID(), evaluatedProperties));
}
#endif // MLN_DRAWABLE_RENDERER
}
@@ -276,6 +276,7 @@ bool RenderFillExtrusionLayer::queryIntersectsFeature(const GeometryCoordinates&
void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
const std::shared_ptr<UpdateParameters>&,
const RenderTree& /*renderTree*/,
UniqueChangeRequestVec& changes) {
if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) {
@@ -286,7 +287,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
// Set up a layer group
if (!layerGroup) {
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->setLayerTweaker(std::make_shared<FillExtrusionLayerTweaker>(evaluatedProperties));
layerGroup_->setLayerTweaker(std::make_shared<FillExtrusionLayerTweaker>(getID(), evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
}
}
@@ -403,6 +404,9 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
FillExtrusionHeight,
FillExtrusionPattern>(binders, evaluated);
if (!shaderGroup) {
continue;
}
const auto shader = std::static_pointer_cast<gfx::ShaderProgramBase>(
shaderGroup->getOrCreateShader(context, uniformProps));
if (!shader) {

View File

@@ -33,6 +33,7 @@ private:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif // MLN_DRAWABLE_RENDERER

View File

@@ -27,12 +27,15 @@
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/renderer/layers/fill_layer_tweaker.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/shaders/fill_layer_ubo.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#endif
namespace mbgl {
using namespace style;
using namespace shaders;
namespace {
@@ -93,8 +96,9 @@ void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) {
#if MLN_DRAWABLE_RENDERER
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<FillLayerTweaker>(evaluatedProperties));
layerGroup->setLayerTweaker(std::make_shared<FillLayerTweaker>(getID(), evaluatedProperties));
}
updateLayerTweaker();
#endif
}
@@ -295,9 +299,22 @@ bool RenderFillLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeo
}
#if MLN_DRAWABLE_RENDERER
void RenderFillLayer::updateLayerTweaker() {
if (layerGroup) {
tweaker = std::make_shared<FillLayerTweaker>(getID(), evaluatedProperties);
#if MLN_RENDER_BACKEND_METAL
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
#endif // MLN_RENDER_BACKEND_METAL
tweaker->enableOverdrawInspector(overdrawInspector);
layerGroup->setLayerTweaker(tweaker);
}
}
void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
const std::shared_ptr<UpdateParameters>& updateParameters,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
@@ -307,11 +324,20 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
return;
}
const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw);
if (overdrawInspector != overdraw) {
overdrawInspector = overdraw;
if (tweaker) {
tweaker->enableOverdrawInspector(overdrawInspector);
}
}
// Set up a layer group
if (!layerGroup) {
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->setLayerTweaker(std::make_shared<FillLayerTweaker>(evaluatedProperties));
layerGroup_->setLayerTweaker(std::make_shared<FillLayerTweaker>(getID(), evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
updateLayerTweaker();
}
}
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
@@ -341,22 +367,6 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
const auto layerPrefix = getID() + "/";
const auto renderPass = RenderPass::Translucent;
const auto finish = [&](gfx::DrawableBuilder& builder,
const OverscaledTileID& tileID,
const FillInterpolateUBO& interpUBO,
const FillDrawableTilePropsUBO& tileUBO) {
builder.flush();
for (auto& drawable : builder.clearDrawables()) {
drawable->setTileID(tileID);
auto& uniforms = drawable->mutableUniformBuffers();
uniforms.createOrUpdate(FillLayerTweaker::FillInterpolateUBOName, &interpUBO, context);
uniforms.createOrUpdate(FillLayerTweaker::FillTilePropsUBOName, &tileUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
};
const auto commonInit = [&](gfx::DrawableBuilder& builder) {
builder.setCullFaceMode(gfx::CullFaceMode::disabled());
builder.setEnableStencil(true);
@@ -399,24 +409,109 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
binders.setPatternParameters(patternPosA, patternPosB, crossfade);
const auto zoom = static_cast<float>(state.getZoom());
const FillInterpolateUBO interpolateUBO = {
/* .color_t = */ std::get<0>(binders.get<FillColor>()->interpolationFactor(zoom)),
/* .opacity_t = */ std::get<0>(binders.get<FillOpacity>()->interpolationFactor(zoom)),
/* .outline_color_t = */ std::get<0>(binders.get<FillOutlineColor>()->interpolationFactor(zoom)),
/* .pattern_from_t = */ std::get<0>(binders.get<FillPattern>()->interpolationFactor(zoom)),
/* .pattern_to_t = */ std::get<0>(binders.get<FillPattern>()->interpolationFactor(zoom)),
/* .fade = */ crossfade.t,
/* .padding = */ 0,
0};
const FillDrawableTilePropsUBO tileProps = {
/* pattern_from = */ patternPosA ? util::cast<float>(patternPosA->tlbr()) : std::array<float, 4>{0},
/* pattern_to = */ patternPosB ? util::cast<float>(patternPosB->tlbr()) : std::array<float, 4>{0},
std::optional<FillInterpolateUBO> fillInterpolateUBO = std::nullopt;
std::optional<FillOutlineInterpolateUBO> fillOutlineInterpolateUBO = std::nullopt;
std::optional<FillPatternInterpolateUBO> fillPatternInterpolateUBO = std::nullopt;
std::optional<FillOutlinePatternInterpolateUBO> fillOutlinePatternInterpolateUBO = std::nullopt;
auto getFillInterpolateUBO = [&]() -> const FillInterpolateUBO& {
if (!fillInterpolateUBO) {
fillInterpolateUBO = {
/* .color_t = */ std::get<0>(binders.get<FillColor>()->interpolationFactor(zoom)),
/* .opacity_t = */ std::get<0>(binders.get<FillOpacity>()->interpolationFactor(zoom)),
0,
0,
};
}
return *fillInterpolateUBO;
};
auto getFillOutlineInterpolateUBO = [&]() -> const FillOutlineInterpolateUBO& {
if (!fillOutlineInterpolateUBO) {
fillOutlineInterpolateUBO = {
/* .color_t = */ std::get<0>(binders.get<FillOutlineColor>()->interpolationFactor(zoom)),
/* .opacity_t = */ std::get<0>(binders.get<FillOpacity>()->interpolationFactor(zoom)),
0,
0,
};
}
return *fillOutlineInterpolateUBO;
};
auto getFillPatternInterpolateUBO = [&]() -> const FillPatternInterpolateUBO& {
if (!fillPatternInterpolateUBO) {
fillPatternInterpolateUBO = {
/* .pattern_from_t = */ std::get<0>(binders.get<FillPattern>()->interpolationFactor(zoom)),
/* .pattern_to_t = */ std::get<0>(binders.get<FillPattern>()->interpolationFactor(zoom)),
/* .opacity_t = */ std::get<0>(binders.get<FillOpacity>()->interpolationFactor(zoom)),
0,
};
}
return *fillPatternInterpolateUBO;
};
auto getFillOutlinePatternInterpolateUBO = [&]() -> const FillOutlinePatternInterpolateUBO& {
if (!fillOutlinePatternInterpolateUBO) {
fillOutlinePatternInterpolateUBO = {
/* .pattern_from_t = */ std::get<0>(binders.get<FillPattern>()->interpolationFactor(zoom)),
/* .pattern_to_t = */ std::get<0>(binders.get<FillPattern>()->interpolationFactor(zoom)),
/* .opacity_t = */ std::get<0>(binders.get<FillOpacity>()->interpolationFactor(zoom)),
0,
};
}
return *fillOutlinePatternInterpolateUBO;
};
std::optional<FillPatternTilePropsUBO> fillPatternTilePropsUBO = std::nullopt;
auto getFillPatternTilePropsUBO = [&]() -> const FillPatternTilePropsUBO& {
if (!fillPatternTilePropsUBO) {
fillPatternTilePropsUBO = {
/* pattern_from = */ patternPosA ? util::cast<float>(patternPosA->tlbr()) : std::array<float, 4>{0},
/* pattern_to = */ patternPosB ? util::cast<float>(patternPosB->tlbr()) : std::array<float, 4>{0},
};
}
return *fillPatternTilePropsUBO;
};
std::optional<FillOutlinePatternTilePropsUBO> fillOutlinePatternTilePropsUBO = std::nullopt;
auto getFillOutlinePatternTilePropsUBO = [&]() -> const FillOutlinePatternTilePropsUBO& {
if (!fillOutlinePatternTilePropsUBO) {
fillOutlinePatternTilePropsUBO = {
/* pattern_from = */ patternPosA ? util::cast<float>(patternPosA->tlbr()) : std::array<float, 4>{0},
/* pattern_to = */ patternPosB ? util::cast<float>(patternPosB->tlbr()) : std::array<float, 4>{0},
};
}
return *fillOutlinePatternTilePropsUBO;
};
gfx::DrawableTweakerPtr atlasTweaker;
auto getAtlasTweaker = [&]() {
if (!atlasTweaker) {
if (const auto& atlases = tile.getAtlasTextures(); atlases && atlases->icon) {
atlasTweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(
atlases,
std::string(),
IconTextureName,
/*isText*/ false,
/*sdfIcons*/ true, // to force linear filter
/*rotationAlignment_*/ AlignmentType::Auto,
/*iconScaled*/ false,
/*textSizeIsZoomConstant_*/ false);
}
}
return atlasTweaker;
};
// `Fill*Program` all use `style::FillPaintProperties`
gfx::VertexAttributeArray vertexAttrs;
const auto uniformProps =
const auto propertiesAsUniforms_ =
vertexAttrs.readDataDrivenPaintProperties<FillColor, FillOpacity, FillOutlineColor, FillPattern>(binders,
evaluated);
@@ -432,28 +527,49 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
// If we already have drawables for this tile, update them.
auto updateExisting = [&](gfx::Drawable& drawable) {
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.createOrUpdate(FillLayerTweaker::FillInterpolateUBOName, &interpolateUBO, context);
uniforms.createOrUpdate(FillLayerTweaker::FillTilePropsUBOName, &tileProps, context);
if (uniforms.get("FillInterpolateUBO")) {
uniforms.createOrUpdate("FillInterpolateUBO", &getFillInterpolateUBO(), context);
} else if (uniforms.get("FillOutlineInterpolateUBO")) {
uniforms.createOrUpdate("FillOutlineInterpolateUBO", &getFillOutlineInterpolateUBO(), context);
} else if (uniforms.get("FillPatternInterpolateUBO")) {
uniforms.createOrUpdate("FillPatternInterpolateUBO", &getFillPatternInterpolateUBO(), context);
uniforms.createOrUpdate("FillPatternTilePropsUBO", &getFillPatternTilePropsUBO(), context);
} else if (uniforms.get("FillOutlinePatternInterpolateUBO")) {
uniforms.createOrUpdate(
"FillOutlinePatternInterpolateUBO", &getFillOutlinePatternInterpolateUBO(), context);
uniforms.createOrUpdate(
"FillOutlinePatternTilePropsUBO", &getFillOutlinePatternTilePropsUBO(), context);
} else {
assert(false);
}
drawable.setVertexAttributes(vertexAttrs);
};
if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) {
continue;
}
// Share UBO buffers among any drawables created for this tile
const auto interpBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO));
const auto tilePropsBuffer = context.createUniformBuffer(&tileProps, sizeof(tileProps));
if (unevaluated.get<FillPattern>().isUndefined()) {
// Fill will occur in opaque or translucent pass based on `opaquePassCutoff`.
// Outline always occurs in translucent pass, defaults to fill color
const auto doOutline = evaluated.get<FillAntialias>();
if (!fillShaderGroup || (doOutline && !outlineShaderGroup)) {
continue;
}
const auto fillShader = std::static_pointer_cast<gfx::ShaderProgramBase>(
fillShaderGroup->getOrCreateShader(context, uniformProps));
const auto outlineShader = doOutline ? std::static_pointer_cast<gfx::ShaderProgramBase>(
outlineShaderGroup->getOrCreateShader(context, uniformProps))
: nullptr;
fillShaderGroup->getOrCreateShader(context, propertiesAsUniforms_));
const auto outlineShader = doOutline
? std::static_pointer_cast<gfx::ShaderProgramBase>(
outlineShaderGroup->getOrCreateShader(context, propertiesAsUniforms_))
: nullptr;
#if MLN_RENDER_BACKEND_METAL
propertiesAsUniforms = std::move(propertiesAsUniforms_);
if (tweaker) {
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
}
#endif // MLN_RENDER_BACKEND_METAL
if (!fillBuilder && fillShader) {
if (auto builder = context.createDrawableBuilder(layerPrefix + "fill")) {
@@ -479,7 +595,20 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
}
}
if (fillBuilder) {
const auto finish =
[&](gfx::DrawableBuilder& builder, const std::string& interpolateUBOName, const auto& interpolateUBO) {
builder.flush();
for (auto& drawable : builder.clearDrawables()) {
drawable->setTileID(tileID);
auto& uniforms = drawable->mutableUniformBuffers();
uniforms.createOrUpdate(interpolateUBOName, &interpolateUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
};
if (fillBuilder && bucket.sharedTriangles->elements()) {
fillBuilder->setShader(fillShader);
if (outlineBuilder) {
fillBuilder->setVertexAttributes(vertexAttrs);
@@ -491,15 +620,15 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
bucket.sharedTriangles,
bucket.triangleSegments.data(),
bucket.triangleSegments.size());
finish(*fillBuilder, tileID, interpolateUBO, tileProps);
finish(*fillBuilder, "FillInterpolateUBO", getFillInterpolateUBO());
}
if (outlineBuilder) {
if (outlineBuilder && bucket.sharedLines->elements()) {
outlineBuilder->setShader(outlineShader);
outlineBuilder->setVertexAttributes(std::move(vertexAttrs));
outlineBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
outlineBuilder->setSegments(
gfx::Lines(2), bucket.sharedLines, bucket.lineSegments.data(), bucket.lineSegments.size());
finish(*outlineBuilder, tileID, interpolateUBO, tileProps);
finish(*outlineBuilder, "FillOutlineInterpolateUBO", getFillOutlineInterpolateUBO());
}
} else { // FillPattern is defined
if ((renderPass & RenderPass::Translucent) == 0) {
@@ -509,16 +638,28 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
// Outline does not default to fill in the pattern case
const auto doOutline = evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined();
if (!patternShaderGroup || (doOutline && !outlinePatternShaderGroup)) {
continue;
}
const auto fillShader = std::static_pointer_cast<gfx::ShaderProgramBase>(
patternShaderGroup->getOrCreateShader(context, uniformProps));
const auto outlineShader = doOutline
? std::static_pointer_cast<gfx::ShaderProgramBase>(
outlinePatternShaderGroup->getOrCreateShader(context, uniformProps))
: nullptr;
patternShaderGroup->getOrCreateShader(context, propertiesAsUniforms_));
const auto outlineShader = doOutline ? std::static_pointer_cast<gfx::ShaderProgramBase>(
outlinePatternShaderGroup->getOrCreateShader(
context, propertiesAsUniforms_))
: nullptr;
#if MLN_RENDER_BACKEND_METAL
propertiesAsUniforms = std::move(propertiesAsUniforms_);
if (tweaker) {
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
}
#endif // MLN_RENDER_BACKEND_METAL
if (!patternBuilder) {
if (auto builder = context.createDrawableBuilder(layerPrefix + "fill-pattern")) {
commonInit(*builder);
builder->setShader(fillShader);
builder->setDepthType(gfx::DepthMaskType::ReadWrite);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setSubLayerIndex(1);
@@ -529,6 +670,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
if (doOutline && !outlinePatternBuilder) {
if (auto builder = context.createDrawableBuilder(layerPrefix + "fill-outline-pattern")) {
commonInit(*builder);
builder->setShader(outlineShader);
builder->setLineWidth(2.0f);
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
builder->setColorMode(gfx::ColorMode::alphaBlended());
@@ -540,28 +682,29 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
if (patternBuilder) {
patternBuilder->clearTweakers();
patternBuilder->addTweaker(getAtlasTweaker());
}
if (outlinePatternBuilder) {
outlinePatternBuilder->clearTweakers();
outlinePatternBuilder->addTweaker(getAtlasTweaker());
}
if (patternBuilder || outlinePatternBuilder) {
if (const auto& atlases = tile.getAtlasTextures()) {
auto tweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(atlases,
/*glyphName=*/std::string(),
std::string(IconTextureName),
/*isText=*/false,
false,
style::AlignmentType::Auto,
false,
false);
if (patternBuilder) {
patternBuilder->addTweaker(tweaker);
}
if (outlinePatternBuilder) {
outlinePatternBuilder->addTweaker(std::move(tweaker));
}
const auto finish = [&](gfx::DrawableBuilder& builder,
const std::string& interpolateName,
const auto& interpolateUBO,
const std::string& tileUBOName,
const auto& tileUBO) {
builder.flush();
for (auto& drawable : builder.clearDrawables()) {
drawable->setTileID(tileID);
auto& uniforms = drawable->mutableUniformBuffers();
uniforms.createOrUpdate(interpolateName, &interpolateUBO, context);
uniforms.createOrUpdate(tileUBOName, &tileUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
}
};
if (patternBuilder) {
patternBuilder->setShader(fillShader);
@@ -577,7 +720,11 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
bucket.triangleSegments.data(),
bucket.triangleSegments.size());
finish(*patternBuilder, tileID, interpolateUBO, tileProps);
finish(*patternBuilder,
"FillPatternInterpolateUBO",
getFillPatternInterpolateUBO(),
"FillPatternTilePropsUBO",
getFillPatternTilePropsUBO());
}
if (outlinePatternBuilder) {
outlinePatternBuilder->setShader(outlineShader);
@@ -587,7 +734,11 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
outlinePatternBuilder->setSegments(
gfx::Lines(2), bucket.sharedLines, bucket.lineSegments.data(), bucket.lineSegments.size());
finish(*outlinePatternBuilder, tileID, interpolateUBO, tileProps);
finish(*outlinePatternBuilder,
"FillOutlinePatternInterpolateUBO",
getFillOutlinePatternInterpolateUBO(),
"FillOutlinePatternTilePropsUBO",
getFillOutlinePatternTilePropsUBO());
}
}
}

View File

@@ -15,6 +15,11 @@ class FillPatternProgram;
class FillOutlineProgram;
class FillOutlinePatternProgram;
#if MLN_DRAWABLE_RENDERER
class FillLayerTweaker;
using FillLayerTweakerPtr = std::shared_ptr<FillLayerTweaker>;
#endif // MLN_DRAWABLE_RENDERER
class RenderFillLayer final : public RenderLayer {
public:
explicit RenderFillLayer(Immutable<style::FillLayer::Impl>);
@@ -25,6 +30,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif
@@ -40,6 +46,10 @@ private:
void render(PaintParameters&) override;
#endif
#if MLN_DRAWABLE_RENDERER
void updateLayerTweaker();
#endif // MLN_DRAWABLE_RENDERER
bool queryIntersectsFeature(const GeometryCoordinates&,
const GeometryTileFeature&,
float,
@@ -63,6 +73,13 @@ private:
gfx::ShaderGroupPtr outlineShaderGroup;
gfx::ShaderGroupPtr patternShaderGroup;
gfx::ShaderGroupPtr outlinePatternShaderGroup;
FillLayerTweakerPtr tweaker;
#if MLN_RENDER_BACKEND_METAL
std::vector<std::string> propertiesAsUniforms;
#endif // MLN_RENDER_BACKEND_METAL
bool overdrawInspector = false;
#endif
};

View File

@@ -68,10 +68,11 @@ void RenderHeatmapLayer::evaluate(const PropertyEvaluationParameters& parameters
#if MLN_DRAWABLE_RENDERER
if (renderTarget) {
renderTarget->getLayerGroup(0)->setLayerTweaker(std::make_shared<HeatmapLayerTweaker>(evaluatedProperties));
renderTarget->getLayerGroup(0)->setLayerTweaker(
std::make_shared<HeatmapLayerTweaker>(getID(), evaluatedProperties));
}
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<HeatmapTextureLayerTweaker>(evaluatedProperties));
layerGroup->setLayerTweaker(std::make_shared<HeatmapTextureLayerTweaker>(getID(), evaluatedProperties));
}
#endif
}
@@ -280,6 +281,7 @@ constexpr auto VertexAttribName = "a_pos";
void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
const std::shared_ptr<UpdateParameters>&,
[[maybe_unused]] const RenderTree& renderTree,
UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
@@ -305,7 +307,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
if (!tileLayerGroup) {
return;
}
tileLayerGroup->setLayerTweaker(std::make_shared<HeatmapLayerTweaker>(evaluatedProperties));
tileLayerGroup->setLayerTweaker(std::make_shared<HeatmapLayerTweaker>(getID(), evaluatedProperties));
renderTarget->addLayerGroup(tileLayerGroup, /*replace=*/true);
}
@@ -375,6 +377,9 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
heatmapVertexAttrs.readDataDrivenPaintProperties<HeatmapWeight, HeatmapRadius>(paintPropertyBinders,
evaluated);
if (!heatmapShaderGroup) {
continue;
}
const auto heatmapShader = heatmapShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
if (!heatmapShader) {
continue;
@@ -417,7 +422,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
if (!layerGroup_) {
return;
}
layerGroup_->setLayerTweaker(std::make_shared<HeatmapTextureLayerTweaker>(evaluatedProperties));
layerGroup_->setLayerTweaker(std::make_shared<HeatmapTextureLayerTweaker>(getID(), evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
}

View File

@@ -23,6 +23,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif

View File

@@ -73,7 +73,7 @@ void RenderHillshadeLayer::evaluate(const PropertyEvaluationParameters& paramete
evaluatedProperties = std::move(properties);
#if MLN_DRAWABLE_RENDERER
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<HillshadeLayerTweaker>(evaluatedProperties));
layerGroup->setLayerTweaker(std::make_shared<HillshadeLayerTweaker>(getID(), evaluatedProperties));
}
#endif
}
@@ -287,6 +287,7 @@ constexpr auto TexturePosAttribName = "a_texture_pos";
void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
[[maybe_unused]] const TransformState& state,
const std::shared_ptr<UpdateParameters>&,
[[maybe_unused]] const RenderTree& renderTree,
UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
@@ -302,7 +303,7 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
if (!layerGroup_) {
return;
}
layerGroup_->setLayerTweaker(std::make_shared<HillshadeLayerTweaker>(evaluatedProperties));
layerGroup_->setLayerTweaker(std::make_shared<HillshadeLayerTweaker>(getID(), evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
}
@@ -370,7 +371,8 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
if (!singleTileLayerGroup) {
return;
}
singleTileLayerGroup->setLayerTweaker(std::make_shared<HillshadePrepareLayerTweaker>(evaluatedProperties));
singleTileLayerGroup->setLayerTweaker(
std::make_shared<HillshadePrepareLayerTweaker>(getID(), evaluatedProperties));
renderTarget->addLayerGroup(singleTileLayerGroup, /*replace=*/true);
gfx::VertexAttributeArray hillshadePrepareVertexAttrs;

View File

@@ -26,6 +26,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif

View File

@@ -1,3 +1,5 @@
#include <mbgl/renderer/layers/render_line_layer.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
@@ -5,7 +7,6 @@
#include <mbgl/programs/programs.hpp>
#include <mbgl/renderer/buckets/line_bucket.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/renderer/layers/render_line_layer.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
@@ -15,9 +16,10 @@
#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/util/intersection_tests.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/convert.hpp>
#include <mbgl/util/intersection_tests.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/math.hpp>
#if MLN_DRAWABLE_RENDERER
#include <mbgl/gfx/drawable_builder.hpp>
@@ -28,9 +30,21 @@
#include <mbgl/shaders/shader_program_base.hpp>
#endif
#if MLN_DRAWABLE_RENDERER
#include <mbgl/gfx/drawable_atlases_tweaker.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/gfx/line_drawable_data.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/layers/line_layer_tweaker.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/shaders/line_layer_ubo.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#endif
namespace mbgl {
using namespace style;
using namespace shaders;
namespace {
@@ -75,9 +89,7 @@ void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) {
evaluatedProperties = std::move(properties);
#if MLN_DRAWABLE_RENDERER
if (layerGroup && layerGroup->getLayerTweaker()) {
layerGroup->setLayerTweaker(std::make_shared<LineLayerTweaker>(evaluatedProperties));
}
updateLayerTweaker();
#endif
}
@@ -344,74 +356,24 @@ float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature,
#if MLN_DRAWABLE_RENDERER
/// Property interpolation UBOs
struct alignas(16) LineInterpolationUBO {
float color_t;
float blur_t;
float opacity_t;
float gapwidth_t;
float offset_t;
float width_t;
float pad1;
float pad2;
};
static_assert(sizeof(LineInterpolationUBO) % 16 == 0);
static constexpr std::string_view LineInterpolationUBOName = "LineInterpolationUBO";
struct alignas(16) LineGradientInterpolationUBO {
float blur_t;
float opacity_t;
float gapwidth_t;
float offset_t;
float width_t;
float pad1;
std::array<float, 2> pad2;
};
static_assert(sizeof(LineGradientInterpolationUBO) % 16 == 0);
static constexpr std::string_view LineGradientInterpolationUBOName = "LineGradientInterpolationUBO";
struct alignas(16) LinePatternInterpolationUBO {
float blur_t;
float opacity_t;
float offset_t;
float gapwidth_t;
float width_t;
float pattern_from_t;
float pattern_to_t;
float pad1;
};
static_assert(sizeof(LinePatternInterpolationUBO) % 16 == 0);
static constexpr std::string_view LinePatternInterpolationUBOName = "LinePatternInterpolationUBO";
struct alignas(16) LineSDFInterpolationUBO {
float color_t;
float blur_t;
float opacity_t;
float gapwidth_t;
float offset_t;
float width_t;
float floorwidth_t;
float pad1;
};
static_assert(sizeof(LineSDFInterpolationUBO) % 16 == 0);
static constexpr std::string_view LineSDFInterpolationUBOName = "LineSDFInterpolationUBO";
/// Evaluated properties that depend on the tile
struct alignas(16) LinePatternTilePropertiesUBO {
std::array<float, 4> pattern_from;
std::array<float, 4> pattern_to;
};
static_assert(sizeof(LinePatternTilePropertiesUBO) % 16 == 0);
static constexpr std::string_view LinePatternTilePropertiesUBOName = "LinePatternTilePropertiesUBO";
void RenderLineLayer::updateLayerTweaker() {
if (layerGroup) {
tweaker = std::make_shared<LineLayerTweaker>(getID(), evaluatedProperties);
#if MLN_RENDER_BACKEND_METAL
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
#endif // MLN_RENDER_BACKEND_METAL
tweaker->enableOverdrawInspector(overdrawInspector);
layerGroup->setLayerTweaker(tweaker);
}
}
static constexpr auto LineImageUniformName = "u_image";
void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
const std::shared_ptr<UpdateParameters>& updateParameters,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
@@ -421,11 +383,19 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
return;
}
const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw);
if (overdrawInspector != overdraw) {
overdrawInspector = overdraw;
if (tweaker) {
tweaker->enableOverdrawInspector(overdrawInspector);
}
}
// Set up a layer group
if (!layerGroup) {
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->setLayerTweaker(std::make_shared<LineLayerTweaker>(evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
updateLayerTweaker();
}
}
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
@@ -538,7 +508,8 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
/*offset_t =*/std::get<0>(paintPropertyBinders.get<LineOffset>()->interpolationFactor(zoom)),
/*width_t =*/std::get<0>(paintPropertyBinders.get<LineWidth>()->interpolationFactor(zoom)),
0,
{0, 0}};
0,
0};
const LinePatternInterpolationUBO linePatternInterpolationUBO{
/*blur_t =*/std::get<0>(paintPropertyBinders.get<LineBlur>()->interpolationFactor(zoom)),
/*opacity_t =*/std::get<0>(paintPropertyBinders.get<LineOpacity>()->interpolationFactor(zoom)),
@@ -568,48 +539,63 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
// update existing drawables
tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
// TODO: use line type
const auto& shader = drawable.getShader();
const auto& shaderUniforms = shader->getUniformBlocks();
auto& drawableUniforms = drawable.mutableUniformBuffers();
// simple line interpolation UBO
if (drawable.getShader()->getUniformBlocks().get(std::string(LineInterpolationUBOName))) {
drawable.mutableUniformBuffers().createOrUpdate(
LineInterpolationUBOName, &lineInterpolationUBO, context);
if (shaderUniforms.get("LineInterpolationUBO")) {
drawableUniforms.createOrUpdate("LineInterpolationUBO", &lineInterpolationUBO, context);
}
// gradient line interpolation UBO
else if (drawable.getShader()->getUniformBlocks().get(std::string(LineGradientInterpolationUBOName))) {
drawable.mutableUniformBuffers().createOrUpdate(
LineGradientInterpolationUBOName, &lineGradientInterpolationUBO, context);
else if (shaderUniforms.get("LineGradientInterpolationUBO")) {
drawableUniforms.createOrUpdate("LineGradientInterpolationUBO", &lineGradientInterpolationUBO, context);
}
// pattern line interpolation UBO
else if (drawable.getShader()->getUniformBlocks().get(std::string(LinePatternInterpolationUBOName))) {
else if (shaderUniforms.get("LinePatternInterpolationUBO")) {
// interpolation
drawable.mutableUniformBuffers().createOrUpdate(
LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context);
drawableUniforms.createOrUpdate("LinePatternInterpolationUBO", &linePatternInterpolationUBO, context);
// tile properties
drawable.mutableUniformBuffers().createOrUpdate(
LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context);
drawableUniforms.createOrUpdate("LinePatternTilePropertiesUBO", &linePatternTilePropertiesUBO, context);
}
// SDF line interpolation UBO
else if (drawable.getShader()->getUniformBlocks().get(std::string(LineSDFInterpolationUBOName))) {
drawable.mutableUniformBuffers().createOrUpdate(
LineSDFInterpolationUBOName, &lineSDFInterpolationUBO, context);
else if (shaderUniforms.get("LineSDFInterpolationUBO")) {
drawableUniforms.createOrUpdate("LineSDFInterpolationUBO", &lineSDFInterpolationUBO, context);
}
});
if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) continue;
if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) {
continue;
}
if (!evaluated.get<LineDasharray>().from.empty()) {
// dash array line (SDF)
gfx::VertexAttributeArray vertexAttrs;
const auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties<LineColor,
LineBlur,
LineOpacity,
LineGapWidth,
LineOffset,
LineWidth,
LineFloorWidth>(
paintPropertyBinders, evaluated);
auto builder = createLineBuilder("lineSDF",
lineSDFShaderGroup->getOrCreateShader(context, propertiesAsUniforms));
auto propertiesAsUniforms_ = vertexAttrs.readDataDrivenPaintProperties<LineColor,
LineBlur,
LineOpacity,
LineGapWidth,
LineOffset,
LineWidth,
LineFloorWidth>(paintPropertyBinders,
evaluated);
if (!lineSDFShaderGroup) {
continue;
}
auto shader = lineSDFShaderGroup->getOrCreateShader(context, propertiesAsUniforms_);
if (!shader) {
continue;
}
#if MLN_RENDER_BACKEND_METAL
propertiesAsUniforms = std::move(propertiesAsUniforms_);
if (tweaker) {
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
}
#endif // MLN_RENDER_BACKEND_METAL
auto builder = createLineBuilder("lineSDF", std::move(shader));
// vertices, attributes and segments
addAttributes(*builder, bucket, std::move(vertexAttrs));
@@ -624,7 +610,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
drawable->setTileID(tileID);
drawable->setData(std::make_unique<gfx::LineDrawableData>(cap));
drawable->mutableUniformBuffers().createOrUpdate(
LineSDFInterpolationUBOName, &lineSDFInterpolationUBO, context);
"LineSDFInterpolationUBO", &lineSDFInterpolationUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
@@ -633,15 +619,30 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
// pattern line
gfx::VertexAttributeArray vertexAttrs;
paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade);
auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties<LineBlur,
LineOpacity,
LineOffset,
LineGapWidth,
LineWidth,
LinePattern>(paintPropertyBinders,
evaluated);
auto builder = createLineBuilder("linePattern",
linePatternShaderGroup->getOrCreateShader(context, propertiesAsUniforms));
auto propertiesAsUniforms_ = vertexAttrs.readDataDrivenPaintProperties<LineBlur,
LineOpacity,
LineOffset,
LineGapWidth,
LineWidth,
LinePattern>(paintPropertyBinders,
evaluated);
if (!linePatternShaderGroup) {
continue;
}
auto shader = linePatternShaderGroup->getOrCreateShader(context, propertiesAsUniforms_);
if (!shader) {
continue;
}
#if MLN_RENDER_BACKEND_METAL
propertiesAsUniforms = std::move(propertiesAsUniforms_);
if (tweaker) {
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
}
#endif // MLN_RENDER_BACKEND_METAL
auto builder = createLineBuilder("linePattern", std::move(shader));
// vertices and attributes
addAttributes(*builder, bucket, std::move(vertexAttrs));
@@ -662,33 +663,44 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
builder->addTweaker(iconTweaker);
// segments
setSegments(builder, bucket);
// finish
builder->flush();
for (auto& drawable : builder->clearDrawables()) {
drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Pattern));
drawable->setTileID(tileID);
drawable->mutableUniformBuffers().createOrUpdate(
LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context);
"LinePatternInterpolationUBO", &linePatternInterpolationUBO, context);
drawable->mutableUniformBuffers().createOrUpdate(
LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context);
"LinePatternTilePropertiesUBO", &linePatternTilePropertiesUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
}
} else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
// gradient line
gfx::VertexAttributeArray vertexAttrs;
auto propertiesAsUniforms =
auto propertiesAsUniforms_ =
vertexAttrs.readDataDrivenPaintProperties<LineBlur, LineOpacity, LineGapWidth, LineOffset, LineWidth>(
paintPropertyBinders, evaluated);
auto builder = createLineBuilder("lineGradient",
lineGradientShaderGroup->getOrCreateShader(context, propertiesAsUniforms));
if (!lineGradientShaderGroup) {
continue;
}
auto shader = lineGradientShaderGroup->getOrCreateShader(context, propertiesAsUniforms_);
if (!shader) {
continue;
}
#if MLN_RENDER_BACKEND_METAL
propertiesAsUniforms = std::move(propertiesAsUniforms_);
if (tweaker) {
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
}
#endif // MLN_RENDER_BACKEND_METAL
auto builder = createLineBuilder("lineGradient", std::move(shader));
// vertices and attributes
addAttributes(*builder, bucket, std::move(vertexAttrs));
@@ -715,7 +727,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Gradient));
drawable->setTileID(tileID);
drawable->mutableUniformBuffers().createOrUpdate(
LineGradientInterpolationUBOName, &lineGradientInterpolationUBO, context);
"LineGradientInterpolationUBO", &lineGradientInterpolationUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
@@ -726,14 +738,35 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
} else {
// simple line
gfx::VertexAttributeArray vertexAttrs;
const auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties<LineColor,
LineBlur,
LineOpacity,
LineGapWidth,
LineOffset,
LineWidth>(paintPropertyBinders,
evaluated);
auto builder = createLineBuilder("line", lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms));
const auto propertiesAsUniforms_ = vertexAttrs.readDataDrivenPaintProperties<LineColor,
LineBlur,
LineOpacity,
LineGapWidth,
LineOffset,
LineWidth>(
paintPropertyBinders, evaluated);
assert(6 == propertiesAsUniforms_.size());
assert(vertexAttrs.size() == (size_t)std::count_if(propertiesAsUniforms_.begin(),
propertiesAsUniforms_.end(),
[](const auto& s) { return s.empty(); }));
if (!lineShaderGroup) {
continue;
}
auto shader = lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms_);
if (!shader) {
continue;
}
#if MLN_RENDER_BACKEND_METAL
propertiesAsUniforms = std::move(propertiesAsUniforms_);
if (tweaker) {
tweaker->setPropertiesAsUniforms(propertiesAsUniforms);
}
#endif // MLN_RENDER_BACKEND_METAL
auto builder = createLineBuilder("line", std::move(shader));
// vertices, attributes and segments
addAttributes(*builder, bucket, std::move(vertexAttrs));
@@ -745,7 +778,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Simple));
drawable->setTileID(tileID);
drawable->mutableUniformBuffers().createOrUpdate(
LineInterpolationUBOName, &lineInterpolationUBO, context);
"LineInterpolationUBO", &lineInterpolationUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;

View File

@@ -27,6 +27,9 @@ class UniformBuffer;
using ShaderGroupPtr = std::shared_ptr<ShaderGroup>;
using UniformBufferPtr = std::shared_ptr<UniformBuffer>;
} // namespace gfx
class LineLayerTweaker;
using LineLayerTweakerPtr = std::shared_ptr<LineLayerTweaker>;
#endif
class RenderLineLayer final : public RenderLayer {
@@ -39,6 +42,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif
@@ -54,6 +58,9 @@ private:
#if MLN_LEGACY_RENDERER
void render(PaintParameters&) override;
#endif
#if MLN_DRAWABLE_RENDERER
void updateLayerTweaker();
#endif
bool queryIntersectsFeature(const GeometryCoordinates&,
const GeometryTileFeature&,
@@ -90,6 +97,13 @@ private:
gfx::ShaderGroupPtr linePatternShaderGroup;
gfx::DrawableTweakerPtr iconTweaker;
LineLayerTweakerPtr tweaker;
#if MLN_RENDER_BACKEND_METAL
std::vector<std::string> propertiesAsUniforms;
#endif // MLN_RENDER_BACKEND_METAL
bool overdrawInspector = false;
#endif
};

View File

@@ -18,6 +18,7 @@
#include <mbgl/gfx/drawable_impl.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#endif
@@ -52,9 +53,7 @@ void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters)
evaluatedProperties = std::move(properties);
#if MLN_DRAWABLE_RENDERER
if (layerGroup && layerGroup->getLayerTweaker()) {
layerGroup->setLayerTweaker(std::make_shared<RasterLayerTweaker>(evaluatedProperties));
}
updateLayerTweaker();
#endif
}
@@ -233,9 +232,18 @@ constexpr auto TexturePosAttribName = "a_texture_pos";
constexpr auto Image0UniformName = "u_image0";
constexpr auto Image1UniformName = "u_image1";
void RenderRasterLayer::updateLayerTweaker() {
if (layerGroup) {
tweaker = std::make_shared<RasterLayerTweaker>(getID(), evaluatedProperties);
tweaker->enableOverdrawInspector(overdrawInspector);
layerGroup->setLayerTweaker(tweaker);
}
}
void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& /*state*/,
const std::shared_ptr<UpdateParameters>& updateParameters,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
@@ -254,6 +262,17 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
if (!rasterShader) {
rasterShader = context.getGenericShader(shaders, "RasterShader");
if (!rasterShader) {
return;
}
}
const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw);
if (overdrawInspector != overdraw) {
overdrawInspector = overdraw;
if (tweaker) {
tweaker->enableOverdrawInspector(overdrawInspector);
}
}
if (!staticDataVertices) {
@@ -336,6 +355,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
sizeof(RasterLayoutVertex),
gfx::AttributeDataType::Short2);
}
builder->setVertexAttributes(std::move(vertexAttrs));
}
@@ -371,8 +391,8 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
} else {
// Set up a layer group
imageLayerGroup = context.createLayerGroup(layerIndex, /*initialCapacity=*/64, getID());
imageLayerGroup->setLayerTweaker(std::make_shared<RasterLayerTweaker>(evaluatedProperties));
activateLayerGroup(imageLayerGroup, isRenderable, changes);
updateLayerTweaker();
}
auto builder = createBuilder();
@@ -398,8 +418,8 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
} else {
// Set up a tile layer group
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->setLayerTweaker(std::make_shared<RasterLayerTweaker>(evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
updateLayerTweaker();
}
}

View File

@@ -8,6 +8,11 @@
namespace mbgl {
#if MLN_DRAWABLE_RENDERER
class RasterLayerTweaker;
using RasterLayerTweakerPtr = std::shared_ptr<RasterLayerTweaker>;
#endif // MLN_DRAWABLE_RENDERER
class ImageSourceRenderData;
class RasterProgram;
@@ -21,6 +26,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif
@@ -41,6 +47,10 @@ private:
void render(PaintParameters&) override;
#endif
#if MLN_DRAWABLE_RENDERER
void updateLayerTweaker();
#endif // MLN_DRAWABLE_RENDERER
// Paint properties
style::RasterPaintProperties::Unevaluated unevaluated;
const ImageSourceRenderData* imageData = nullptr;
@@ -65,6 +75,9 @@ private:
using RasterSegmentVector = SegmentVector<RasterAttributes>;
using RasterSegmentVectorPtr = std::shared_ptr<RasterSegmentVector>;
std::shared_ptr<RasterSegmentVector> staticDataSegments;
RasterLayerTweakerPtr tweaker;
bool overdrawInspector = false;
#endif
};

View File

@@ -379,7 +379,7 @@ void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters)
#if MLN_DRAWABLE_RENDERER
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<SymbolLayerTweaker>(evaluatedProperties));
layerGroup->setLayerTweaker(std::make_shared<SymbolLayerTweaker>(getID(), evaluatedProperties));
}
#endif // MLN_DRAWABLE_RENDERER
}
@@ -954,6 +954,7 @@ void RenderSymbolLayer::removeAllDrawables() {
void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
const std::shared_ptr<UpdateParameters>&,
const RenderTree& /*renderTree*/,
UniqueChangeRequestVec& changes) {
if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) {
@@ -964,7 +965,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
// Set up a layer group
if (!layerGroup) {
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->setLayerTweaker(std::make_shared<SymbolLayerTweaker>(evaluatedProperties));
layerGroup_->setLayerTweaker(std::make_shared<SymbolLayerTweaker>(getID(), evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
}
}
@@ -972,7 +973,8 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
if (!collisionTileLayerGroup) {
if ((collisionTileLayerGroup = context.createTileLayerGroup(
layerIndex, /*initialCapacity=*/64, getID() + "-collision"))) {
collisionTileLayerGroup->setLayerTweaker(std::make_shared<CollisionLayerTweaker>(evaluatedProperties));
collisionTileLayerGroup->setLayerTweaker(
std::make_shared<CollisionLayerTweaker>(getID(), evaluatedProperties));
activateLayerGroup(collisionTileLayerGroup, true, changes);
}
}
@@ -1270,6 +1272,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
builder->setVertexAttrName(posOffsetAttribName);
}
if (!shaderGroup) {
return;
}
const auto shader = std::static_pointer_cast<gfx::ShaderProgramBase>(
shaderGroup->getOrCreateShader(context, uniformProps, posOffsetAttribName));
if (!shader) {

View File

@@ -90,6 +90,7 @@ public:
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif // MLN_DRAWABLE_RENDERER

View File

@@ -81,11 +81,6 @@ std::array<float, 2> toArray(const Size& s) {
constexpr auto texUniformName = "u_texture";
constexpr auto texIconUniformName = "u_texture_icon";
template <typename T, class... Is, class... Ts>
auto constOrDefault(const IndexedTuple<TypeList<Is...>, TypeList<Ts...>>& evaluated) {
return evaluated.template get<T>().constantOr(T::defaultValue());
}
SymbolDrawablePaintUBO buildPaintUBO(bool isText, const SymbolPaintProperties::PossiblyEvaluated& evaluated) {
return {
/*.fill_color=*/isText ? constOrDefault<TextColor>(evaluated) : constOrDefault<IconColor>(evaluated),
@@ -169,21 +164,23 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup,
// Unpitched point labels need to have their rotation applied after projection
const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine;
const SymbolDrawableUBO drawableUBO = {/*.matrix=*/util::cast<float>(matrix),
/*.label_plane_matrix=*/util::cast<float>(labelPlaneMatrix),
/*.coord_matrix=*/util::cast<float>(glCoordMatrix),
const SymbolDrawableUBO drawableUBO = {
/*.matrix=*/util::cast<float>(matrix),
/*.label_plane_matrix=*/util::cast<float>(labelPlaneMatrix),
/*.coord_matrix=*/util::cast<float>(glCoordMatrix),
/*.texsize=*/toArray(getTexSize(drawable, texUniformName)),
/*.texsize_icon=*/toArray(getTexSize(drawable, texIconUniformName)),
/*.texsize=*/toArray(getTexSize(drawable, texUniformName)),
/*.texsize_icon=*/toArray(getTexSize(drawable, texIconUniformName)),
/*.gamma_scale=*/gammaScale,
/*.device_pixel_ratio=*/parameters.pixelRatio,
/*.gamma_scale=*/gammaScale,
/*.device_pixel_ratio=*/parameters.pixelRatio,
/*.camera_to_center_distance=*/camDist,
/*.pitch=*/static_cast<float>(state.getPitch()),
/*.rotate_symbol=*/rotateInShader,
/*.aspect_ratio=*/state.getSize().aspectRatio(),
/*.pad=*/{0, 0}};
/*.camera_to_center_distance=*/camDist,
/*.pitch=*/static_cast<float>(state.getPitch()),
/*.rotate_symbol=*/rotateInShader,
/*.aspect_ratio=*/state.getSize().aspectRatio(),
/*.pad=*/{0},
};
const SymbolDynamicUBO dynamicUBO = {/*.fade_change=*/parameters.symbolFadeChange,
/*.pad1=*/0,

View File

@@ -11,8 +11,8 @@ namespace mbgl {
*/
class SymbolLayerTweaker : public LayerTweaker {
public:
SymbolLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
SymbolLayerTweaker(std::string id_, Immutable<style::LayerProperties> properties)
: LayerTweaker(std::move(id_), properties) {}
public:
~SymbolLayerTweaker() override = default;

View File

@@ -36,7 +36,8 @@ PaintParameters::PaintParameters(gfx::Context& context_,
const TransformParameters& transformParams_,
RenderStaticData& staticData_,
LineAtlas& lineAtlas_,
PatternAtlas& patternAtlas_)
PatternAtlas& patternAtlas_,
uint64_t frameCount_)
: context(context_),
backend(backend_),
encoder(context.createCommandEncoder()),
@@ -55,7 +56,8 @@ PaintParameters::PaintParameters(gfx::Context& context_,
#else
programs(staticData_.programs),
#endif
shaders(*staticData_.shaders) {
shaders(*staticData_.shaders),
frameCount(frameCount_) {
pixelsToGLUnits = {{2.0f / state.getSize().width, -2.0f / state.getSize().height}};
if (state.getViewportMode() == ViewportMode::FlippedY) {

View File

@@ -57,7 +57,8 @@ public:
const TransformParameters&,
RenderStaticData&,
LineAtlas&,
PatternAtlas&);
PatternAtlas&,
uint64_t frameCount);
~PaintParameters();
gfx::Context& context;
@@ -103,7 +104,14 @@ public:
/// Clear the stencil buffer, even if there are no tile masks (for 3D)
void clearStencil();
/// @brief Get a stencil mode for rendering constrined to the specified tile ID.
/// The tile ID must have been present in the set previously passed to `renderTileClippingMasks`
gfx::StencilMode stencilModeForClipping(const UnwrappedTileID&) const;
/// @brief Initialize a stencil mode for 3D rendering.
/// @details Clears the tile stencil masks, so `stencilModeForClipping`
/// cannot be used until `renderTileClippingMasks` is called again.
/// @return The stencil mode, each value is unique.
gfx::StencilMode stencilModeFor3D();
private:
@@ -117,13 +125,15 @@ private:
int32_t nextStencilID = 1;
public:
int numSublayers = 3;
const int numSublayers = 3;
uint32_t currentLayer;
float depthRangeSize;
static constexpr float depthEpsilon = 1.0f / (1 << 16);
static constexpr int maxStencilValue = 255;
uint32_t opaquePassCutoff = 0;
float symbolFadeChange;
const uint64_t frameCount;
static constexpr float depthEpsilon = 1.0f / (1 << 16);
static constexpr int maxStencilValue = 255;
};
} // namespace mbgl

View File

@@ -93,7 +93,9 @@ void PatternAtlas::upload([[maybe_unused]] gfx::UploadPass& uploadPass) {
#if MLN_DRAWABLE_RENDERER
if (!atlasTexture2D) {
atlasTexture2D = uploadPass.getContext().createTexture2D();
atlasTexture2D->upload(atlasImage);
if (atlasTexture2D) {
atlasTexture2D->upload(atlasImage);
}
} else if (dirty) {
atlasTexture2D->upload(atlasImage);
}

View File

@@ -30,6 +30,7 @@ class RenderTree;
class SymbolBucket;
class TransformState;
class TransitionParameters;
class UpdateParameters;
class UploadParameters;
#if MLN_DRAWABLE_RENDERER
@@ -164,8 +165,12 @@ public:
#if MLN_DRAWABLE_RENDERER
/// Generate any changes needed by the layer
virtual void update(
gfx::ShaderRegistry&, gfx::Context&, const TransformState&, const RenderTree&, UniqueChangeRequestVec&) {}
virtual void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec&) {}
/// Called when the style layer is replaced (same ID and type), and the render layer is reused.
virtual void layerChanged(const TransitionParameters&,

View File

@@ -823,6 +823,7 @@ bool RenderOrchestrator::addLayerGroup(LayerGroupBasePtr layerGroup, const bool
for (auto it = range.first; it != range.second; ++it) {
if (it->second == layerGroup) {
found = true;
// not added
if (replace) {
onRemoveLayerGroup(*it->second);
it->second = std::move(layerGroup);
@@ -849,6 +850,10 @@ bool RenderOrchestrator::removeLayerGroup(const int32_t layerIndex) {
return removed;
}
size_t RenderOrchestrator::numLayerGroups() const noexcept {
return layerGroupsByLayerIndex.size();
}
int32_t RenderOrchestrator::maxLayerIndex() const {
if (!layerGroupsByLayerIndex.empty()) {
return layerGroupsByLayerIndex.crbegin()->second->getLayerIndex();
@@ -897,7 +902,7 @@ void RenderOrchestrator::updateLayers(gfx::ShaderRegistry& shaders,
std::vector<std::unique_ptr<ChangeRequest>> changes;
for (const auto& item : renderTree.getLayerRenderItems()) {
auto& renderLayer = static_cast<const LayerRenderItem&>(item.get()).layer.get();
renderLayer.update(shaders, context, state, renderTree, changes);
renderLayer.update(shaders, context, state, updateParameters, renderTree, changes);
}
addChanges(changes);
}

View File

@@ -100,6 +100,7 @@ public:
#if MLN_DRAWABLE_RENDERER
bool addLayerGroup(LayerGroupBasePtr, bool replace);
bool removeLayerGroup(const int32_t layerIndex);
size_t numLayerGroups() const noexcept;
int32_t maxLayerIndex() const;
const LayerGroupBasePtr& getLayerGroup(const int32_t layerIndex) const;
void visitLayerGroups(std::function<void(LayerGroupBase&)>);

View File

@@ -19,13 +19,18 @@
#if MLN_DRAWABLE_RENDERER
#include <mbgl/gfx/drawable_tweaker.hpp>
#include <mbgl/gl/drawable_gl.hpp>
#include <mbgl/renderer/layer_tweaker.hpp>
#include <mbgl/renderer/render_target.hpp>
#include <mbgl/shaders/gl/shader_program_gl.hpp>
#include <limits>
#endif
#endif // MLN_DRAWABLE_RENDERER
#if !MLN_RENDER_BACKEND_METAL
#include <mbgl/gl/defines.hpp>
#if MLN_DRAWABLE_RENDERER
#include <mbgl/gl/drawable_gl.hpp>
#endif // MLN_DRAWABLE_RENDERER
#endif // !MLN_RENDER_BACKEND_METAL
namespace mbgl {
@@ -99,7 +104,8 @@ void Renderer::Impl::render(const RenderTree& renderTree,
renderTreeParameters.transformParams,
*staticData,
renderTree.getLineAtlas(),
renderTree.getPatternAtlas()};
renderTree.getPatternAtlas(),
frameCount};
parameters.symbolFadeChange = renderTreeParameters.symbolFadeChange;
parameters.opaquePassCutoff = renderTreeParameters.opaquePassCutOff;
@@ -109,7 +115,11 @@ void Renderer::Impl::render(const RenderTree& renderTree,
// - UPLOAD PASS -------------------------------------------------------------------------------
// Uploads all required buffers and images before we do any actual rendering.
{
const auto uploadPass = parameters.encoder->createUploadPass("upload");
const auto uploadPass = parameters.encoder->createUploadPass("upload",
parameters.backend.getDefaultRenderable());
#if !defined(NDEBUG)
const auto debugGroup = uploadPass->createDebugGroup("upload");
#endif
// Update all clipping IDs + upload buckets.
for (const RenderItem& item : sourceRenderItems) {
@@ -131,15 +141,23 @@ void Renderer::Impl::render(const RenderTree& renderTree,
*staticData->shaders, context, renderTreeParameters.transformParams.state, updateParameters, renderTree);
}
// Process changes
orchestrator.processChanges();
// Run layer tweakers to update any dynamic elements
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) {
if (layerGroup.getLayerTweaker()) {
layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters);
}
});
// Upload layer groups
{
const auto uploadPass = parameters.encoder->createUploadPass("layerGroup-upload",
parameters.backend.getDefaultRenderable());
#if !defined(NDEBUG)
const auto debugGroup = uploadPass->createDebugGroup("layerGroup-upload");
#endif
// Tweakers are run in the upload pass so they can set up uniforms.
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) {
if (layerGroup.getLayerTweaker()) {
layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters);
}
});
}
// Update the debug layer groups
orchestrator.updateDebugLayerGroups(renderTree, parameters);
@@ -150,7 +168,8 @@ void Renderer::Impl::render(const RenderTree& renderTree,
// Upload layer groups
{
const auto uploadPass = parameters.encoder->createUploadPass("layerGroup-upload");
const auto uploadPass = parameters.encoder->createUploadPass("layerGroup-upload",
parameters.backend.getDefaultRenderable());
// Give the layers a chance to upload
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.upload(*uploadPass); });
@@ -367,7 +386,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
renderDebugOverlays();
#else
static_assert(0, "Must define one of (MLN_DRAWABLE_RENDERER, MLN_LEGACY_RENDERER)");
#endif
#endif // MLN_LEGACY_RENDERER
#if MLN_DRAWABLE_RENDERER
// Give the layers a chance to do cleanup
@@ -395,6 +414,8 @@ void Renderer::Impl::render(const RenderTree& renderTree,
renderState = RenderState::Fully;
observer->onDidFinishRenderingMap();
}
frameCount += 1;
}
void Renderer::Impl::reduceMemoryUse() {

View File

@@ -47,6 +47,8 @@ private:
};
RenderState renderState = RenderState::Never;
uint64_t frameCount = 0;
};
} // namespace mbgl

View File

@@ -10,10 +10,11 @@
#include <mbgl/util/math.hpp>
#if MLN_DRAWABLE_RENDERER
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/util/convert.hpp>
@@ -61,6 +62,9 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
auto& shaders = *parameters.staticData.shaders;
constexpr auto DebugShaderName = "DebugShader";
gfx::ShaderProgramBasePtr debugShader = context.getGenericShader(shaders, std::string(DebugShaderName));
if (!debugShader) {
return;
}
// create a builder
constexpr auto VertexAttribName = "a_pos";

View File

@@ -118,14 +118,14 @@ std::shared_ptr<ShaderProgramGL> ShaderProgramGL::create(Context& context,
ShaderType::Vertex,
std::initializer_list<const char*>{
"#version 300 es\n",
programParameters.getDefines().c_str(),
programParameters.getDefinesString().c_str(),
additionalDefines.c_str(),
shaders::ShaderSource<shaders::BuiltIn::Prelude, gfx::Backend::Type::OpenGL>::vertex,
vertexSource.c_str()});
auto fragProg = context.createShader(
ShaderType::Fragment,
{"#version 300 es\n",
programParameters.getDefines().c_str(),
programParameters.getDefinesString().c_str(),
additionalDefines.c_str(),
shaders::ShaderSource<shaders::BuiltIn::Prelude, gfx::Backend::Type::OpenGL>::fragment,
fragmentSource.c_str()});

View File

@@ -0,0 +1,192 @@
#include <mbgl/shaders/mtl/shader_program.hpp>
#include <mbgl/gfx/render_pass.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/renderer_backend.hpp>
#include <mbgl/mtl/renderable_resource.hpp>
#include <mbgl/mtl/uniform_block.hpp>
#include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/vertex_attribute.hpp>
#include <mbgl/programs/program_parameters.hpp>
#include <mbgl/shaders/shader_manifest.hpp>
#include <mbgl/util/logging.hpp>
#include <Metal/MTLRenderPass.hpp>
#include <Metal/MTLRenderPipeline.hpp>
#include <cstring>
#include <utility>
using namespace std::string_literals;
namespace mbgl {
namespace mtl {
namespace {
MTL::BlendOperation metalBlendOperation(const gfx::ColorBlendEquationType& colorBlend) {
switch (colorBlend) {
case gfx::ColorBlendEquationType::Add:
return MTL::BlendOperationAdd;
case gfx::ColorBlendEquationType::Subtract:
return MTL::BlendOperationSubtract;
case gfx::ColorBlendEquationType::ReverseSubtract:
return MTL::BlendOperationReverseSubtract;
}
}
MTL::BlendFactor metalBlendFactor(const gfx::ColorBlendFactorType& colorFactor) {
switch (colorFactor) {
case gfx::ColorBlendFactorType::Zero:
return MTL::BlendFactorZero;
case gfx::ColorBlendFactorType::One:
return MTL::BlendFactorOne;
case gfx::ColorBlendFactorType::SrcColor:
return MTL::BlendFactorSourceColor;
case gfx::ColorBlendFactorType::OneMinusSrcColor:
return MTL::BlendFactorOneMinusSourceColor;
case gfx::ColorBlendFactorType::SrcAlpha:
return MTL::BlendFactorSourceAlpha;
case gfx::ColorBlendFactorType::OneMinusSrcAlpha:
return MTL::BlendFactorOneMinusSourceAlpha;
case gfx::ColorBlendFactorType::DstAlpha:
return MTL::BlendFactorDestinationAlpha;
case gfx::ColorBlendFactorType::OneMinusDstAlpha:
return MTL::BlendFactorOneMinusDestinationAlpha;
case gfx::ColorBlendFactorType::DstColor:
return MTL::BlendFactorDestinationColor;
case gfx::ColorBlendFactorType::OneMinusDstColor:
return MTL::BlendFactorOneMinusDestinationColor;
case gfx::ColorBlendFactorType::SrcAlphaSaturate:
return MTL::BlendFactorSourceAlphaSaturated;
case gfx::ColorBlendFactorType::ConstantColor:
return MTL::BlendFactorBlendColor;
case gfx::ColorBlendFactorType::OneMinusConstantColor:
return MTL::BlendFactorOneMinusBlendColor;
case gfx::ColorBlendFactorType::ConstantAlpha:
return MTL::BlendFactorBlendAlpha;
case gfx::ColorBlendFactorType::OneMinusConstantAlpha:
return MTL::BlendFactorOneMinusBlendAlpha;
}
}
} // namespace
ShaderProgram::ShaderProgram(std::string name, RendererBackend& backend_, MTLFunctionPtr vert, MTLFunctionPtr frag)
: ShaderProgramBase(),
shaderName(std::move(name)),
backend(backend_),
vertexFunction(std::move(vert)),
fragmentFunction(std::move(frag)) {}
MTLRenderPipelineStatePtr ShaderProgram::getRenderPipelineState(const gfx::RenderPassDescriptor& renderPassDescriptor,
const MTLVertexDescriptorPtr& vertexDescriptor,
const gfx::ColorMode& colorMode) const {
auto pool = NS::TransferPtr(NS::AutoreleasePool::alloc()->init());
const auto& renderable = renderPassDescriptor.renderable;
const auto& renderableResource = renderable.getResource<RenderableResource>();
auto colorFormat = MTL::PixelFormat::PixelFormatBGRA8Unorm;
std::optional<MTL::PixelFormat> depthFormat = std::nullopt;
std::optional<MTL::PixelFormat> stencilFormat = std::nullopt;
if (const auto& rpd = renderableResource.getRenderPassDescriptor()) {
if (auto* colorTarget = rpd->colorAttachments()->object(0)) {
if (auto* tex = colorTarget->texture()) {
colorFormat = tex->pixelFormat();
}
}
if (auto* depthTarget = rpd->depthAttachment()) {
if (auto* tex = depthTarget->texture()) {
depthFormat = tex->pixelFormat();
}
}
if (auto* stencilTarget = rpd->stencilAttachment()) {
if (auto* tex = stencilTarget->texture()) {
stencilFormat = tex->pixelFormat();
}
}
}
auto desc = NS::TransferPtr(MTL::RenderPipelineDescriptor::alloc()->init());
desc->setLabel(NS::String::string(shaderName.data(), NS::UTF8StringEncoding));
desc->setVertexFunction(vertexFunction.get());
desc->setFragmentFunction(fragmentFunction.get());
desc->setVertexDescriptor(vertexDescriptor.get());
if (auto* colorTarget = desc->colorAttachments()->object(0)) {
const auto blendEnabled = !colorMode.blendFunction.is<gfx::ColorMode::Replace>();
auto blendOperation = MTL::BlendOperationAdd;
auto srcFactor = MTL::BlendFactorOne;
auto destFactor = MTL::BlendFactorOne;
if (blendEnabled) {
apply_visitor(
[&](const auto& blendFunction) {
blendOperation = metalBlendOperation(gfx::ColorBlendEquationType(blendFunction.equation));
srcFactor = metalBlendFactor(blendFunction.srcFactor);
destFactor = metalBlendFactor(blendFunction.dstFactor);
},
colorMode.blendFunction);
}
colorTarget->setPixelFormat(colorFormat);
colorTarget->setBlendingEnabled(blendEnabled);
colorTarget->setRgbBlendOperation(blendOperation);
colorTarget->setAlphaBlendOperation(blendOperation);
colorTarget->setSourceRGBBlendFactor(srcFactor);
colorTarget->setSourceAlphaBlendFactor(srcFactor);
colorTarget->setDestinationRGBBlendFactor(destFactor);
colorTarget->setDestinationAlphaBlendFactor(destFactor);
}
if (depthFormat) {
desc->setDepthAttachmentPixelFormat(*depthFormat);
}
if (stencilFormat) {
desc->setStencilAttachmentPixelFormat(*stencilFormat);
}
NS::Error* error = nullptr;
const auto& device = backend.getDevice();
auto rps = NS::TransferPtr(device->newRenderPipelineState(desc.get(), &error));
if (!rps || error) {
const auto errPtr = error ? error->localizedDescription()->utf8String() : nullptr;
const auto errStr = (errPtr && errPtr[0]) ? ": "s + errPtr : std::string();
Log::Error(Event::Shader, shaderName + " newRenderPipelineState failed" + errStr);
assert(false);
}
return rps;
}
std::optional<uint32_t> ShaderProgram::getSamplerLocation(std::string_view name) const {
std::size_t index = 0;
for (const auto& bindingName : textureBindings) {
if (bindingName == name) {
return index;
}
index += 1;
}
return std::nullopt;
}
void ShaderProgram::initAttribute(const shaders::AttributeInfo& info) {
vertexAttributes.add(std::string(info.name), static_cast<int>(info.index), info.dataType, info.count);
}
void ShaderProgram::initUniformBlock(const shaders::UniformBlockInfo& info) {
if (const auto& block_ = uniformBlocks.add(info.name.data(), static_cast<int>(info.index), info.size)) {
auto& block = static_cast<UniformBlock&>(*block_);
block.setBindVertex(info.vertex);
block.setBindFragment(info.fragment);
}
}
void ShaderProgram::initTexture(const shaders::TextureInfo& info) {
textureBindings.resize(std::max(textureBindings.size(), info.index + 1));
textureBindings[info.index] = info.name;
}
} // namespace mtl
} // namespace mbgl

View File

@@ -1,11 +0,0 @@
#include <mbgl/shaders/mtl/shader_program_mtl.hpp>
namespace mbgl {
namespace mtl {
// bool ShaderProgramMTL::compile(std::string_view vert, std::string_view frag) {
// return false;
// }
} // namespace mtl
} // namespace mbgl

View File

@@ -304,5 +304,10 @@ public:
template <class... Ps>
using ConcatenateProperties = typename TypeListConcat<typename Ps::PropertyTypes...>::template ExpandInto<Properties>;
template <typename T, class... Is, class... Ts>
auto constOrDefault(const IndexedTuple<TypeList<Is...>, TypeList<Ts...>>& evaluated) {
return evaluated.template get<T>().constantOr(T::defaultValue());
}
} // namespace style
} // namespace mbgl