diff --git a/android/filament-android/src/main/cpp/Texture.cpp b/android/filament-android/src/main/cpp/Texture.cpp index ef778056c0e..ff3fd36d269 100644 --- a/android/filament-android/src/main/cpp/Texture.cpp +++ b/android/filament-android/src/main/cpp/Texture.cpp @@ -138,6 +138,13 @@ Java_com_google_android_filament_Texture_nBuilderImportTexture(JNIEnv*, jclass, builder->import((intptr_t)id); } +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_Texture_nBuilderExternal(JNIEnv*, jclass, jlong nativeBuilder) { + Texture::Builder *builder = (Texture::Builder *) nativeBuilder; + builder->external(); +} + extern "C" JNIEXPORT jlong JNICALL Java_com_google_android_filament_Texture_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder, jlong nativeEngine) { diff --git a/android/filament-android/src/main/java/com/google/android/filament/Texture.java b/android/filament-android/src/main/java/com/google/android/filament/Texture.java index 1cb732af13f..eaf81adc3cf 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Texture.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Texture.java @@ -800,6 +800,19 @@ public Builder importTexture(long id) { return this; } + /** + * Creates an external texture. The content must be set using setExternalImage(). + * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally + * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not + * validated. + * @return This Builder, for chaining calls. + */ + @NonNull + public Builder external() { + nBuilderExternal(mNativeBuilder); + return this; + } + /** * Creates a new Texture instance. * @param engine The {@link Engine} to associate this Texture with. @@ -1261,6 +1274,7 @@ void clearNativeObject() { private static native void nBuilderUsage(long nativeBuilder, int flags); private static native void nBuilderSwizzle(long nativeBuilder, int r, int g, int b, int a); private static native void nBuilderImportTexture(long nativeBuilder, long id); + private static native void nBuilderExternal(long nativeBuilder); private static native long nBuilderBuild(long nativeBuilder, long nativeEngine); private static native int nGetWidth(long nativeTexture, int level); diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 9aaf381fc00..6b951da975c 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -214,6 +214,7 @@ DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureViewSwizzle, backend::TextureSwizzle, a) DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage, + backend::SamplerType, target, backend::TextureFormat, format, uint32_t, width, uint32_t, height, diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 0972f3491e8..38b9b6e0d3b 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -482,7 +482,9 @@ mContext->textures.insert(construct_handle(th, *mContext, src, r, g, b, a)); } -void MetalDriver::createTextureExternalImageR(Handle th, backend::TextureFormat format, +void MetalDriver::createTextureExternalImageR(Handle th, + backend::SamplerType target, + backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) { mContext->textures.insert(construct_handle( th, *mContext, format, width, height, usage, (CVPixelBufferRef)image)); diff --git a/filament/backend/src/opengl/GLDescriptorSet.cpp b/filament/backend/src/opengl/GLDescriptorSet.cpp index 1584f6aff77..79c65d9a125 100644 --- a/filament/backend/src/opengl/GLDescriptorSet.cpp +++ b/filament/backend/src/opengl/GLDescriptorSet.cpp @@ -173,6 +173,7 @@ void GLDescriptorSet::update(OpenGLContext& gl, arg.target = t ? t->gl.target : 0; arg.id = t ? t->gl.id : 0; + arg.external = t ? t->gl.external : false; if constexpr (std::is_same_v || std::is_same_v) { if constexpr (std::is_same_v) { @@ -285,7 +286,7 @@ void GLDescriptorSet::bind( } else if constexpr (std::is_same_v) { GLuint const unit = p.getTextureUnit(set, binding); if (arg.target) { - gl.bindTexture(unit, arg.target, arg.id); + gl.bindTexture(unit, arg.target, arg.id, arg.external); gl.bindSampler(unit, arg.sampler); if (UTILS_UNLIKELY(arg.ref)) { updateTextureView(gl, handleAllocator, unit, arg); @@ -296,7 +297,7 @@ void GLDescriptorSet::bind( } else if constexpr (std::is_same_v) { GLuint const unit = p.getTextureUnit(set, binding); if (arg.target) { - gl.bindTexture(unit, arg.target, arg.id); + gl.bindTexture(unit, arg.target, arg.id, arg.external); gl.bindSampler(unit, arg.sampler); if (UTILS_UNLIKELY(arg.ref)) { updateTextureView(gl, handleAllocator, unit, arg); @@ -314,7 +315,7 @@ void GLDescriptorSet::bind( // in ES2 the sampler parameters need to be set on the texture itself GLuint const unit = p.getTextureUnit(set, binding); if (arg.target) { - gl.bindTexture(unit, arg.target, arg.id); + gl.bindTexture(unit, arg.target, arg.id, arg.external); SamplerParams const params = arg.params; glTexParameteri(arg.target, GL_TEXTURE_MIN_FILTER, (GLint)GLUtils::getTextureFilter(params.filterMin)); diff --git a/filament/backend/src/opengl/GLDescriptorSet.h b/filament/backend/src/opengl/GLDescriptorSet.h index 51ac2afd884..59b6b6ace57 100644 --- a/filament/backend/src/opengl/GLDescriptorSet.h +++ b/filament/backend/src/opengl/GLDescriptorSet.h @@ -111,7 +111,9 @@ struct GLDescriptorSet : public HwDescriptorSet { // A sampler descriptor struct Sampler { - GLenum target = 0; // 4 + uint16_t target; // 2 (GLenum) + bool external = false; // 1 + bool reserved = false; // 1 GLuint id = 0; // 4 GLuint sampler = 0; // 4 Handle ref; // 4 @@ -126,7 +128,9 @@ struct GLDescriptorSet : public HwDescriptorSet { }; struct SamplerWithAnisotropyWorkaround { - GLenum target = 0; // 4 + uint16_t target; // 2 (GLenum) + bool external = false; // 1 + bool reserved = false; // 1 GLuint id = 0; // 4 GLuint sampler = 0; // 4 Handle ref; // 4 @@ -143,7 +147,9 @@ struct GLDescriptorSet : public HwDescriptorSet { // A sampler descriptor for ES2 struct SamplerGLES2 { - GLenum target = 0; // 4 + uint16_t target; // 2 (GLenum) + bool external = false; // 1 + bool reserved = false; // 1 GLuint id = 0; // 4 SamplerParams params{}; // 4 float anisotropy = 1.0f; // 4 diff --git a/filament/backend/src/opengl/GLTexture.h b/filament/backend/src/opengl/GLTexture.h index 5d721d3c214..26784d15644 100644 --- a/filament/backend/src/opengl/GLTexture.h +++ b/filament/backend/src/opengl/GLTexture.h @@ -35,7 +35,7 @@ struct GLTextureRef { GLTextureRef() = default; // view reference counter uint16_t count = 1; - // current per-view values of the texture (in GL we can only have a single View active at + // Current per-view values of the texture (in GL we can only have a single View active at // a time, and this tracks that state). It's used to avoid unnecessarily change state. int8_t baseLevel = 127; int8_t maxLevel = -1; @@ -50,7 +50,7 @@ struct GLTextureRef { struct GLTexture : public HwTexture { using HwTexture::HwTexture; struct GL { - GL() noexcept : imported(false), sidecarSamples(1), reserved1(0) {} + GL() noexcept : imported(false), external(false), sidecarSamples(1), reserved1(0) {} GLuint id = 0; // texture or renderbuffer id GLenum target = 0; GLenum internalFormat = 0; @@ -62,7 +62,8 @@ struct GLTexture : public HwTexture { int8_t maxLevel = -1; uint8_t reserved0 = 0; bool imported : 1; - uint8_t sidecarSamples : 4; + bool external : 1; + uint8_t sidecarSamples : 3; uint8_t reserved1 : 3; std::array swizzle{ TextureSwizzle::CHANNEL_0, diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 39ceb346787..44354259121 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -153,7 +153,7 @@ class OpenGLContext final : public TimerQueryFactoryInterface { void pixelStore(GLenum, GLint) noexcept; inline void activeTexture(GLuint unit) noexcept; - inline void bindTexture(GLuint unit, GLuint target, GLuint texId) noexcept; + inline void bindTexture(GLuint unit, GLuint target, GLuint texId, bool external) noexcept; void unbindTexture(GLenum target, GLuint id) noexcept; void unbindTextureUnit(GLuint unit) noexcept; @@ -761,7 +761,9 @@ void OpenGLContext::bindBufferRange(GLenum target, GLuint index, GLuint buffer, #endif } -void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId) noexcept { +void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId, bool external) noexcept { + // another texture is bound to the same unit with a different target, + // unbind the texture from the current target update_state(state.textures.units[unit].target, target, [&]() { activeTexture(unit); glBindTexture(state.textures.units[unit].target, 0); @@ -769,7 +771,7 @@ void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId) noexce update_state(state.textures.units[unit].id, texId, [&]() { activeTexture(unit); glBindTexture(target, texId); - }, target == GL_TEXTURE_EXTERNAL_OES); + }, external); } void OpenGLContext::useProgram(GLuint program) noexcept { diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 7ee4f5a3abc..0052c275a39 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -402,7 +402,7 @@ void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index, void OpenGLDriver::bindTexture(GLuint unit, GLTexture const* t) noexcept { assert_invariant(t != nullptr); - mContext.bindTexture(unit, t->gl.target, t->gl.id); + mContext.bindTexture(unit, t->gl.target, t->gl.id, t->gl.external); } bool OpenGLDriver::useProgram(OpenGLProgram* p) noexcept { @@ -1052,14 +1052,36 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle th, Handle th, backend::TextureFormat format, - uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) { +void OpenGLDriver::createTextureExternalImageR(Handle th, SamplerType target, + TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image) { DEBUG_MARKER() - createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage); - GLTexture* t = handle_cast(th); + usage |= TextureUsage::SAMPLEABLE; + usage &= ~TextureUsage::UPLOADABLE; + + auto& gl = mContext; + GLenum internalFormat = getInternalFormat(format); + if (UTILS_UNLIKELY(gl.isES2())) { + // on ES2, format and internal format must match + // FIXME: handle compressed texture format + internalFormat = textureFormatToFormatAndType(format).first; + } + assert_invariant(internalFormat); + + GLTexture* const t = construct(th, target, 1, 1, width, height, 1, format, usage); assert_invariant(t); - assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL); + + t->externalTexture = mPlatform.createExternalImageTexture(); + if (t->externalTexture) { + t->gl.target = t->externalTexture->target; + t->gl.id = t->externalTexture->id; + // internalFormat actually depends on the external image, but it doesn't matter + // because it's not used anywhere for anything important. + t->gl.internalFormat = internalFormat; + t->gl.baseLevel = 0; + t->gl.maxLevel = 0; + t->gl.external = true; // forces bindTexture() call (they're never cached) + } bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); if (mPlatform.setExternalImage(image, t->externalTexture)) { @@ -1092,6 +1114,7 @@ void OpenGLDriver::importTextureR(Handle th, intptr_t id, switch (target) { case SamplerType::SAMPLER_EXTERNAL: t->gl.target = GL_TEXTURE_EXTERNAL_OES; + t->gl.external = true; // forces bindTexture() call (they're never cached) break; case SamplerType::SAMPLER_2D: t->gl.target = GL_TEXTURE_2D; @@ -3503,7 +3526,7 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) { auto& gl = mContext; gl.bindVertexArray(nullptr); for (int unit = OpenGLContext::DUMMY_TEXTURE_BINDING; unit >= 0; unit--) { - gl.bindTexture(unit, GL_TEXTURE_2D, 0); + gl.bindTexture(unit, GL_TEXTURE_2D, 0, false); } gl.disable(GL_CULL_FACE); gl.depthFunc(GL_LESS); diff --git a/filament/backend/src/opengl/platforms/PlatformEGL.cpp b/filament/backend/src/opengl/platforms/PlatformEGL.cpp index 38b8b9d5049..9e6b628f02b 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGL.cpp @@ -715,14 +715,16 @@ void PlatformEGL::destroyExternalImage(ExternalTexture* texture) noexcept { bool PlatformEGL::setExternalImage(void* externalImage, UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { - if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) { - assert_invariant(texture->target == GL_TEXTURE_EXTERNAL_OES); + + // OES_EGL_image_external_essl3 must be present if the target is TEXTURE_EXTERNAL_OES + // GL_OES_EGL_image must be present if TEXTURE_2D is used + +#if defined(GL_OES_EGL_image) || defined(GL_OES_EGL_image_external_essl3) // the texture is guaranteed to be bound here. -#ifdef GL_OES_EGL_image - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, + glEGLImageTargetTexture2DOES(texture->target, static_cast(externalImage)); #endif - } + return true; } diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 3e7238c1e56..26d3064ba99 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -543,7 +543,8 @@ void VulkanDriver::createTextureViewSwizzleR(Handle th, Handle th, backend::TextureFormat format, +void VulkanDriver::createTextureExternalImageR(Handle th, + backend::SamplerType target, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) { FVK_SYSTRACE_SCOPE(); diff --git a/filament/backend/test/test_RenderExternalImage.cpp b/filament/backend/test/test_RenderExternalImage.cpp index 414e9c414d9..643545a2bec 100644 --- a/filament/backend/test/test_RenderExternalImage.cpp +++ b/filament/backend/test/test_RenderExternalImage.cpp @@ -227,7 +227,8 @@ TEST_F(BackendTest, RenderExternalImage) { api.setupExternalImage(pixBuffer); backend::Handle texture = - api.createTextureExternalImage(TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer); + api.createTextureExternalImage(SamplerType::SAMPLER_EXTERNAL, + TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer); // We're now free to release the buffer. CVBufferRelease(pixBuffer); diff --git a/filament/include/filament/Texture.h b/filament/include/filament/Texture.h index b351c429435..6813b13e736 100644 --- a/filament/include/filament/Texture.h +++ b/filament/include/filament/Texture.h @@ -261,6 +261,18 @@ class UTILS_PUBLIC Texture : public FilamentAPI { */ Builder& import(intptr_t id) noexcept; + /** + * Creates an external texture. The content must be set using setExternalImage(). + * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally + * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not + * validated. + * + * If the Sampler is set to SAMPLER_EXTERNAL, external() is implied. + * + * @return + */ + Builder& external() noexcept; + private: friend class FTexture; }; @@ -395,7 +407,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { /** - * Specify the external image to associate with this Texture. Typically the external + * Specify the external image to associate with this Texture. Typically, the external * image is OS specific, and can be a video or camera frame. * There are many restrictions when using an external image as a texture, such as: * - only the level of detail (lod) 0 can be specified @@ -420,7 +432,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept; /** - * Specify the external image and plane to associate with this Texture. Typically the external + * Specify the external image and plane to associate with this Texture. Typically, the external * image is OS specific, and can be a video or camera frame. When using this method, the * external image must be a planar type (such as a YUV camera frame). The plane parameter * selects which image plane is bound to this texture. diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index 176907345b7..cff6d7e42a9 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -81,6 +81,7 @@ struct Texture::BuilderDetails { Usage mUsage = Usage::NONE; bool mHasBlitSrc = false; bool mTextureIsSwizzled = false; + bool mExternal = false; std::array mSwizzle = { Swizzle::CHANNEL_0, Swizzle::CHANNEL_1, Swizzle::CHANNEL_2, Swizzle::CHANNEL_3 }; @@ -136,6 +137,11 @@ Texture::Builder& Texture::Builder::import(intptr_t id) noexcept { return *this; } +Texture::Builder& Texture::Builder::external() noexcept { + mImpl->mExternal = true; + return *this; +} + Texture::Builder& Texture::Builder::swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept { mImpl->mTextureIsSwizzled = true; mImpl->mSwizzle = { r, g, b, a }; @@ -154,6 +160,11 @@ Texture* Texture::Builder::build(Engine& engine) { (isProtectedTexturesSupported && useProtectedMemory) || !useProtectedMemory) << "Texture is PROTECTED but protected textures are not supported"; + // SAMPLER_EXTERNAL implies imported. + if (mImpl->mTarget == SamplerType::SAMPLER_EXTERNAL) { + mImpl->mExternal = true; + } + uint8_t maxLevelCount; switch (mImpl->mTarget) { case SamplerType::SAMPLER_2D: @@ -174,7 +185,7 @@ Texture* Texture::Builder::build(Engine& engine) { mImpl->mUsage = TextureUsage::DEFAULT; if (mImpl->mLevels > 1 && (mImpl->mWidth > 1 || mImpl->mHeight > 1) && - mImpl->mTarget != SamplerType::SAMPLER_EXTERNAL) { + !mImpl->mExternal) { const bool formatMipmappable = downcast(engine).getDriverApi().isTextureFormatMipmappable(mImpl->mFormat); if (formatMipmappable) { @@ -243,9 +254,10 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) { mSwizzle = builder->mSwizzle; mTextureIsSwizzled = builder->mTextureIsSwizzled; mHasBlitSrc = builder->mHasBlitSrc; + mExternal = builder->mExternal; bool const isImported = builder->mImportedId != 0; - if (mTarget == SamplerType::SAMPLER_EXTERNAL && !isImported) { + if (mExternal && !isImported) { // mHandle and mHandleForSampling will be created in setExternalImage() // If this Texture is used for sampling before setExternalImage() is called, // we'll lazily create a 1x1 placeholder texture. @@ -318,8 +330,8 @@ void FTexture::setImage(FEngine& engine, size_t level, << "level=" << unsigned(level) << " is >= to levelCount=" << unsigned(mLevelCount) << "."; - FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_EXTERNAL) - << "Texture SamplerType::SAMPLER_EXTERNAL not supported for this operation."; + FILAMENT_CHECK_PRECONDITION(!mExternal) + << "External Texture not supported for this operation."; FILAMENT_CHECK_PRECONDITION(mSampleCount <= 1) << "Operation not supported with multisample (" << unsigned(mSampleCount) << ") texture."; @@ -454,15 +466,14 @@ void FTexture::setImage(FEngine& engine, size_t level, } void FTexture::setExternalImage(FEngine& engine, void* image) noexcept { - if (mTarget != Sampler::SAMPLER_EXTERNAL) { - return; - } + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; + // The call to setupExternalImage is synchronous, and allows the driver to take ownership of the // external image on this thread, if necessary. auto& api = engine.getDriverApi(); api.setupExternalImage(image); - auto texture = api.createTextureExternalImage(mFormat, mWidth, mHeight, mUsage, image); + auto texture = api.createTextureExternalImage(mTarget, mFormat, mWidth, mHeight, mUsage, image); if (mTextureIsSwizzled) { auto const& s = mSwizzle; @@ -475,9 +486,8 @@ void FTexture::setExternalImage(FEngine& engine, void* image) noexcept { } void FTexture::setExternalImage(FEngine& engine, void* image, size_t plane) noexcept { - if (mTarget != Sampler::SAMPLER_EXTERNAL) { - return; - } + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; + // The call to setupExternalImage is synchronous, and allows the driver to take ownership of // the external image on this thread, if necessary. auto& api = engine.getDriverApi(); @@ -497,9 +507,7 @@ void FTexture::setExternalImage(FEngine& engine, void* image, size_t plane) noex } void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept { - if (mTarget != Sampler::SAMPLER_EXTERNAL) { - return; - } + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; auto& api = engine.getDriverApi(); auto texture = api.createTexture( @@ -524,7 +532,7 @@ void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept { } void FTexture::generateMipmaps(FEngine& engine) const noexcept { - FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_EXTERNAL) + FILAMENT_CHECK_PRECONDITION(!mExternal) << "External Textures are not mipmappable."; FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_3D) @@ -544,12 +552,11 @@ void FTexture::generateMipmaps(FEngine& engine) const noexcept { } bool FTexture::textureHandleCanMutate() const noexcept { - return (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) || - mTarget == SamplerType::SAMPLER_EXTERNAL; + return (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) || mExternal; } void FTexture::updateLodRange(uint8_t baseLevel, uint8_t levelCount) noexcept { - assert_invariant(mTarget != SamplerType::SAMPLER_EXTERNAL); + assert_invariant(!mExternal); if (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) { auto& range = mLodRange; uint8_t const last = int8_t(baseLevel + levelCount); @@ -601,7 +608,7 @@ backend::Handle FTexture::createPlaceholderTexture( } backend::Handle FTexture::getHwHandleForSampling() const noexcept { - if (UTILS_UNLIKELY(mTarget == SamplerType::SAMPLER_EXTERNAL && !mHandleForSampling)) { + if (UTILS_UNLIKELY(mExternal && !mHandleForSampling)) { return setHandleForSampling(createPlaceholderTexture(*mDriver)); } auto const& range = mLodRange; @@ -610,9 +617,10 @@ backend::Handle FTexture::getHwHandleForSampling() const noe if (UTILS_UNLIKELY(lodRangeChanged)) { activeRange = range; if (range.empty() || hasAllLods(range)) { - setHandleForSampling(mHandle); + std::ignore = setHandleForSampling(mHandle); } else { - setHandleForSampling(mDriver->createTextureView(mHandle, range.first, range.size())); + std::ignore = setHandleForSampling(mDriver->createTextureView( + mHandle, range.first, range.size())); } } return mHandleForSampling; diff --git a/filament/src/details/Texture.h b/filament/src/details/Texture.h index 6bf04dae4ac..2131988c84c 100644 --- a/filament/src/details/Texture.h +++ b/filament/src/details/Texture.h @@ -173,7 +173,8 @@ class FTexture : public Texture { // Indicates whether the user has set the TextureUsage::BLIT_SRC usage. This will be used to // temporarily validate whether this texture can be used for readPixels. bool mHasBlitSrc = false; - // there is 5 bytes of padding here + bool mExternal = false; + // there is 4 bytes of padding here FStream* mStream = nullptr; // only needed for streaming textures }; diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index c45c50b35b1..1ca1b97c93f 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1489,6 +1489,8 @@ class_("Texture$Builder") return &builder->sampler(target); }) .BUILDER_FUNCTION("format", TexBuilder, (TexBuilder* builder, Texture::InternalFormat fmt), { return &builder->format(fmt); }) + .BUILDER_FUNCTION("external", TexBuilder, (TexBuilder* builder), { + return &builder->external(); }) // This takes a bitfield that can be composed by or'ing constants. // - JS clients should use the value member, as in: "Texture$Usage.SAMPLEABLE.value".