Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

external textures are no longer restricted to SAMPLER_EXTERNAL #8323

Merged
merged 2 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions android/filament-android/src/main/cpp/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>Texture</code> instance.
* @param engine The {@link Engine} to associate this <code>Texture</code> with.
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 1 addition & 11 deletions filament/backend/include/private/backend/DriverAPI.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -399,17 +400,6 @@ DECL_DRIVER_API_N(update3DImage,
DECL_DRIVER_API_N(generateMipmaps,
backend::TextureHandle, th)

// Deprecated
DECL_DRIVER_API_N(setExternalImage,
backend::TextureHandle, th,
void*, image)

// Deprecated
DECL_DRIVER_API_N(setExternalImagePlane,
backend::TextureHandle, th,
void*, image,
uint32_t, plane)

DECL_DRIVER_API_N(setExternalStream,
backend::TextureHandle, th,
backend::StreamHandle, sh)
Expand Down
8 changes: 3 additions & 5 deletions filament/backend/src/metal/MetalDriver.mm
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,9 @@
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a));
}

void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image));
Expand Down Expand Up @@ -1191,10 +1193,6 @@
CVPixelBufferRetain(pixelBuffer);
}

void MetalDriver::setExternalImage(Handle<HwTexture> th, void* image) {}

void MetalDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {}

void MetalDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
}

Expand Down
6 changes: 0 additions & 6 deletions filament/backend/src/noop/NoopDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,6 @@ TimerQueryResult NoopDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64
return TimerQueryResult::ERROR;
}

void NoopDriver::setExternalImage(Handle<HwTexture> th, void* image) {
}

void NoopDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
}

void NoopDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
}

Expand Down
7 changes: 4 additions & 3 deletions filament/backend/src/opengl/GLDescriptorSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, Sampler> ||
std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
if constexpr (std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
Expand Down Expand Up @@ -285,7 +286,7 @@ void GLDescriptorSet::bind(
} else if constexpr (std::is_same_v<T, Sampler>) {
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);
Expand All @@ -296,7 +297,7 @@ void GLDescriptorSet::bind(
} else if constexpr (std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
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);
Expand All @@ -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));
Expand Down
12 changes: 9 additions & 3 deletions filament/backend/src/opengl/GLDescriptorSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<GLTextureRef> ref; // 4
Expand All @@ -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<GLTextureRef> ref; // 4
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions filament/backend/src/opengl/GLTexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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<TextureSwizzle, 4> swizzle{
TextureSwizzle::CHANNEL_0,
Expand Down
8 changes: 5 additions & 3 deletions filament/backend/src/opengl/OpenGLContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -761,15 +761,17 @@ 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);
});
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 {
Expand Down
68 changes: 41 additions & 27 deletions filament/backend/src/opengl/OpenGLDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -1052,17 +1052,49 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
CHECK_GL_ERROR(utils::slog.e)
}

void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage);
setExternalImage(th, image);
void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType target,
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image) {
DEBUG_MARKER()

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<GLTexture>(th, target, 1, 1, width, height, 1, format, usage);
assert_invariant(t);

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)) {
// the target and id can be reset each time
t->gl.target = t->externalTexture->target;
t->gl.id = t->externalTexture->id;
}
}

void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane) {
createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage);
setExternalImagePlane(th, image, plane);
// not relevant for the OpenGL backend
}

void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
Expand All @@ -1082,6 +1114,7 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> 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;
Expand Down Expand Up @@ -2774,25 +2807,6 @@ void OpenGLDriver::setupExternalImage(void* image) {
mPlatform.retainExternalImage(image);
}

void OpenGLDriver::setExternalImage(Handle<HwTexture> th, void* image) {
DEBUG_MARKER()
GLTexture* t = handle_cast<GLTexture*>(th);
assert_invariant(t);
assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL);

bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
if (mPlatform.setExternalImage(image, t->externalTexture)) {
// the target and id can be reset each time
t->gl.target = t->externalTexture->target;
t->gl.id = t->externalTexture->id;
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
}
}

void OpenGLDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
DEBUG_MARKER()
}

void OpenGLDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
auto& gl = mContext;
if (gl.ext.OES_EGL_image_external_essl3) {
Expand Down Expand Up @@ -3512,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);
Expand Down
12 changes: 7 additions & 5 deletions filament/backend/src/opengl/platforms/PlatformEGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<GLeglImageOES>(externalImage));
#endif
}

return true;
}

Expand Down
10 changes: 2 additions & 8 deletions filament/backend/src/vulkan/VulkanDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,8 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
texture.inc();
}

void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th,
backend::SamplerType target, backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) {
FVK_SYSTRACE_SCOPE();

Expand Down Expand Up @@ -1189,13 +1190,6 @@ TimerQueryResult VulkanDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint
return TimerQueryResult::AVAILABLE;
}

void VulkanDriver::setExternalImage(Handle<HwTexture> th, void* image) {

}

void VulkanDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
}

void VulkanDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
}

Expand Down
3 changes: 2 additions & 1 deletion filament/backend/test/test_RenderExternalImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ TEST_F(BackendTest, RenderExternalImage) {

api.setupExternalImage(pixBuffer);
backend::Handle<HwTexture> 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);
Expand Down
Loading
Loading