Rebase fill-extrusion work to eliminate dependence on render target branch (#1618)
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:
@@ -1,12 +1,29 @@
|
||||
#include <mbgl/renderer/paint_parameters.hpp>
|
||||
#include <mbgl/renderer/update_parameters.hpp>
|
||||
|
||||
#include <mbgl/gfx/command_encoder.hpp>
|
||||
#include <mbgl/gfx/cull_face_mode.hpp>
|
||||
#include <mbgl/gfx/render_pass.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/renderer/render_static_data.hpp>
|
||||
#include <mbgl/renderer/render_source.hpp>
|
||||
#include <mbgl/renderer/render_tile.hpp>
|
||||
#include <mbgl/gfx/command_encoder.hpp>
|
||||
#include <mbgl/gfx/render_pass.hpp>
|
||||
#include <mbgl/gfx/cull_face_mode.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/renderer/update_parameters.hpp>
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
#include <mbgl/mtl/context.hpp>
|
||||
#include <mbgl/mtl/render_pass.hpp>
|
||||
#include <mbgl/mtl/renderer_backend.hpp>
|
||||
#include <mbgl/shaders/layer_ubo.hpp>
|
||||
#include <mbgl/shaders/mtl/clipping_mask.hpp>
|
||||
#include <mbgl/shaders/mtl/shader_program.hpp>
|
||||
#include <mbgl/shaders/shader_program_base.hpp>
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
#include <mbgl/util/convert.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
#include <Foundation/Foundation.hpp>
|
||||
#include <Metal/Metal.hpp>
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -88,8 +105,18 @@ gfx::DepthMode PaintParameters::depthModeFor3D() const {
|
||||
|
||||
void PaintParameters::clearStencil() {
|
||||
nextStencilID = 1;
|
||||
context.clearStencilBuffer(0b00000000);
|
||||
tileClippingMaskIDs.clear();
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
// Metal doesn't have an equivalent of `glClear`, so we clear the buffer by drawing zero to (0:0,0)
|
||||
std::set<UnwrappedTileID> ids{{0, 0, 0}};
|
||||
auto f = [](const auto& ii) -> const UnwrappedTileID& {
|
||||
return ii;
|
||||
};
|
||||
renderTileClippingMasks(ids.cbegin(), ids.cend(), std::move(f), /*clear=*/true);
|
||||
#else
|
||||
context.clearStencilBuffer(0b00000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -111,14 +138,17 @@ bool tileIDsIdentical(TIter beg, TIter end, GetTileIDFunc<TIter>& f, const TileM
|
||||
} // namespace
|
||||
|
||||
void PaintParameters::renderTileClippingMasks(const std::set<UnwrappedTileID>& tileIDs) {
|
||||
renderTileClippingMasks(
|
||||
tileIDs.cbegin(), tileIDs.cend(), [](const auto& ii) -> const UnwrappedTileID& { return ii; });
|
||||
auto f = [](const auto& ii) -> const UnwrappedTileID& {
|
||||
return ii;
|
||||
};
|
||||
renderTileClippingMasks(tileIDs.cbegin(), tileIDs.cend(), std::move(f), /*clear=*/false);
|
||||
}
|
||||
|
||||
void PaintParameters::renderTileClippingMasks(const RenderTiles& renderTiles) {
|
||||
renderTileClippingMasks((*renderTiles).cbegin(),
|
||||
(*renderTiles).cend(),
|
||||
[](const auto& ii) -> const UnwrappedTileID& { return ii.get().id; });
|
||||
auto f = [](const auto& ii) -> const UnwrappedTileID& {
|
||||
return ii.get().id;
|
||||
};
|
||||
renderTileClippingMasks((*renderTiles).cbegin(), (*renderTiles).cend(), std::move(f), /*clear=*/false);
|
||||
}
|
||||
|
||||
void PaintParameters::clearTileClippingMasks() {
|
||||
@@ -128,18 +158,162 @@ void PaintParameters::clearTileClippingMasks() {
|
||||
}
|
||||
|
||||
template <typename TIter>
|
||||
void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter>&& f) {
|
||||
void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter>&& f, bool clear) {
|
||||
if (tileIDsIdentical(beg, end, f, tileClippingMaskIDs)) {
|
||||
// The current stencil mask is for this source already; no need to draw another one.
|
||||
return;
|
||||
}
|
||||
|
||||
const auto count = std::distance(beg, end);
|
||||
if (nextStencilID + count > maxStencilValue) {
|
||||
if (!clear && nextStencilID + count > maxStencilValue) {
|
||||
// we'll run out of fresh IDs so we need to clear and start from scratch
|
||||
clearStencil();
|
||||
}
|
||||
|
||||
if (!renderPass) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
const auto debugGroup = renderPass->createDebugGroup("tile-clip-masks");
|
||||
#endif
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
using ShaderClass = shaders::ShaderSource<shaders::BuiltIn::ClippingMaskProgram, gfx::Backend::Type::Metal>;
|
||||
const auto group = staticData.shaders->getShaderGroup("ClippingMaskProgram");
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
const auto shader = std::static_pointer_cast<gfx::ShaderProgramBase>(group->getOrCreateShader(context, {}));
|
||||
if (!shader) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& mtlContext = static_cast<mtl::Context&>(context);
|
||||
const auto& mtlShader = static_cast<const mtl::ShaderProgram&>(*shader);
|
||||
const auto& mtlRenderPass = static_cast<mtl::RenderPass&>(*renderPass);
|
||||
const auto& encoder = mtlRenderPass.getMetalEncoder();
|
||||
const auto colorMode = gfx::ColorMode::disabled();
|
||||
|
||||
constexpr std::size_t indexCount = 6;
|
||||
std::optional<mtl::BufferResource> indexRes;
|
||||
|
||||
// TODO: refactor to use `Context::makeDepthStencilState`
|
||||
const auto init = [&]() {
|
||||
// TODO: a lot of this can be cached
|
||||
// Create a vertex buffer from the fixed tile coordinates
|
||||
const auto vertices = RenderStaticData::tileVertices();
|
||||
constexpr auto vertexSize = sizeof(decltype(vertices)::Vertex::a1);
|
||||
auto vertexRes = mtlContext.createBuffer(vertices.data(), vertices.bytes(), gfx::BufferUsageType::StaticDraw);
|
||||
if (!vertexRes) {
|
||||
return;
|
||||
}
|
||||
encoder->setVertexBuffer(vertexRes.getMetalBuffer().get(), /*offset=*/0, ShaderClass::attributes[0].index);
|
||||
|
||||
// A vertex descriptor tells Metal what's in the vertex buffer
|
||||
auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor());
|
||||
auto attribDesc = NS::TransferPtr(MTL::VertexAttributeDescriptor::alloc()->init());
|
||||
auto layoutDesc = NS::TransferPtr(MTL::VertexBufferLayoutDescriptor::alloc()->init());
|
||||
if (!vertDesc || !attribDesc || !layoutDesc) {
|
||||
return;
|
||||
}
|
||||
attribDesc->setBufferIndex(ShaderClass::attributes[0].index);
|
||||
attribDesc->setOffset(0);
|
||||
attribDesc->setFormat(MTL::VertexFormatShort2);
|
||||
layoutDesc->setStride(static_cast<NS::UInteger>(vertexSize));
|
||||
layoutDesc->setStepFunction(MTL::VertexStepFunctionPerVertex);
|
||||
layoutDesc->setStepRate(1);
|
||||
vertDesc->attributes()->setObject(attribDesc.get(), 0);
|
||||
vertDesc->layouts()->setObject(layoutDesc.get(), 0);
|
||||
|
||||
// Create a buffer from the fixed tile indexes
|
||||
const auto indexes = RenderStaticData::quadTriangleIndices();
|
||||
assert(indexes.elements() == indexCount);
|
||||
indexRes.emplace(mtlContext.createBuffer(indexes.data(), indexes.bytes(), gfx::BufferUsageType::StaticDraw));
|
||||
if (!indexRes || !*indexRes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// gfx::CullFaceMode::disabled();
|
||||
encoder->setCullMode(MTL::CullModeNone);
|
||||
|
||||
auto stencilDescriptor = NS::TransferPtr(MTL::StencilDescriptor::alloc()->init());
|
||||
if (!stencilDescriptor) {
|
||||
return;
|
||||
}
|
||||
stencilDescriptor->setStencilCompareFunction(MTL::CompareFunction::CompareFunctionAlways);
|
||||
stencilDescriptor->setStencilFailureOperation(MTL::StencilOperation::StencilOperationKeep);
|
||||
stencilDescriptor->setDepthFailureOperation(MTL::StencilOperation::StencilOperationKeep);
|
||||
stencilDescriptor->setDepthStencilPassOperation(MTL::StencilOperation::StencilOperationReplace);
|
||||
stencilDescriptor->setReadMask(0);
|
||||
stencilDescriptor->setWriteMask(0b11111111);
|
||||
|
||||
auto depthStencilDescriptor = NS::TransferPtr(MTL::DepthStencilDescriptor::alloc()->init());
|
||||
if (!depthStencilDescriptor) {
|
||||
return;
|
||||
}
|
||||
depthStencilDescriptor->setDepthCompareFunction(MTL::CompareFunction::CompareFunctionAlways);
|
||||
depthStencilDescriptor->setDepthWriteEnabled(false);
|
||||
depthStencilDescriptor->setFrontFaceStencil(stencilDescriptor.get());
|
||||
depthStencilDescriptor->setBackFaceStencil(stencilDescriptor.get());
|
||||
|
||||
auto& device = mtlContext.getBackend().getDevice();
|
||||
auto depthStencilState = NS::TransferPtr(device->newDepthStencilState(depthStencilDescriptor.get()));
|
||||
if (!depthStencilState) {
|
||||
return;
|
||||
}
|
||||
encoder->setDepthStencilState(depthStencilState.get());
|
||||
|
||||
// Create a render pipeline state, telling Metal how to render the primitives
|
||||
const auto& renderPassDescriptor = mtlRenderPass.getDescriptor();
|
||||
if (auto state = mtlShader.getRenderPipelineState(renderPassDescriptor, vertDesc, colorMode)) {
|
||||
encoder->setRenderPipelineState(state.get());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// For each tile in the set...
|
||||
for (auto i = beg; i != end; ++i) {
|
||||
const auto& tileID = f(*i);
|
||||
|
||||
const int32_t stencilID = clear ? 0 : nextStencilID;
|
||||
if (!clear) {
|
||||
const auto result = tileClippingMaskIDs.insert(std::make_pair(tileID, stencilID));
|
||||
if (result.second) {
|
||||
// inserted
|
||||
nextStencilID++;
|
||||
} else {
|
||||
// already present
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!indexRes) {
|
||||
init();
|
||||
}
|
||||
|
||||
encoder->setStencilReferenceValue(stencilID);
|
||||
|
||||
const auto ubo = shaders::ClipUBO{/* .matrix = */ util::cast<float>(matrixForTile(tileID))};
|
||||
// Create a buffer for the per-tile UBO data
|
||||
if (auto uboRes = mtlContext.createBuffer(&ubo, sizeof(ubo), gfx::BufferUsageType::StaticDraw)) {
|
||||
encoder->setVertexBuffer(uboRes.getMetalBuffer().get(), /*offset=*/0, ShaderClass::uniforms[0].index);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
encoder->drawIndexedPrimitives(MTL::PrimitiveType::PrimitiveTypeTriangle,
|
||||
static_cast<NS::UInteger>(indexCount),
|
||||
MTL::IndexType::IndexTypeUInt16,
|
||||
indexRes->getMetalBuffer().get(),
|
||||
/*indexOffset=*/0,
|
||||
/*instanceCount=*/1,
|
||||
/*baseVertex=*/0,
|
||||
/*baseInstance=*/0);
|
||||
}
|
||||
#else // !MLN_RENDER_BACKEND_METAL
|
||||
auto program = staticData.shaders->getLegacyGroup().get<ClippingMaskProgram>();
|
||||
|
||||
if (!program) {
|
||||
@@ -188,6 +362,7 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun
|
||||
ClippingMaskProgram::TextureBindings{},
|
||||
"clipping/" + util::toString(stencilID));
|
||||
}
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
}
|
||||
|
||||
gfx::StencilMode PaintParameters::stencilModeForClipping(const UnwrappedTileID& tileID) const {
|
||||
|
||||
Reference in New Issue
Block a user