From 302c07048ca854cd2ec75db9704ed478e26de7b3 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 15 Jul 2021 16:56:19 -0700 Subject: [PATCH] Switch Metal driver to use HandleAllocator (#4326) --- CMakeLists.txt | 4 + filament/CMakeLists.txt | 1 + .../include/private/backend/HandleAllocator.h | 5 +- filament/backend/src/HandleAllocator.cpp | 4 + filament/backend/src/metal/MetalDriver.h | 89 +++------- filament/backend/src/metal/MetalDriver.mm | 163 +++++++++--------- filament/backend/src/metal/MetalHandles.h | 6 +- 7 files changed, 124 insertions(+), 148 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b64080b24..5ac68d7ac5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,10 @@ set(FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB "4" CACHE STRING "Size of the OpenGL handle arena, default 4." ) +set(FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB "8" CACHE STRING + "Size of the Metal handle arena, default 8." +) + # ================================================================================================== # CMake policies # ================================================================================================== diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index ab97946c93..ab17f01921 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -224,6 +224,7 @@ add_definitions( -DFILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB=${FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB} -DFILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB=${FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB} -DFILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB=${FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB} + -DFILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB=${FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB} ) # ================================================================================================== diff --git a/filament/backend/include/private/backend/HandleAllocator.h b/filament/backend/include/private/backend/HandleAllocator.h index d34767d01a..9624bda8d1 100644 --- a/filament/backend/include/private/backend/HandleAllocator.h +++ b/filament/backend/include/private/backend/HandleAllocator.h @@ -31,8 +31,9 @@ # define HANDLE_TYPE_SAFETY 0 #endif -#define HandleAllocatorGL HandleAllocator<16, 64, 208> -#define HandleAllocatorVK HandleAllocator<16, 64, 880> +#define HandleAllocatorGL HandleAllocator<16, 64, 208> +#define HandleAllocatorVK HandleAllocator<16, 64, 880> +#define HandleAllocatorMTL HandleAllocator<16, 64, 576> namespace filament::backend { diff --git a/filament/backend/src/HandleAllocator.cpp b/filament/backend/src/HandleAllocator.cpp index 0f6eb928a3..3257e4e2c9 100644 --- a/filament/backend/src/HandleAllocator.cpp +++ b/filament/backend/src/HandleAllocator.cpp @@ -110,4 +110,8 @@ template class HandleAllocatorGL; template class HandleAllocatorVK; #endif +#if defined (FILAMENT_SUPPORTS_METAL) +template class HandleAllocatorMTL; +#endif + } // namespace filament::backend diff --git a/filament/backend/src/metal/MetalDriver.h b/filament/backend/src/metal/MetalDriver.h index 78b955b44e..2fb051edf0 100644 --- a/filament/backend/src/metal/MetalDriver.h +++ b/filament/backend/src/metal/MetalDriver.h @@ -20,14 +20,12 @@ #include "private/backend/Driver.h" #include "DriverBase.h" +#include "private/backend/HandleAllocator.h" + #include #include #include -#include - -#include - namespace filament { namespace backend { @@ -41,6 +39,10 @@ struct MetalContext; struct MetalProgram; struct UniformBufferState; +#ifndef FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB +#define FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB 8 +#endif + class MetalDriver final : public DriverBase { explicit MetalDriver(backend::MetalPlatform* platform) noexcept; ~MetalDriver() noexcept override; @@ -84,78 +86,37 @@ private: * Memory management */ - // Copied from VulkanDriver.h + backend::HandleAllocatorMTL mHandleAllocator; - // For now we're not bothering to store handles in pools, just simple on-demand allocation. - // We have a little map from integer handles to "blobs" which get replaced with the Hw objects. - using Blob = void*; - using HandleMap = tsl::robin_map; - std::mutex mHandleMapMutex; - HandleMap mHandleMap; - HandleBase::HandleId mNextId = 1; - - template - Handle alloc_handle() { - std::lock_guard lock(mHandleMapMutex); - mHandleMap[mNextId] = malloc(sizeof(Dp)); - return Handle(mNextId++); + template + Handle alloc_handle() { + return mHandleAllocator.allocate(); } - template + template Handle alloc_and_construct_handle(ARGS&& ... args) { - std::lock_guard lock(mHandleMapMutex); - Blob blob = mHandleMap[mNextId] = malloc(sizeof(Dp)); - Dp* addr = reinterpret_cast(blob); - new(addr) Dp(std::forward(args)...); - return Handle(mNextId++); + return mHandleAllocator.allocateAndConstruct(std::forward(args)...); } - template - Dp* handle_cast(HandleMap& handleMap, Handle handle) noexcept { - assert_invariant(handle); - if (!handle) return nullptr; // better to get a NPE than random behavior/corruption - std::lock_guard lock(mHandleMapMutex); - auto iter = handleMap.find(handle.getId()); - assert_invariant(iter != handleMap.end()); - Blob& blob = iter.value(); - return reinterpret_cast(blob); + template + D* handle_cast(Handle handle) noexcept { + return mHandleAllocator.handle_cast(handle); } - template - const Dp* handle_const_cast(HandleMap& handleMap, const Handle& handle) noexcept { - assert_invariant(handle); - if (!handle) return nullptr; // better to get a NPE than random behavior/corruption - std::lock_guard lock(mHandleMapMutex); - auto iter = handleMap.find(handle.getId()); - assert_invariant(iter != handleMap.end()); - Blob& blob = iter.value(); - return reinterpret_cast(blob); + template + const D* handle_const_cast(const Handle& handle) noexcept { + return mHandleAllocator.handle_cast(handle); } - template - Dp* construct_handle(HandleMap& handleMap, Handle& handle, ARGS&& ... args) noexcept { - assert_invariant(handle); - if (!handle) return nullptr; // better to get a NPE than random behavior/corruption - std::lock_guard lock(mHandleMapMutex); - auto iter = handleMap.find(handle.getId()); - assert_invariant(iter != handleMap.end()); - Blob& blob = iter.value(); - Dp* addr = reinterpret_cast(blob); - new(addr) Dp(std::forward(args)...); - return addr; + template + D* construct_handle(Handle& handle, ARGS&& ... args) noexcept { + return mHandleAllocator.construct(handle, std::forward(args)...); } - template - void destruct_handle(HandleMap& handleMap, Handle& handle) noexcept { - std::lock_guard lock(mHandleMapMutex); - assert_invariant(handle); - // Call the destructor, remove the blob, don't bother reclaiming the integer id. - auto iter = handleMap.find(handle.getId()); - assert_invariant(iter != handleMap.end()); - Blob& blob = iter.value(); - reinterpret_cast(blob)->~Dp(); - free(blob); - handleMap.erase(handle.getId()); + template + void destruct_handle(Handle& handle) noexcept { + auto* p = mHandleAllocator.handle_cast(handle); + mHandleAllocator.deallocate(handle, p); } void enumerateSamplerGroups(const MetalProgram* program, diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index e8598a658a..b65365e21e 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -55,7 +55,8 @@ Driver* MetalDriver::create(MetalPlatform* const platform) { MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept : DriverBase(new ConcreteDispatcher()), mPlatform(*platform), - mContext(new MetalContext) { + mContext(new MetalContext), + mHandleAllocator("Handles", FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U) { mContext->driver = this; mContext->device = mPlatform.createDevice(); @@ -145,13 +146,13 @@ void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) { void MetalDriver::setFrameScheduledCallback(Handle sch, backend::FrameScheduledCallback callback, void* user) { - auto* swapChain = handle_cast(mHandleMap, sch); + auto* swapChain = handle_cast(sch); swapChain->setFrameScheduledCallback(callback, user); } void MetalDriver::setFrameCompletedCallback(Handle sch, backend::FrameCompletedCallback callback, void* user) { - auto* swapChain = handle_cast(mHandleMap, sch); + auto* swapChain = handle_cast(sch); swapChain->setFrameCompletedCallback(callback, user); } @@ -205,19 +206,19 @@ void MetalDriver::createVertexBufferR(Handle vbh, uint8_t buffer uint8_t attributeCount, uint32_t vertexCount, AttributeArray attributes, BufferUsage usage) { // TODO: Take BufferUsage into account when creating the buffer. - construct_handle(mHandleMap, vbh, *mContext, bufferCount, + construct_handle(vbh, *mContext, bufferCount, attributeCount, vertexCount, attributes); } void MetalDriver::createIndexBufferR(Handle ibh, ElementType elementType, uint32_t indexCount, BufferUsage) { auto elementSize = (uint8_t) getElementTypeSize(elementType); - construct_handle(mHandleMap, ibh, *mContext, elementSize, indexCount); + construct_handle(ibh, *mContext, elementSize, indexCount); } void MetalDriver::createBufferObjectR(Handle boh, uint32_t byteCount, BufferObjectBinding bindingType, BufferUsage) { - construct_handle(mHandleMap, boh, *mContext, byteCount); + construct_handle(boh, *mContext, byteCount); } void MetalDriver::createTextureR(Handle th, SamplerType target, uint8_t levels, @@ -227,7 +228,7 @@ void MetalDriver::createTextureR(Handle th, SamplerType target, uint8 auto& sc = mContext->sampleCountLookup; samples = sc[std::min(MAX_SAMPLE_COUNT, samples)]; - construct_handle(mHandleMap, th, *mContext, target, levels, format, samples, + construct_handle(th, *mContext, target, levels, format, samples, width, height, depth, usage, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3); } @@ -240,7 +241,7 @@ void MetalDriver::createTextureSwizzledR(Handle th, SamplerType targe auto& sc = mContext->sampleCountLookup; samples = sc[std::min(MAX_SAMPLE_COUNT, samples)]; - construct_handle(mHandleMap, th, *mContext, target, levels, format, samples, + construct_handle(th, *mContext, target, levels, format, samples, width, height, depth, usage, r, g, b, a); } @@ -266,24 +267,24 @@ void MetalDriver::importTextureR(Handle th, intptr_t i, ASSERT_PRECONDITION(metalTexture.textureType == filamentMetalType, "Imported id type (%d) != Filament texture type (%d)", metalTexture.textureType, filamentMetalType); - construct_handle(mHandleMap, th, *mContext, target, levels, format, samples, + construct_handle(th, *mContext, target, levels, format, samples, width, height, depth, usage, metalTexture); } void MetalDriver::createSamplerGroupR(Handle sbh, uint32_t size) { - mContext->samplerGroups.insert(construct_handle(mHandleMap, sbh, size)); + mContext->samplerGroups.insert(construct_handle(sbh, size)); } void MetalDriver::createRenderPrimitiveR(Handle rph, int dummy) { - construct_handle(mHandleMap, rph); + construct_handle(rph); } void MetalDriver::createProgramR(Handle rph, Program&& program) { - construct_handle(mHandleMap, rph, mContext->device, program); + construct_handle(rph, mContext->device, program); } void MetalDriver::createDefaultRenderTargetR(Handle rth, int dummy) { - construct_handle(mHandleMap, rth, mContext); + construct_handle(rth, mContext); } void MetalDriver::createRenderTargetR(Handle rth, @@ -303,7 +304,7 @@ void MetalDriver::createRenderTargetR(Handle rth, continue; } - auto colorTexture = handle_cast(mHandleMap, buffer.handle); + auto colorTexture = handle_cast(buffer.handle); ASSERT_PRECONDITION(colorTexture->texture, "Color texture passed to render target has no texture allocation"); colorTexture->updateLodRange(buffer.level); @@ -314,7 +315,7 @@ void MetalDriver::createRenderTargetR(Handle rth, MetalRenderTarget::Attachment depthAttachment = { nil }; if (depth.handle) { - auto depthTexture = handle_cast(mHandleMap, depth.handle); + auto depthTexture = handle_cast(depth.handle); ASSERT_PRECONDITION(depthTexture->texture, "Depth texture passed to render target has no texture allocation."); depthTexture->updateLodRange(depth.level); @@ -325,7 +326,7 @@ void MetalDriver::createRenderTargetR(Handle rth, ASSERT_POSTCONDITION(!depth.handle || any(targetBufferFlags & TargetBufferFlags::DEPTH), "The DEPTH flag was specified, but no depth texture provided."); - construct_handle(mHandleMap, rth, mContext, width, height, samples, + construct_handle(rth, mContext, width, height, samples, colorAttachments, depthAttachment); ASSERT_POSTCONDITION( @@ -335,28 +336,28 @@ void MetalDriver::createRenderTargetR(Handle rth, } void MetalDriver::createFenceR(Handle fh, int dummy) { - auto* fence = handle_cast(mHandleMap, fh); + auto* fence = handle_cast(fh); fence->encode(); } void MetalDriver::createSyncR(Handle sh, int) { - auto* fence = handle_cast(mHandleMap, sh); + auto* fence = handle_cast(sh); fence->encode(); } void MetalDriver::createSwapChainR(Handle sch, void* nativeWindow, uint64_t flags) { if (UTILS_UNLIKELY(flags & backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) { CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) nativeWindow; - construct_handle(mHandleMap, sch, *mContext, pixelBuffer, flags); + construct_handle(sch, *mContext, pixelBuffer, flags); } else { auto* metalLayer = (__bridge CAMetalLayer*) nativeWindow; - construct_handle(mHandleMap, sch, *mContext, metalLayer, flags); + construct_handle(sch, *mContext, metalLayer, flags); } } void MetalDriver::createSwapChainHeadlessR(Handle sch, uint32_t width, uint32_t height, uint64_t flags) { - construct_handle(mHandleMap, sch, *mContext, width, height, flags); + construct_handle(sch, *mContext, width, height, flags); } void MetalDriver::createStreamFromTextureIdR(Handle, intptr_t externalTextureId, @@ -368,47 +369,47 @@ void MetalDriver::createTimerQueryR(Handle tqh, int) { } Handle MetalDriver::createVertexBufferS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createIndexBufferS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createBufferObjectS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createTextureS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createTextureSwizzledS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::importTextureS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createSamplerGroupS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createRenderPrimitiveS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createProgramS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createDefaultRenderTargetS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createRenderTargetS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createFenceS() noexcept { @@ -424,11 +425,11 @@ Handle MetalDriver::createSyncS() noexcept { } Handle MetalDriver::createSwapChainS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createSwapChainHeadlessS() noexcept { - return alloc_handle(); + return alloc_handle(); } Handle MetalDriver::createStreamFromTextureIdS() noexcept { @@ -443,13 +444,13 @@ Handle MetalDriver::createTimerQueryS() noexcept { void MetalDriver::destroyVertexBuffer(Handle vbh) { if (vbh) { - destruct_handle(mHandleMap, vbh); + destruct_handle(vbh); } } void MetalDriver::destroyIndexBuffer(Handle ibh) { if (ibh) { - destruct_handle(mHandleMap, ibh); + destruct_handle(ibh); } } @@ -458,24 +459,24 @@ void MetalDriver::destroyBufferObject(Handle boh) { return; } // TODO: we can skip this loop if we're not a uniform buffer - auto* bo = handle_cast(mHandleMap, boh); + auto* bo = handle_cast(boh); for (auto& thisUniform : mContext->uniformState) { if (thisUniform.buffer == bo->getBuffer()) { thisUniform.bound = false; } } - destruct_handle(mHandleMap, boh); + destruct_handle(boh); } void MetalDriver::destroyRenderPrimitive(Handle rph) { if (rph) { - destruct_handle(mHandleMap, rph); + destruct_handle(rph); } } void MetalDriver::destroyProgram(Handle ph) { if (ph) { - destruct_handle(mHandleMap, ph); + destruct_handle(ph); } } @@ -484,14 +485,14 @@ void MetalDriver::destroySamplerGroup(Handle sbh) { return; } // Unbind this sampler group from our internal state. - auto* metalSampler = handle_cast(mHandleMap, sbh); + auto* metalSampler = handle_cast(sbh); for (auto& samplerBinding : mContext->samplerBindings) { if (samplerBinding == metalSampler) { samplerBinding = {}; } } mContext->samplerGroups.erase(metalSampler); - destruct_handle(mHandleMap, sbh); + destruct_handle(sbh); } void MetalDriver::destroyTexture(Handle th) { @@ -510,18 +511,18 @@ void MetalDriver::destroyTexture(Handle th) { } } - destruct_handle(mHandleMap, th); + destruct_handle(th); } void MetalDriver::destroyRenderTarget(Handle rth) { if (rth) { - destruct_handle(mHandleMap, rth); + destruct_handle(rth); } } void MetalDriver::destroySwapChain(Handle sch) { if (sch) { - destruct_handle(mHandleMap, sch); + destruct_handle(sch); } } @@ -531,13 +532,13 @@ void MetalDriver::destroyStream(Handle sh) { void MetalDriver::destroyTimerQuery(Handle tqh) { if (tqh) { - destruct_handle(mHandleMap, tqh); + destruct_handle(tqh); } } void MetalDriver::destroySync(Handle sh) { if (sh) { - destruct_handle(mHandleMap, sh); + destruct_handle(sh); } } @@ -589,12 +590,12 @@ void MetalDriver::updateStreams(backend::DriverApi* driver) { void MetalDriver::destroyFence(Handle fh) { if (fh) { - destruct_handle(mHandleMap, fh); + destruct_handle(fh); } } FenceStatus MetalDriver::wait(Handle fh, uint64_t timeout) { - auto* fence = handle_cast(mHandleMap, fh); + auto* fence = handle_cast(fh); if (!fence) { return FenceStatus::ERROR; } @@ -682,22 +683,22 @@ uint8_t MetalDriver::getMaxDrawBuffers() { void MetalDriver::updateIndexBuffer(Handle ibh, BufferDescriptor&& data, uint32_t byteOffset) { assert_invariant(byteOffset == 0); // TODO: handle byteOffset for index buffers - auto* ib = handle_cast(mHandleMap, ibh); + auto* ib = handle_cast(ibh); ib->buffer.copyIntoBuffer(data.buffer, data.size); scheduleDestroy(std::move(data)); } void MetalDriver::updateBufferObject(Handle boh, BufferDescriptor&& data, uint32_t byteOffset) { - auto* bo = handle_cast(mHandleMap, boh); + auto* bo = handle_cast(boh); bo->updateBuffer(data.buffer, data.size, byteOffset); scheduleDestroy(std::move(data)); } void MetalDriver::setVertexBufferObject(Handle vbh, uint32_t index, Handle boh) { - auto* vertexBuffer = handle_cast(mHandleMap, vbh); - auto* bufferObject = handle_cast(mHandleMap, boh); + auto* vertexBuffer = handle_cast(vbh); + auto* bufferObject = handle_cast(boh); assert_invariant(index < vertexBuffer->buffers.size()); vertexBuffer->buffers[index] = bufferObject->getBuffer(); } @@ -706,7 +707,7 @@ void MetalDriver::update2DImage(Handle th, uint32_t level, uint32_t x uint32_t yoffset, uint32_t width, uint32_t height, PixelBufferDescriptor&& data) { ASSERT_PRECONDITION(!isInRenderPass(mContext), "update2DImage must be called outside of a render pass."); - auto tex = handle_cast(mHandleMap, th); + auto tex = handle_cast(th); tex->loadImage(level, MTLRegionMake2D(xoffset, yoffset, width, height), data); scheduleDestroy(std::move(data)); } @@ -720,7 +721,7 @@ void MetalDriver::update3DImage(Handle th, uint32_t level, PixelBufferDescriptor&& data) { ASSERT_PRECONDITION(!isInRenderPass(mContext), "update3DImage must be called outside of a render pass."); - auto tex = handle_cast(mHandleMap, th); + auto tex = handle_cast(th); tex->loadImage(level, MTLRegionMake3D(xoffset, yoffset, zoffset, width, height, depth), data); scheduleDestroy(std::move(data)); } @@ -729,7 +730,7 @@ void MetalDriver::updateCubeImage(Handle th, uint32_t level, PixelBufferDescriptor&& data, FaceOffsets faceOffsets) { ASSERT_PRECONDITION(!isInRenderPass(mContext), "updateCubeImage must be called outside of a render pass."); - auto tex = handle_cast(mHandleMap, th); + auto tex = handle_cast(th); tex->loadCubeImage(faceOffsets, level, data); scheduleDestroy(std::move(data)); } @@ -749,12 +750,12 @@ void MetalDriver::cancelExternalImage(void* image) { } void MetalDriver::setExternalImage(Handle th, void* image) { - auto texture = handle_cast(mHandleMap, th); + auto texture = handle_cast(th); texture->externalImage.set((CVPixelBufferRef) image); } void MetalDriver::setExternalImagePlane(Handle th, void* image, uint32_t plane) { - auto texture = handle_cast(mHandleMap, th); + auto texture = handle_cast(th); texture->externalImage.set((CVPixelBufferRef) image, plane); } @@ -762,12 +763,12 @@ void MetalDriver::setExternalStream(Handle th, Handle sh) { } bool MetalDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { - auto* tq = handle_cast(mHandleMap, tqh); + auto* tq = handle_cast(tqh); return mContext->timerQueryImpl->getQueryResult(tq, elapsedTime); } SyncStatus MetalDriver::getSyncStatus(Handle sh) { - auto* fence = handle_cast(mHandleMap, sh); + auto* fence = handle_cast(sh); FenceStatus status = fence->wait(0); if (status == FenceStatus::TIMEOUT_EXPIRED) { return SyncStatus::NOT_SIGNALED; @@ -780,7 +781,7 @@ SyncStatus MetalDriver::getSyncStatus(Handle sh) { void MetalDriver::generateMipmaps(Handle th) { ASSERT_PRECONDITION(!isInRenderPass(mContext), "generateMipmaps must be called outside of a render pass."); - auto tex = handle_cast(mHandleMap, th); + auto tex = handle_cast(th); id blitEncoder = [getPendingCommandBuffer(mContext) blitCommandEncoder]; [blitEncoder generateMipmapsForTexture:tex->texture]; [blitEncoder endEncoding]; @@ -794,13 +795,13 @@ bool MetalDriver::canGenerateMipmaps() { void MetalDriver::updateSamplerGroup(Handle sbh, SamplerGroup&& samplerGroup) { - auto sb = handle_cast(mHandleMap, sbh); + auto sb = handle_cast(sbh); *sb->sb = samplerGroup; } void MetalDriver::beginRenderPass(Handle rth, const RenderPassParams& params) { - auto renderTarget = handle_cast(mHandleMap, rth); + auto renderTarget = handle_cast(rth); mContext->currentRenderTarget = renderTarget; mContext->currentRenderPassFlags = params.flags; @@ -851,16 +852,16 @@ void MetalDriver::endRenderPass(int dummy) { void MetalDriver::setRenderPrimitiveBuffer(Handle rph, Handle vbh, Handle ibh) { - auto primitive = handle_cast(mHandleMap, rph); - auto vertexBuffer = handle_cast(mHandleMap, vbh); - auto indexBuffer = handle_cast(mHandleMap, ibh); + auto primitive = handle_cast(rph); + auto vertexBuffer = handle_cast(vbh); + auto indexBuffer = handle_cast(ibh); primitive->setBuffers(vertexBuffer, indexBuffer); } void MetalDriver::setRenderPrimitiveRange(Handle rph, PrimitiveType pt, uint32_t offset, uint32_t minIndex, uint32_t maxIndex, uint32_t count) { - auto primitive = handle_cast(mHandleMap, rph); + auto primitive = handle_cast(rph); primitive->type = pt; primitive->offset = offset * primitive->indexBuffer->elementSize; primitive->count = count; @@ -870,24 +871,24 @@ void MetalDriver::setRenderPrimitiveRange(Handle rph, void MetalDriver::makeCurrent(Handle schDraw, Handle schRead) { ASSERT_PRECONDITION_NON_FATAL(schDraw, "A draw SwapChain must be set."); - auto* drawSwapChain = handle_cast(mHandleMap, schDraw); + auto* drawSwapChain = handle_cast(schDraw); mContext->currentDrawSwapChain = drawSwapChain; if (schRead) { - auto* readSwapChain = handle_cast(mHandleMap, schRead); + auto* readSwapChain = handle_cast(schRead); mContext->currentReadSwapChain = readSwapChain; } } void MetalDriver::commit(Handle sch) { - auto* swapChain = handle_cast(mHandleMap, sch); + auto* swapChain = handle_cast(sch); swapChain->present(); submitPendingCommands(mContext); swapChain->releaseDrawable(); } void MetalDriver::bindUniformBuffer(uint32_t index, Handle boh) { - auto* bo = handle_cast(mHandleMap, boh); + auto* bo = handle_cast(boh); mContext->uniformState[index] = UniformBufferState{ .buffer = bo->getBuffer(), .offset = 0, @@ -897,7 +898,7 @@ void MetalDriver::bindUniformBuffer(uint32_t index, Handle boh) void MetalDriver::bindUniformBufferRange(uint32_t index, Handle boh, uint32_t offset, uint32_t size) { - auto* bo = handle_cast(mHandleMap, boh); + auto* bo = handle_cast(boh); mContext->uniformState[index] = UniformBufferState{ .buffer = bo->getBuffer(), .offset = offset, @@ -906,7 +907,7 @@ void MetalDriver::bindUniformBufferRange(uint32_t index, Handle } void MetalDriver::bindSamplers(uint32_t index, Handle sbh) { - auto sb = handle_cast(mHandleMap, sbh); + auto sb = handle_cast(sbh); mContext->samplerBindings[index] = sb; } @@ -950,7 +951,7 @@ void MetalDriver::readPixels(Handle src, uint32_t x, uint32_t y, ASSERT_PRECONDITION(!isInRenderPass(mContext), "readPixels must be called outside of a render pass."); - auto srcTarget = handle_cast(mHandleMap, src); + auto srcTarget = handle_cast(src); // We always readPixels from the COLOR0 attachment. MetalRenderTarget::Attachment color = srcTarget->getDrawColorAttachment(0); id srcTexture = color.texture; @@ -1039,8 +1040,8 @@ void MetalDriver::blit(TargetBufferFlags buffers, mContext->currentRenderPassEncoder = nil; } - auto srcTarget = handle_cast(mHandleMap, src); - auto dstTarget = handle_cast(mHandleMap, dst); + auto srcTarget = handle_cast(src); + auto dstTarget = handle_cast(dst); ASSERT_PRECONDITION(srcRect.left >= 0 && srcRect.bottom >= 0 && dstRect.left >= 0 && dstRect.bottom >= 0, @@ -1139,8 +1140,8 @@ void MetalDriver::blit(TargetBufferFlags buffers, void MetalDriver::draw(backend::PipelineState ps, Handle rph) { ASSERT_PRECONDITION(mContext->currentRenderPassEncoder != nullptr, "Attempted to draw without a valid command encoder."); - auto primitive = handle_cast(mHandleMap, rph); - auto program = handle_cast(mHandleMap, ps.program); + auto primitive = handle_cast(rph); + auto program = handle_cast(ps.program); const auto& rs = ps.rasterState; // If the material debugger is enabled, avoid fatal (or cascading) errors and that can occur @@ -1264,7 +1265,7 @@ void MetalDriver::draw(backend::PipelineState ps, Handle rph) if (binding >= SAMPLER_BINDING_COUNT) { return; } - const auto metalTexture = handle_const_cast(mHandleMap, sampler->t); + const auto metalTexture = handle_const_cast(sampler->t); texturesToBind[binding] = metalTexture->swizzledTextureView ? metalTexture->swizzledTextureView : metalTexture->texture; @@ -1352,14 +1353,14 @@ void MetalDriver::draw(backend::PipelineState ps, Handle rph) void MetalDriver::beginTimerQuery(Handle tqh) { ASSERT_PRECONDITION(!isInRenderPass(mContext), "beginTimerQuery must be called outside of a render pass."); - auto* tq = handle_cast(mHandleMap, tqh); + auto* tq = handle_cast(tqh); mContext->timerQueryImpl->beginTimeElapsedQuery(tq); } void MetalDriver::endTimerQuery(Handle tqh) { ASSERT_PRECONDITION(!isInRenderPass(mContext), "endTimerQuery must be called outside of a render pass."); - auto* tq = handle_cast(mHandleMap, tqh); + auto* tq = handle_cast(tqh); mContext->timerQueryImpl->endTimeElapsedQuery(tq); } diff --git a/filament/backend/src/metal/MetalHandles.h b/filament/backend/src/metal/MetalHandles.h index f9574fd541..d75ae7ef28 100644 --- a/filament/backend/src/metal/MetalHandles.h +++ b/filament/backend/src/metal/MetalHandles.h @@ -34,6 +34,7 @@ #include #include #include +#include #include namespace filament { @@ -258,7 +259,10 @@ private: id multisampledDepth = nil; }; -class MetalFence : public HwFence { +// MetalFence is used to implement both Fences and Syncs. +// There's no diamond problem, because HwBase (superclass of HwFence and HwSync) is empty. +static_assert(std::is_empty_v); +class MetalFence : public HwFence, public HwSync { public: // MetalFence is special, as it gets constructed on the Filament thread. We must delay inserting