Switch Metal driver to use HandleAllocator (#4326)

This commit is contained in:
Ben Doherty
2021-07-15 16:56:19 -07:00
committed by GitHub
parent 2686b0bbac
commit 302c07048c
7 changed files with 124 additions and 148 deletions
+4
View File
@@ -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
# ==================================================================================================
+1
View File
@@ -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}
)
# ==================================================================================================
@@ -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 {
+4
View File
@@ -110,4 +110,8 @@ template class HandleAllocatorGL;
template class HandleAllocatorVK;
#endif
#if defined (FILAMENT_SUPPORTS_METAL)
template class HandleAllocatorMTL;
#endif
} // namespace filament::backend
+25 -64
View File
@@ -20,14 +20,12 @@
#include "private/backend/Driver.h"
#include "DriverBase.h"
#include "private/backend/HandleAllocator.h"
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/debug.h>
#include <tsl/robin_map.h>
#include <mutex>
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<HandleBase::HandleId, Blob>;
std::mutex mHandleMapMutex;
HandleMap mHandleMap;
HandleBase::HandleId mNextId = 1;
template<typename Dp, typename B>
Handle<B> alloc_handle() {
std::lock_guard<std::mutex> lock(mHandleMapMutex);
mHandleMap[mNextId] = malloc(sizeof(Dp));
return Handle<B>(mNextId++);
template<typename D>
Handle<D> alloc_handle() {
return mHandleAllocator.allocate<D>();
}
template<typename Dp, typename B, typename ... ARGS>
template<typename D, typename B, typename ... ARGS>
Handle<B> alloc_and_construct_handle(ARGS&& ... args) {
std::lock_guard<std::mutex> lock(mHandleMapMutex);
Blob blob = mHandleMap[mNextId] = malloc(sizeof(Dp));
Dp* addr = reinterpret_cast<Dp*>(blob);
new(addr) Dp(std::forward<ARGS>(args)...);
return Handle<B>(mNextId++);
return mHandleAllocator.allocateAndConstruct<D>(std::forward<ARGS>(args)...);
}
template<typename Dp, typename B>
Dp* handle_cast(HandleMap& handleMap, Handle<B> handle) noexcept {
assert_invariant(handle);
if (!handle) return nullptr; // better to get a NPE than random behavior/corruption
std::lock_guard<std::mutex> lock(mHandleMapMutex);
auto iter = handleMap.find(handle.getId());
assert_invariant(iter != handleMap.end());
Blob& blob = iter.value();
return reinterpret_cast<Dp*>(blob);
template<typename D, typename B>
D* handle_cast(Handle<B> handle) noexcept {
return mHandleAllocator.handle_cast<D*>(handle);
}
template<typename Dp, typename B>
const Dp* handle_const_cast(HandleMap& handleMap, const Handle<B>& handle) noexcept {
assert_invariant(handle);
if (!handle) return nullptr; // better to get a NPE than random behavior/corruption
std::lock_guard<std::mutex> lock(mHandleMapMutex);
auto iter = handleMap.find(handle.getId());
assert_invariant(iter != handleMap.end());
Blob& blob = iter.value();
return reinterpret_cast<const Dp*>(blob);
template<typename D, typename B>
const D* handle_const_cast(const Handle<B>& handle) noexcept {
return mHandleAllocator.handle_cast<D*>(handle);
}
template<typename Dp, typename B, typename ... ARGS>
Dp* construct_handle(HandleMap& handleMap, Handle<B>& handle, ARGS&& ... args) noexcept {
assert_invariant(handle);
if (!handle) return nullptr; // better to get a NPE than random behavior/corruption
std::lock_guard<std::mutex> lock(mHandleMapMutex);
auto iter = handleMap.find(handle.getId());
assert_invariant(iter != handleMap.end());
Blob& blob = iter.value();
Dp* addr = reinterpret_cast<Dp*>(blob);
new(addr) Dp(std::forward<ARGS>(args)...);
return addr;
template<typename D, typename B, typename ... ARGS>
D* construct_handle(Handle<B>& handle, ARGS&& ... args) noexcept {
return mHandleAllocator.construct<D>(handle, std::forward<ARGS>(args)...);
}
template<typename Dp, typename B>
void destruct_handle(HandleMap& handleMap, Handle<B>& handle) noexcept {
std::lock_guard<std::mutex> 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<Dp*>(blob)->~Dp();
free(blob);
handleMap.erase(handle.getId());
template<typename D, typename B>
void destruct_handle(Handle<B>& handle) noexcept {
auto* p = mHandleAllocator.handle_cast<D*>(handle);
mHandleAllocator.deallocate(handle, p);
}
void enumerateSamplerGroups(const MetalProgram* program,
+82 -81
View File
@@ -55,7 +55,8 @@ Driver* MetalDriver::create(MetalPlatform* const platform) {
MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept
: DriverBase(new ConcreteDispatcher<MetalDriver>()),
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<HwSwapChain> sch,
backend::FrameScheduledCallback callback, void* user) {
auto* swapChain = handle_cast<MetalSwapChain>(mHandleMap, sch);
auto* swapChain = handle_cast<MetalSwapChain>(sch);
swapChain->setFrameScheduledCallback(callback, user);
}
void MetalDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
backend::FrameCompletedCallback callback, void* user) {
auto* swapChain = handle_cast<MetalSwapChain>(mHandleMap, sch);
auto* swapChain = handle_cast<MetalSwapChain>(sch);
swapChain->setFrameCompletedCallback(callback, user);
}
@@ -205,19 +206,19 @@ void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> 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<MetalVertexBuffer>(mHandleMap, vbh, *mContext, bufferCount,
construct_handle<MetalVertexBuffer>(vbh, *mContext, bufferCount,
attributeCount, vertexCount, attributes);
}
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage) {
auto elementSize = (uint8_t) getElementTypeSize(elementType);
construct_handle<MetalIndexBuffer>(mHandleMap, ibh, *mContext, elementSize, indexCount);
construct_handle<MetalIndexBuffer>(ibh, *mContext, elementSize, indexCount);
}
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage) {
construct_handle<MetalBufferObject>(mHandleMap, boh, *mContext, byteCount);
construct_handle<MetalBufferObject>(boh, *mContext, byteCount);
}
void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
@@ -227,7 +228,7 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
auto& sc = mContext->sampleCountLookup;
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
construct_handle<MetalTexture>(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<HwTexture> th, SamplerType targe
auto& sc = mContext->sampleCountLookup;
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
construct_handle<MetalTexture>(th, *mContext, target, levels, format, samples,
width, height, depth, usage, r, g, b, a);
}
@@ -266,24 +267,24 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
ASSERT_PRECONDITION(metalTexture.textureType == filamentMetalType,
"Imported id<MTLTexture> type (%d) != Filament texture type (%d)",
metalTexture.textureType, filamentMetalType);
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
construct_handle<MetalTexture>(th, *mContext, target, levels, format, samples,
width, height, depth, usage, metalTexture);
}
void MetalDriver::createSamplerGroupR(Handle<HwSamplerGroup> sbh, uint32_t size) {
mContext->samplerGroups.insert(construct_handle<MetalSamplerGroup>(mHandleMap, sbh, size));
mContext->samplerGroups.insert(construct_handle<MetalSamplerGroup>(sbh, size));
}
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, int dummy) {
construct_handle<MetalRenderPrimitive>(mHandleMap, rph);
construct_handle<MetalRenderPrimitive>(rph);
}
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
construct_handle<MetalProgram>(mHandleMap, rph, mContext->device, program);
construct_handle<MetalProgram>(rph, mContext->device, program);
}
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dummy) {
construct_handle<MetalRenderTarget>(mHandleMap, rth, mContext);
construct_handle<MetalRenderTarget>(rth, mContext);
}
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
@@ -303,7 +304,7 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
continue;
}
auto colorTexture = handle_cast<MetalTexture>(mHandleMap, buffer.handle);
auto colorTexture = handle_cast<MetalTexture>(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<HwRenderTarget> rth,
MetalRenderTarget::Attachment depthAttachment = { nil };
if (depth.handle) {
auto depthTexture = handle_cast<MetalTexture>(mHandleMap, depth.handle);
auto depthTexture = handle_cast<MetalTexture>(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<HwRenderTarget> rth,
ASSERT_POSTCONDITION(!depth.handle || any(targetBufferFlags & TargetBufferFlags::DEPTH),
"The DEPTH flag was specified, but no depth texture provided.");
construct_handle<MetalRenderTarget>(mHandleMap, rth, mContext, width, height, samples,
construct_handle<MetalRenderTarget>(rth, mContext, width, height, samples,
colorAttachments, depthAttachment);
ASSERT_POSTCONDITION(
@@ -335,28 +336,28 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
}
void MetalDriver::createFenceR(Handle<HwFence> fh, int dummy) {
auto* fence = handle_cast<MetalFence>(mHandleMap, fh);
auto* fence = handle_cast<MetalFence>(fh);
fence->encode();
}
void MetalDriver::createSyncR(Handle<HwSync> sh, int) {
auto* fence = handle_cast<MetalFence>(mHandleMap, sh);
auto* fence = handle_cast<MetalFence>(sh);
fence->encode();
}
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
if (UTILS_UNLIKELY(flags & backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) nativeWindow;
construct_handle<MetalSwapChain>(mHandleMap, sch, *mContext, pixelBuffer, flags);
construct_handle<MetalSwapChain>(sch, *mContext, pixelBuffer, flags);
} else {
auto* metalLayer = (__bridge CAMetalLayer*) nativeWindow;
construct_handle<MetalSwapChain>(mHandleMap, sch, *mContext, metalLayer, flags);
construct_handle<MetalSwapChain>(sch, *mContext, metalLayer, flags);
}
}
void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
uint32_t width, uint32_t height, uint64_t flags) {
construct_handle<MetalSwapChain>(mHandleMap, sch, *mContext, width, height, flags);
construct_handle<MetalSwapChain>(sch, *mContext, width, height, flags);
}
void MetalDriver::createStreamFromTextureIdR(Handle<HwStream>, intptr_t externalTextureId,
@@ -368,47 +369,47 @@ void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
}
Handle<HwVertexBuffer> MetalDriver::createVertexBufferS() noexcept {
return alloc_handle<MetalVertexBuffer, HwVertexBuffer>();
return alloc_handle<MetalVertexBuffer>();
}
Handle<HwIndexBuffer> MetalDriver::createIndexBufferS() noexcept {
return alloc_handle<MetalIndexBuffer, HwIndexBuffer>();
return alloc_handle<MetalIndexBuffer>();
}
Handle<HwBufferObject> MetalDriver::createBufferObjectS() noexcept {
return alloc_handle<MetalBufferObject, HwBufferObject>();
return alloc_handle<MetalBufferObject>();
}
Handle<HwTexture> MetalDriver::createTextureS() noexcept {
return alloc_handle<MetalTexture, HwTexture>();
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::createTextureSwizzledS() noexcept {
return alloc_handle<MetalTexture, HwTexture>();
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::importTextureS() noexcept {
return alloc_handle<MetalTexture, HwTexture>();
return alloc_handle<MetalTexture>();
}
Handle<HwSamplerGroup> MetalDriver::createSamplerGroupS() noexcept {
return alloc_handle<MetalSamplerGroup, HwSamplerGroup>();
return alloc_handle<MetalSamplerGroup>();
}
Handle<HwRenderPrimitive> MetalDriver::createRenderPrimitiveS() noexcept {
return alloc_handle<MetalRenderPrimitive, HwRenderPrimitive>();
return alloc_handle<MetalRenderPrimitive>();
}
Handle<HwProgram> MetalDriver::createProgramS() noexcept {
return alloc_handle<MetalProgram, HwProgram>();
return alloc_handle<MetalProgram>();
}
Handle<HwRenderTarget> MetalDriver::createDefaultRenderTargetS() noexcept {
return alloc_handle<MetalRenderTarget, HwRenderTarget>();
return alloc_handle<MetalRenderTarget>();
}
Handle<HwRenderTarget> MetalDriver::createRenderTargetS() noexcept {
return alloc_handle<MetalRenderTarget, HwRenderTarget>();
return alloc_handle<MetalRenderTarget>();
}
Handle<HwFence> MetalDriver::createFenceS() noexcept {
@@ -424,11 +425,11 @@ Handle<HwSync> MetalDriver::createSyncS() noexcept {
}
Handle<HwSwapChain> MetalDriver::createSwapChainS() noexcept {
return alloc_handle<MetalSwapChain, HwSwapChain>();
return alloc_handle<MetalSwapChain>();
}
Handle<HwSwapChain> MetalDriver::createSwapChainHeadlessS() noexcept {
return alloc_handle<MetalSwapChain, HwSwapChain>();
return alloc_handle<MetalSwapChain>();
}
Handle<HwStream> MetalDriver::createStreamFromTextureIdS() noexcept {
@@ -443,13 +444,13 @@ Handle<HwTimerQuery> MetalDriver::createTimerQueryS() noexcept {
void MetalDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
if (vbh) {
destruct_handle<MetalVertexBuffer>(mHandleMap, vbh);
destruct_handle<MetalVertexBuffer>(vbh);
}
}
void MetalDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
if (ibh) {
destruct_handle<MetalIndexBuffer>(mHandleMap, ibh);
destruct_handle<MetalIndexBuffer>(ibh);
}
}
@@ -458,24 +459,24 @@ void MetalDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
return;
}
// TODO: we can skip this loop if we're not a uniform buffer
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
auto* bo = handle_cast<MetalBufferObject>(boh);
for (auto& thisUniform : mContext->uniformState) {
if (thisUniform.buffer == bo->getBuffer()) {
thisUniform.bound = false;
}
}
destruct_handle<MetalBufferObject>(mHandleMap, boh);
destruct_handle<MetalBufferObject>(boh);
}
void MetalDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
if (rph) {
destruct_handle<MetalRenderPrimitive>(mHandleMap, rph);
destruct_handle<MetalRenderPrimitive>(rph);
}
}
void MetalDriver::destroyProgram(Handle<HwProgram> ph) {
if (ph) {
destruct_handle<MetalProgram>(mHandleMap, ph);
destruct_handle<MetalProgram>(ph);
}
}
@@ -484,14 +485,14 @@ void MetalDriver::destroySamplerGroup(Handle<HwSamplerGroup> sbh) {
return;
}
// Unbind this sampler group from our internal state.
auto* metalSampler = handle_cast<MetalSamplerGroup>(mHandleMap, sbh);
auto* metalSampler = handle_cast<MetalSamplerGroup>(sbh);
for (auto& samplerBinding : mContext->samplerBindings) {
if (samplerBinding == metalSampler) {
samplerBinding = {};
}
}
mContext->samplerGroups.erase(metalSampler);
destruct_handle<MetalSamplerGroup>(mHandleMap, sbh);
destruct_handle<MetalSamplerGroup>(sbh);
}
void MetalDriver::destroyTexture(Handle<HwTexture> th) {
@@ -510,18 +511,18 @@ void MetalDriver::destroyTexture(Handle<HwTexture> th) {
}
}
destruct_handle<MetalTexture>(mHandleMap, th);
destruct_handle<MetalTexture>(th);
}
void MetalDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
if (rth) {
destruct_handle<MetalRenderTarget>(mHandleMap, rth);
destruct_handle<MetalRenderTarget>(rth);
}
}
void MetalDriver::destroySwapChain(Handle<HwSwapChain> sch) {
if (sch) {
destruct_handle<MetalSwapChain>(mHandleMap, sch);
destruct_handle<MetalSwapChain>(sch);
}
}
@@ -531,13 +532,13 @@ void MetalDriver::destroyStream(Handle<HwStream> sh) {
void MetalDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
if (tqh) {
destruct_handle<MetalTimerQuery>(mHandleMap, tqh);
destruct_handle<MetalTimerQuery>(tqh);
}
}
void MetalDriver::destroySync(Handle<HwSync> sh) {
if (sh) {
destruct_handle<MetalFence>(mHandleMap, sh);
destruct_handle<MetalFence>(sh);
}
}
@@ -589,12 +590,12 @@ void MetalDriver::updateStreams(backend::DriverApi* driver) {
void MetalDriver::destroyFence(Handle<HwFence> fh) {
if (fh) {
destruct_handle<MetalFence>(mHandleMap, fh);
destruct_handle<MetalFence>(fh);
}
}
FenceStatus MetalDriver::wait(Handle<HwFence> fh, uint64_t timeout) {
auto* fence = handle_cast<MetalFence>(mHandleMap, fh);
auto* fence = handle_cast<MetalFence>(fh);
if (!fence) {
return FenceStatus::ERROR;
}
@@ -682,22 +683,22 @@ uint8_t MetalDriver::getMaxDrawBuffers() {
void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& data,
uint32_t byteOffset) {
assert_invariant(byteOffset == 0); // TODO: handle byteOffset for index buffers
auto* ib = handle_cast<MetalIndexBuffer>(mHandleMap, ibh);
auto* ib = handle_cast<MetalIndexBuffer>(ibh);
ib->buffer.copyIntoBuffer(data.buffer, data.size);
scheduleDestroy(std::move(data));
}
void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& data,
uint32_t byteOffset) {
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
auto* bo = handle_cast<MetalBufferObject>(boh);
bo->updateBuffer(data.buffer, data.size, byteOffset);
scheduleDestroy(std::move(data));
}
void MetalDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
Handle<HwBufferObject> boh) {
auto* vertexBuffer = handle_cast<MetalVertexBuffer>(mHandleMap, vbh);
auto* bufferObject = handle_cast<MetalBufferObject>(mHandleMap, boh);
auto* vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
auto* bufferObject = handle_cast<MetalBufferObject>(boh);
assert_invariant(index < vertexBuffer->buffers.size());
vertexBuffer->buffers[index] = bufferObject->getBuffer();
}
@@ -706,7 +707,7 @@ void MetalDriver::update2DImage(Handle<HwTexture> 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<MetalTexture>(mHandleMap, th);
auto tex = handle_cast<MetalTexture>(th);
tex->loadImage(level, MTLRegionMake2D(xoffset, yoffset, width, height), data);
scheduleDestroy(std::move(data));
}
@@ -720,7 +721,7 @@ void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
PixelBufferDescriptor&& data) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
"update3DImage must be called outside of a render pass.");
auto tex = handle_cast<MetalTexture>(mHandleMap, th);
auto tex = handle_cast<MetalTexture>(th);
tex->loadImage(level, MTLRegionMake3D(xoffset, yoffset, zoffset, width, height, depth), data);
scheduleDestroy(std::move(data));
}
@@ -729,7 +730,7 @@ void MetalDriver::updateCubeImage(Handle<HwTexture> 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<MetalTexture>(mHandleMap, th);
auto tex = handle_cast<MetalTexture>(th);
tex->loadCubeImage(faceOffsets, level, data);
scheduleDestroy(std::move(data));
}
@@ -749,12 +750,12 @@ void MetalDriver::cancelExternalImage(void* image) {
}
void MetalDriver::setExternalImage(Handle<HwTexture> th, void* image) {
auto texture = handle_cast<MetalTexture>(mHandleMap, th);
auto texture = handle_cast<MetalTexture>(th);
texture->externalImage.set((CVPixelBufferRef) image);
}
void MetalDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
auto texture = handle_cast<MetalTexture>(mHandleMap, th);
auto texture = handle_cast<MetalTexture>(th);
texture->externalImage.set((CVPixelBufferRef) image, plane);
}
@@ -762,12 +763,12 @@ void MetalDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
}
bool MetalDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64_t* elapsedTime) {
auto* tq = handle_cast<MetalTimerQuery>(mHandleMap, tqh);
auto* tq = handle_cast<MetalTimerQuery>(tqh);
return mContext->timerQueryImpl->getQueryResult(tq, elapsedTime);
}
SyncStatus MetalDriver::getSyncStatus(Handle<HwSync> sh) {
auto* fence = handle_cast<MetalFence>(mHandleMap, sh);
auto* fence = handle_cast<MetalFence>(sh);
FenceStatus status = fence->wait(0);
if (status == FenceStatus::TIMEOUT_EXPIRED) {
return SyncStatus::NOT_SIGNALED;
@@ -780,7 +781,7 @@ SyncStatus MetalDriver::getSyncStatus(Handle<HwSync> sh) {
void MetalDriver::generateMipmaps(Handle<HwTexture> th) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
"generateMipmaps must be called outside of a render pass.");
auto tex = handle_cast<MetalTexture>(mHandleMap, th);
auto tex = handle_cast<MetalTexture>(th);
id <MTLBlitCommandEncoder> blitEncoder = [getPendingCommandBuffer(mContext) blitCommandEncoder];
[blitEncoder generateMipmapsForTexture:tex->texture];
[blitEncoder endEncoding];
@@ -794,13 +795,13 @@ bool MetalDriver::canGenerateMipmaps() {
void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
SamplerGroup&& samplerGroup) {
auto sb = handle_cast<MetalSamplerGroup>(mHandleMap, sbh);
auto sb = handle_cast<MetalSamplerGroup>(sbh);
*sb->sb = samplerGroup;
}
void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
const RenderPassParams& params) {
auto renderTarget = handle_cast<MetalRenderTarget>(mHandleMap, rth);
auto renderTarget = handle_cast<MetalRenderTarget>(rth);
mContext->currentRenderTarget = renderTarget;
mContext->currentRenderPassFlags = params.flags;
@@ -851,16 +852,16 @@ void MetalDriver::endRenderPass(int dummy) {
void MetalDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh) {
auto primitive = handle_cast<MetalRenderPrimitive>(mHandleMap, rph);
auto vertexBuffer = handle_cast<MetalVertexBuffer>(mHandleMap, vbh);
auto indexBuffer = handle_cast<MetalIndexBuffer>(mHandleMap, ibh);
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
auto vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
auto indexBuffer = handle_cast<MetalIndexBuffer>(ibh);
primitive->setBuffers(vertexBuffer, indexBuffer);
}
void MetalDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
PrimitiveType pt, uint32_t offset, uint32_t minIndex, uint32_t maxIndex,
uint32_t count) {
auto primitive = handle_cast<MetalRenderPrimitive>(mHandleMap, rph);
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
primitive->type = pt;
primitive->offset = offset * primitive->indexBuffer->elementSize;
primitive->count = count;
@@ -870,24 +871,24 @@ void MetalDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
void MetalDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain> schRead) {
ASSERT_PRECONDITION_NON_FATAL(schDraw, "A draw SwapChain must be set.");
auto* drawSwapChain = handle_cast<MetalSwapChain>(mHandleMap, schDraw);
auto* drawSwapChain = handle_cast<MetalSwapChain>(schDraw);
mContext->currentDrawSwapChain = drawSwapChain;
if (schRead) {
auto* readSwapChain = handle_cast<MetalSwapChain>(mHandleMap, schRead);
auto* readSwapChain = handle_cast<MetalSwapChain>(schRead);
mContext->currentReadSwapChain = readSwapChain;
}
}
void MetalDriver::commit(Handle<HwSwapChain> sch) {
auto* swapChain = handle_cast<MetalSwapChain>(mHandleMap, sch);
auto* swapChain = handle_cast<MetalSwapChain>(sch);
swapChain->present();
submitPendingCommands(mContext);
swapChain->releaseDrawable();
}
void MetalDriver::bindUniformBuffer(uint32_t index, Handle<HwBufferObject> boh) {
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
auto* bo = handle_cast<MetalBufferObject>(boh);
mContext->uniformState[index] = UniformBufferState{
.buffer = bo->getBuffer(),
.offset = 0,
@@ -897,7 +898,7 @@ void MetalDriver::bindUniformBuffer(uint32_t index, Handle<HwBufferObject> boh)
void MetalDriver::bindUniformBufferRange(uint32_t index, Handle<HwBufferObject> boh,
uint32_t offset, uint32_t size) {
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
auto* bo = handle_cast<MetalBufferObject>(boh);
mContext->uniformState[index] = UniformBufferState{
.buffer = bo->getBuffer(),
.offset = offset,
@@ -906,7 +907,7 @@ void MetalDriver::bindUniformBufferRange(uint32_t index, Handle<HwBufferObject>
}
void MetalDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
auto sb = handle_cast<MetalSamplerGroup>(mHandleMap, sbh);
auto sb = handle_cast<MetalSamplerGroup>(sbh);
mContext->samplerBindings[index] = sb;
}
@@ -950,7 +951,7 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
ASSERT_PRECONDITION(!isInRenderPass(mContext),
"readPixels must be called outside of a render pass.");
auto srcTarget = handle_cast<MetalRenderTarget>(mHandleMap, src);
auto srcTarget = handle_cast<MetalRenderTarget>(src);
// We always readPixels from the COLOR0 attachment.
MetalRenderTarget::Attachment color = srcTarget->getDrawColorAttachment(0);
id<MTLTexture> srcTexture = color.texture;
@@ -1039,8 +1040,8 @@ void MetalDriver::blit(TargetBufferFlags buffers,
mContext->currentRenderPassEncoder = nil;
}
auto srcTarget = handle_cast<MetalRenderTarget>(mHandleMap, src);
auto dstTarget = handle_cast<MetalRenderTarget>(mHandleMap, dst);
auto srcTarget = handle_cast<MetalRenderTarget>(src);
auto dstTarget = handle_cast<MetalRenderTarget>(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<HwRenderPrimitive> rph) {
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder != nullptr,
"Attempted to draw without a valid command encoder.");
auto primitive = handle_cast<MetalRenderPrimitive>(mHandleMap, rph);
auto program = handle_cast<MetalProgram>(mHandleMap, ps.program);
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
auto program = handle_cast<MetalProgram>(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<HwRenderPrimitive> rph)
if (binding >= SAMPLER_BINDING_COUNT) {
return;
}
const auto metalTexture = handle_const_cast<MetalTexture>(mHandleMap, sampler->t);
const auto metalTexture = handle_const_cast<MetalTexture>(sampler->t);
texturesToBind[binding] = metalTexture->swizzledTextureView ? metalTexture->swizzledTextureView
: metalTexture->texture;
@@ -1352,14 +1353,14 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph)
void MetalDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
"beginTimerQuery must be called outside of a render pass.");
auto* tq = handle_cast<MetalTimerQuery>(mHandleMap, tqh);
auto* tq = handle_cast<MetalTimerQuery>(tqh);
mContext->timerQueryImpl->beginTimeElapsedQuery(tq);
}
void MetalDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
"endTimerQuery must be called outside of a render pass.");
auto* tq = handle_cast<MetalTimerQuery>(mHandleMap, tqh);
auto* tq = handle_cast<MetalTimerQuery>(tqh);
mContext->timerQueryImpl->endTimeElapsedQuery(tq);
}
+5 -1
View File
@@ -34,6 +34,7 @@
#include <atomic>
#include <condition_variable>
#include <memory>
#include <type_traits>
#include <vector>
namespace filament {
@@ -258,7 +259,10 @@ private:
id<MTLTexture> 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<HwBase>);
class MetalFence : public HwFence, public HwSync {
public:
// MetalFence is special, as it gets constructed on the Filament thread. We must delay inserting