Fix a bug with buffer reuse. Simplify stencil clearing. (#1763)
Co-authored-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
@@ -60,7 +60,7 @@ public:
|
||||
MTLSamplerStatePtr createMetalSamplerState(MTLSamplerDescriptorPtr samplerDescriptor) const;
|
||||
|
||||
// Actually remove the objects we marked as abandoned with the above methods.
|
||||
void performCleanup() override {}
|
||||
void performCleanup() override;
|
||||
|
||||
void reduceMemoryUsage() override {}
|
||||
|
||||
@@ -134,6 +134,7 @@ private:
|
||||
MTLDepthStencilStatePtr clipMaskDepthStencilState;
|
||||
MTLRenderPipelineStatePtr clipMaskPipelineState;
|
||||
BufferResource clipMaskUniformsBuffer;
|
||||
bool clipMaskUniformsBufferUsed = false;
|
||||
const gfx::Renderable* stencilStateRenderable = nullptr;
|
||||
|
||||
gfx::RenderingStats stats;
|
||||
|
||||
@@ -144,6 +144,10 @@ MTLSamplerStatePtr Context::createMetalSamplerState(MTLSamplerDescriptorPtr samp
|
||||
return NS::TransferPtr(backend.getDevice()->newSamplerState(samplerDescriptor.get()));
|
||||
}
|
||||
|
||||
void Context::performCleanup() {
|
||||
clipMaskUniformsBufferUsed = false;
|
||||
}
|
||||
|
||||
gfx::UniqueDrawableBuilder Context::createDrawableBuilder(std::string name) {
|
||||
return std::make_unique<DrawableBuilder>(std::move(name));
|
||||
}
|
||||
@@ -311,19 +315,22 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass,
|
||||
// Create a buffer for the UBO data.
|
||||
constexpr auto uboSize = sizeof(shaders::ClipUBO);
|
||||
const auto bufferSize = tileUBOs.size() * uboSize;
|
||||
if (!clipMaskUniformsBuffer || clipMaskUniformsBuffer.getSizeInBytes() < bufferSize) {
|
||||
clipMaskUniformsBuffer = createBuffer(tileUBOs.data(), bufferSize, gfx::BufferUsageType::StaticDraw);
|
||||
if (!clipMaskUniformsBuffer) {
|
||||
|
||||
BufferResource tempBuffer;
|
||||
auto& uboBuffer = clipMaskUniformsBufferUsed ? tempBuffer : clipMaskUniformsBuffer;
|
||||
clipMaskUniformsBufferUsed = true;
|
||||
if (!uboBuffer || uboBuffer.getSizeInBytes() < bufferSize) {
|
||||
uboBuffer = createBuffer(tileUBOs.data(), bufferSize, gfx::BufferUsageType::StaticDraw);
|
||||
if (!uboBuffer) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
clipMaskUniformsBuffer.update(tileUBOs.data(), bufferSize, /*offset=*/0);
|
||||
uboBuffer.update(tileUBOs.data(), bufferSize, /*offset=*/0);
|
||||
}
|
||||
|
||||
encoder->setCullMode(MTL::CullModeNone);
|
||||
encoder->setVertexBuffer(vertexRes.getMetalBuffer().get(), /*offset=*/0, ShaderClass::attributes[0].index);
|
||||
encoder->setVertexBuffer(
|
||||
clipMaskUniformsBuffer.getMetalBuffer().get(), /*offset=*/0, ShaderClass::uniforms[0].index);
|
||||
encoder->setVertexBuffer(uboBuffer.getMetalBuffer().get(), /*offset=*/0, ShaderClass::uniforms[0].index);
|
||||
encoder->drawIndexedPrimitives(MTL::PrimitiveType::PrimitiveTypeTriangle,
|
||||
indexCount,
|
||||
MTL::IndexType::IndexTypeUInt16,
|
||||
|
||||
@@ -144,21 +144,32 @@ void PaintParameters::clearStencil() {
|
||||
tileClippingMaskIDs.clear();
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
auto& mtlContext = static_cast<mtl::Context&>(context);
|
||||
|
||||
// Metal doesn't have an equivalent of `glClear`, so we clear the buffer by drawing zero to (0:0,0)
|
||||
static const std::set<UnwrappedTileID> ids{{0, 0, 0}};
|
||||
renderTileClippingMasks(ids.cbegin(), ids.cend(), &unwrapIdentity, /*clear=*/true);
|
||||
#else
|
||||
#if !defined(NDEBUG)
|
||||
const auto debugGroup = renderPass->createDebugGroup("tile-clip-mask-clear");
|
||||
#endif
|
||||
|
||||
const std::vector<shaders::ClipUBO> tileUBO = {
|
||||
shaders::ClipUBO{/*.matrix=*/util::cast<float>(matrixForTile({0, 0, 0})),
|
||||
/*.stencil_ref=*/0,
|
||||
/*.pad=*/0,
|
||||
0,
|
||||
0}};
|
||||
mtlContext.renderTileClippingMasks(*renderPass, staticData, tileUBO);
|
||||
#else // !MLN_RENDER_BACKEND_METAL
|
||||
context.clearStencilBuffer(0b00000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MLN_LEGACY_RENDERER
|
||||
void PaintParameters::renderTileClippingMasks(const RenderTiles& renderTiles) {
|
||||
renderTileClippingMasks((*renderTiles).cbegin(), (*renderTiles).cend(), &unwrapRenderTiles, /*clear=*/false);
|
||||
renderTileClippingMasks((*renderTiles).cbegin(), (*renderTiles).cend(), &unwrapRenderTiles);
|
||||
}
|
||||
#else // !MLN_LEGACY_RENDERER
|
||||
void PaintParameters::renderTileClippingMasks(const std::set<UnwrappedTileID>& tileIDs) {
|
||||
renderTileClippingMasks(tileIDs.cbegin(), tileIDs.cend(), &unwrapIdentity, /*clear=*/false);
|
||||
renderTileClippingMasks(tileIDs.cbegin(), tileIDs.cend(), &unwrapIdentity);
|
||||
}
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
|
||||
@@ -169,23 +180,21 @@ void PaintParameters::clearTileClippingMasks() {
|
||||
}
|
||||
|
||||
template <typename TIter>
|
||||
void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter> unwrap, bool clear) {
|
||||
void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter> unwrap) {
|
||||
if (!renderPass) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clear) {
|
||||
if (tileIDsCovered(beg, end, unwrap, tileClippingMaskIDs)) {
|
||||
// The current stencil mask is for this source already; no need to draw another one.
|
||||
return;
|
||||
}
|
||||
if (tileIDsCovered(beg, end, unwrap, 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) {
|
||||
// we'll run out of fresh IDs so we need to clear and start from scratch
|
||||
clearStencil();
|
||||
}
|
||||
const auto count = std::distance(beg, end);
|
||||
if (nextStencilID + count > maxStencilValue) {
|
||||
// we'll run out of fresh IDs so we need to clear and start from scratch
|
||||
clearStencil();
|
||||
}
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
@@ -194,16 +203,14 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun
|
||||
for (auto i = beg; i != end; ++i) {
|
||||
const auto& tileID = unwrap(*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;
|
||||
}
|
||||
const int32_t stencilID = nextStencilID;
|
||||
const auto result = tileClippingMaskIDs.insert(std::make_pair(tileID, stencilID));
|
||||
if (result.second) {
|
||||
// inserted
|
||||
nextStencilID++;
|
||||
} else {
|
||||
// already present
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tileUBOs.empty()) {
|
||||
|
||||
@@ -121,7 +121,7 @@ private:
|
||||
template <typename TIter>
|
||||
using GetTileIDFunc = const UnwrappedTileID& (*)(const typename TIter::value_type&);
|
||||
template <typename TIter>
|
||||
void renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter> unwrap, bool clear);
|
||||
void renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter> unwrap);
|
||||
|
||||
// This needs to be an ordered map so that we have the same order as the renderTiles.
|
||||
std::map<UnwrappedTileID, int32_t> tileClippingMaskIDs;
|
||||
|
||||
Reference in New Issue
Block a user