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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <mbgl/util/ignore.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gfx {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -17,6 +17,7 @@ DrawableGL::DrawableGL(std::string name_)
|
||||
impl(std::make_unique<Impl>()) {}
|
||||
|
||||
DrawableGL::~DrawableGL() {
|
||||
impl->indexBuffer = {0, nullptr};
|
||||
impl->attributeBuffers.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
|
||||
VertexAttributeArrayGL vertexAttributes;
|
||||
|
||||
gfx::IndexBuffer indexBuffer = {0, nullptr};
|
||||
std::vector<gfx::UniqueVertexBufferResource> attributeBuffers;
|
||||
|
||||
UniformBufferArrayGL uniformBuffers;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
44
src/mbgl/mtl/buffer_resource.cpp
Normal file
44
src/mbgl/mtl/buffer_resource.cpp
Normal 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
|
||||
92
src/mbgl/mtl/command_encoder.cpp
Normal file
92
src/mbgl/mtl/command_encoder.cpp
Normal 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
210
src/mbgl/mtl/context.cpp
Normal 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
517
src/mbgl/mtl/drawable.cpp
Normal 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
|
||||
49
src/mbgl/mtl/drawable_builder.cpp
Normal file
49
src/mbgl/mtl/drawable_builder.cpp
Normal 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
|
||||
68
src/mbgl/mtl/drawable_impl.hpp
Normal file
68
src/mbgl/mtl/drawable_impl.hpp
Normal 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
|
||||
60
src/mbgl/mtl/layer_group.cpp
Normal file
60
src/mbgl/mtl/layer_group.cpp
Normal 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
9
src/mbgl/mtl/mtl.cpp
Normal 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>
|
||||
94
src/mbgl/mtl/render_pass.cpp
Normal file
94
src/mbgl/mtl/render_pass.cpp
Normal 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
|
||||
138
src/mbgl/mtl/renderer_backend.cpp
Normal file
138
src/mbgl/mtl/renderer_backend.cpp
Normal 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
201
src/mbgl/mtl/texture2d.cpp
Normal 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
|
||||
113
src/mbgl/mtl/tile_layer_group.cpp
Normal file
113
src/mbgl/mtl/tile_layer_group.cpp
Normal 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
|
||||
17
src/mbgl/mtl/uniform_block.cpp
Normal file
17
src/mbgl/mtl/uniform_block.cpp
Normal 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
|
||||
30
src/mbgl/mtl/uniform_buffer.cpp
Normal file
30
src/mbgl/mtl/uniform_buffer.cpp
Normal 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
|
||||
268
src/mbgl/mtl/upload_pass.cpp
Normal file
268
src/mbgl/mtl/upload_pass.cpp
Normal 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
|
||||
100
src/mbgl/mtl/vertex_attribute.cpp
Normal file
100
src/mbgl/mtl/vertex_attribute.cpp
Normal 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(¶msUBO, 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(¶msUBO, 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(¶msUBO, 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(¶msUBO, 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(¶msUBO, 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
void update(gfx::ShaderRegistry&,
|
||||
gfx::Context&,
|
||||
const TransformState&,
|
||||
const std::shared_ptr<UpdateParameters>&,
|
||||
const RenderTree&,
|
||||
UniqueChangeRequestVec&) override;
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
void update(gfx::ShaderRegistry&,
|
||||
gfx::Context&,
|
||||
const TransformState&,
|
||||
const std::shared_ptr<UpdateParameters>&,
|
||||
const RenderTree&,
|
||||
UniqueChangeRequestVec&) override;
|
||||
#endif
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
void update(gfx::ShaderRegistry&,
|
||||
gfx::Context&,
|
||||
const TransformState&,
|
||||
const std::shared_ptr<UpdateParameters>&,
|
||||
const RenderTree&,
|
||||
UniqueChangeRequestVec&) override;
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
void update(gfx::ShaderRegistry&,
|
||||
gfx::Context&,
|
||||
const TransformState&,
|
||||
const std::shared_ptr<UpdateParameters>&,
|
||||
const RenderTree&,
|
||||
UniqueChangeRequestVec&) override;
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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&,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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&)>);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -47,6 +47,8 @@ private:
|
||||
};
|
||||
|
||||
RenderState renderState = RenderState::Never;
|
||||
|
||||
uint64_t frameCount = 0;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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()});
|
||||
|
||||
192
src/mbgl/shaders/mtl/shader_program.cpp
Normal file
192
src/mbgl/shaders/mtl/shader_program.cpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user