From 3c1ea07502f23aec747baeee633484939bc528bc Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 9 Jul 2020 10:39:22 -0700 Subject: [PATCH] Add Metal support for Texture::import (#2782) --- filament/backend/src/metal/MetalDriver.mm | 22 +++++++++++++++++- filament/backend/src/metal/MetalEnums.h | 14 +++++++++++ filament/backend/src/metal/MetalHandles.h | 6 +++++ filament/backend/src/metal/MetalHandles.mm | 10 ++++++++ filament/include/filament/Texture.h | 27 ++++++++++++++++++++++ 5 files changed, 78 insertions(+), 1 deletion(-) diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 02ce8dcbc1..eef7b13855 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -177,10 +177,30 @@ void MetalDriver::createTextureSwizzledR(Handle th, SamplerType targe // TODO: implement texture swizzle } -void MetalDriver::importTextureR(Handle th, intptr_t id, +void MetalDriver::importTextureR(Handle th, intptr_t i, SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage) { + id metalTexture = (id) CFBridgingRelease((void*) i); + ASSERT_PRECONDITION(metalTexture.width == width, + "Imported id width (%d) != Filament texture width (%d)", + metalTexture.width, width); + ASSERT_PRECONDITION(metalTexture.height == height, + "Imported id height (%d) != Filament texture height (%d)", + metalTexture.height, height); + ASSERT_PRECONDITION(metalTexture.mipmapLevelCount == levels, + "Imported id levels (%d) != Filament texture levels (%d)", + metalTexture.mipmapLevelCount, levels); + MTLPixelFormat filamentMetalFormat = getMetalFormat(format); + ASSERT_PRECONDITION(metalTexture.pixelFormat == filamentMetalFormat, + "Imported id format (%d) != Filament texture format (%d)", + metalTexture.pixelFormat, filamentMetalFormat); + MTLTextureType filamentMetalType = getMetalType(target); + 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, + width, height, depth, usage, metalTexture); } void MetalDriver::createSamplerGroupR(Handle sbh, size_t size) { diff --git a/filament/backend/src/metal/MetalEnums.h b/filament/backend/src/metal/MetalEnums.h index dc79b0b14c..b22a66067c 100644 --- a/filament/backend/src/metal/MetalEnums.h +++ b/filament/backend/src/metal/MetalEnums.h @@ -291,6 +291,20 @@ inline MTLPixelFormat getMetalFormat(TextureFormat format) noexcept { } } +constexpr inline MTLTextureType getMetalType(SamplerType target) { + switch (target) { + case SamplerType::SAMPLER_2D: + case SamplerType::SAMPLER_EXTERNAL: + return MTLTextureType2D; + case SamplerType::SAMPLER_2D_ARRAY: + return MTLTextureType2DArray; + case SamplerType::SAMPLER_CUBEMAP: + return MTLTextureTypeCube; + case SamplerType::SAMPLER_3D: + return MTLTextureType3D; + } +} + constexpr inline MTLBlendOperation getMetalBlendOperation(BlendEquation equation) noexcept { switch (equation) { case BlendEquation::ADD: return MTLBlendOperationAdd; diff --git a/filament/backend/src/metal/MetalHandles.h b/filament/backend/src/metal/MetalHandles.h index 5304aba7f0..48feec4088 100644 --- a/filament/backend/src/metal/MetalHandles.h +++ b/filament/backend/src/metal/MetalHandles.h @@ -121,6 +121,12 @@ struct MetalTexture : public HwTexture { MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage) noexcept; + + // Constructor for importing an id outside of Filament. + MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format, + uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, + id texture) noexcept; + ~MetalTexture(); void load2DImage(uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, diff --git a/filament/backend/src/metal/MetalHandles.mm b/filament/backend/src/metal/MetalHandles.mm index 9cae36b2e4..fe23f0a2cc 100644 --- a/filament/backend/src/metal/MetalHandles.mm +++ b/filament/backend/src/metal/MetalHandles.mm @@ -319,6 +319,16 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le } } +MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format, + uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, + id metalTexture) noexcept + : HwTexture(target, levels, samples, width, height, depth, format, usage), context(context), + externalImage(context), reshaper(format) { + texture = metalTexture; + minLod = 0; + maxLod = levels - 1; +} + MetalTexture::~MetalTexture() { externalImage.set(nullptr); } diff --git a/filament/include/filament/Texture.h b/filament/include/filament/Texture.h index 0eadeaa5ae..b51a4187e0 100644 --- a/filament/include/filament/Texture.h +++ b/filament/include/filament/Texture.h @@ -201,6 +201,33 @@ public: /* no user serviceable parts below */ + /** + * Specify a native texture to import as a Filament texture. + * + * The texture id is backend-specific: + * - OpenGL: GLuint texture ID + * - Metal: id + * + * With Metal, the id object should be cast to an intptr_t using + * CFBridgingRetain to transfer ownership to Filament. Filament will release ownership of + * the textue object when the Filament texture is destroyed. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + * id metalTexture = ... + * filamentTexture->import((intptr_t) CFBridgingRetain(metalTexture)); + * // free to release metalTexture + * + * // after using texture: + * engine->destroy(filamentTexture); // metalTexture is released + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @warning This method should be used as a last resort. This API is subject to change or + * removal. + * + * @param id a backend specific texture identifier + * + * @return This Builder, for chaining calls. + */ Builder& import(intptr_t id) noexcept; private: