From 61fb5a588e98b13d085b72e699f2fec58dfcf493 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 15 Jul 2022 10:39:23 -0700 Subject: [PATCH] rework backend texture upload APIs The main goal is to allow more flexibility, allow cubemap arrays in the future and better match vk and metal apis. Main changes: - remove updateCubeImage - remove update2DImage - update3DImage is now the only texture upload backend API cubemaps are now treated just like a 2D array of 6 layers. For this reason, Texture::setImage(..., FaceOFfsets) is deprecated. Additionally, the 2D versions of Texture::setImage() become inline helpers. A side effect of this change is that it is now possible to update only a single face of a cubemap, but also a region of a face (or faces). --- RELEASE_NOTES.md | 2 + .../filament-android/src/main/cpp/Texture.cpp | 69 +-------- .../com/google/android/filament/Texture.java | 36 +---- .../backend/include/backend/DriverEnums.h | 45 ------ .../include/private/backend/DriverAPI.inc | 15 -- filament/backend/src/metal/MetalDriver.mm | 18 --- filament/backend/src/metal/MetalHandles.h | 7 +- filament/backend/src/metal/MetalHandles.mm | 26 +--- filament/backend/src/noop/NoopDriver.cpp | 11 -- filament/backend/src/opengl/OpenGLDriver.cpp | 100 +++++------- filament/backend/src/opengl/OpenGLDriver.h | 4 +- filament/backend/src/ostream.cpp | 10 -- filament/backend/src/vulkan/VulkanDriver.cpp | 17 +-- filament/backend/src/vulkan/VulkanTexture.cpp | 52 +------ filament/backend/src/vulkan/VulkanTexture.h | 4 - filament/backend/test/test_Blit.cpp | 6 +- filament/backend/test/test_FeedbackLoops.cpp | 2 +- filament/backend/test/test_LoadImage.cpp | 16 +- filament/include/filament/Texture.h | 142 +++++++++++------- filament/src/Froxelizer.cpp | 4 +- filament/src/PostProcessManager.cpp | 22 +-- filament/src/Texture.cpp | 12 -- filament/src/details/Engine.cpp | 26 +--- filament/src/details/Engine.h | 2 - filament/src/details/Texture.cpp | 125 +++++---------- filament/src/details/Texture.h | 7 +- libs/filamentapp/include/filamentapp/IBL.h | 2 +- libs/filamentapp/src/IBL.cpp | 15 +- libs/ktxreader/src/Ktx1Reader.cpp | 23 +-- 29 files changed, 233 insertions(+), 587 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 1a318422b5..5008ec45f1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,6 +5,8 @@ A new header is inserted each time a *tag* is created. ## main branch +- backend: streamline texture upload APIs [⚠️ **API Change**] + ## v1.25.3 - engine: Fix Adreno gpu crash introduced by gpu morph target change diff --git a/android/filament-android/src/main/cpp/Texture.cpp b/android/filament-android/src/main/cpp/Texture.cpp index 56f4927bf4..bb5be8fd43 100644 --- a/android/filament-android/src/main/cpp/Texture.cpp +++ b/android/filament-android/src/main/cpp/Texture.cpp @@ -188,69 +188,6 @@ Java_com_google_android_filament_Texture_nGetInternalFormat(JNIEnv*, jclass, return (jint) texture->getFormat(); } -extern "C" JNIEXPORT jint JNICALL -Java_com_google_android_filament_Texture_nSetImage(JNIEnv* env, jclass, jlong nativeTexture, - jlong nativeEngine, jint level, jint xoffset, jint yoffset, jint width, jint height, - jobject storage, jint remaining, - jint left, jint top, jint type, jint alignment, - jint stride, jint format, - jobject handler, jobject runnable) { - Texture* texture = (Texture*) nativeTexture; - Engine* engine = (Engine*) nativeEngine; - - size_t sizeInBytes = getTextureDataSize(texture, (size_t) level, (Texture::Format) format, - (Texture::Type) type, (size_t) stride, (size_t) height, (size_t) alignment); - - AutoBuffer nioBuffer(env, storage, 0); - if (sizeInBytes > (size_t(remaining) << nioBuffer.getShift())) { - // BufferOverflowException - return -1; - } - - void *buffer = nioBuffer.getData(); - auto *callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer)); - - Texture::PixelBufferDescriptor desc(buffer, sizeInBytes, (backend::PixelDataFormat) format, - (backend::PixelDataType) type, (uint8_t) alignment, (uint32_t) left, (uint32_t) top, - (uint32_t) stride, - callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback); - - texture->setImage(*engine, (size_t) level, (uint32_t) xoffset, (uint32_t) yoffset, - (uint32_t) width, (uint32_t) height, std::move(desc)); - - return 0; -} - -extern "C" JNIEXPORT jint JNICALL -Java_com_google_android_filament_Texture_nSetImageCompressed(JNIEnv *env, jclass, - jlong nativeTexture, jlong nativeEngine, jint level, jint xoffset, jint yoffset, - jint width, jint height, jobject storage, jint remaining, - jint, jint, jint, jint, jint compressedSizeInBytes, jint compressedFormat, - jobject handler, jobject runnable) { - Texture *texture = (Texture *) nativeTexture; - Engine *engine = (Engine *) nativeEngine; - - size_t sizeInBytes = (size_t) compressedSizeInBytes; - - AutoBuffer nioBuffer(env, storage, 0); - if (sizeInBytes > (size_t(remaining) << nioBuffer.getShift())) { - // BufferOverflowException - return -1; - } - - void *buffer = nioBuffer.getData(); - auto *callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer)); - - Texture::PixelBufferDescriptor desc(buffer, sizeInBytes, - (backend::CompressedPixelDataType) compressedFormat, (uint32_t) compressedSizeInBytes, - callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback); - - texture->setImage(*engine, (size_t) level, (uint32_t) xoffset, (uint32_t) yoffset, - (uint32_t) width, (uint32_t) height, std::move(desc)); - - return 0; -} - extern "C" JNIEXPORT jint JNICALL Java_com_google_android_filament_Texture_nSetImage3D(JNIEnv* env, jclass, jlong nativeTexture, jlong nativeEngine, jint level, @@ -353,7 +290,10 @@ Java_com_google_android_filament_Texture_nSetImageCubemap(JNIEnv *env, jclass, (uint32_t) stride, callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" texture->setImage(*engine, (size_t) level, std::move(desc), faceOffsets); +#pragma clang diagnostic pop return 0; } @@ -388,7 +328,10 @@ Java_com_google_android_filament_Texture_nSetImageCubemapCompressed(JNIEnv *env, (backend::CompressedPixelDataType) compressedFormat, (uint32_t) compressedSizeInBytes, callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" texture->setImage(*engine, (size_t) level, std::move(desc), faceOffsets); +#pragma clang diagnostic pop return 0; } 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 972dd4077c..03391451fd 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 @@ -912,7 +912,7 @@ public class Texture { public void setImage(@NonNull Engine engine, @IntRange(from = 0) int level, @NonNull PixelBufferDescriptor buffer) { - setImage(engine, level, 0, 0, getWidth(level), getHeight(level), buffer); + setImage(engine, level, 0, 0, 0, getWidth(level), getHeight(level), 1, buffer); } @@ -947,25 +947,7 @@ public class Texture { @IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset, @IntRange(from = 0) int width, @IntRange(from = 0) int height, @NonNull PixelBufferDescriptor buffer) { - int result; - if (buffer.type == COMPRESSED) { - result = nSetImageCompressed(getNativeObject(), engine.getNativeObject(), level, - xoffset, yoffset, width, height, - buffer.storage, buffer.storage.remaining(), - buffer.left, buffer.top, buffer.type.ordinal(), buffer.alignment, - buffer.compressedSizeInBytes, buffer.compressedFormat.ordinal(), - buffer.handler, buffer.callback); - } else { - result = nSetImage(getNativeObject(), engine.getNativeObject(), level, - xoffset, yoffset, width, height, - buffer.storage, buffer.storage.remaining(), - buffer.left, buffer.top, buffer.type.ordinal(), buffer.alignment, - buffer.stride, buffer.format.ordinal(), - buffer.handler, buffer.callback); - } - if (result < 0) { - throw new BufferOverflowException(); - } + setImage(engine, level, xoffset, yoffset, 0, width, height, 1, buffer); } /** @@ -1046,7 +1028,9 @@ public class Texture { * * @see Builder#sampler * @see PixelBufferDescriptor + * @deprecated use {@link #setImage(Engine, int, int, int, int, int, int, int, PixelBufferDescriptor)} */ + @Deprecated public void setImage(@NonNull Engine engine, @IntRange(from = 0) int level, @NonNull PixelBufferDescriptor buffer, @NonNull @Size(min = 6) int[] faceOffsetsInBytes) { @@ -1258,18 +1242,6 @@ public class Texture { private static native int nGetTarget(long nativeTexture); private static native int nGetInternalFormat(long nativeTexture); - private static native int nSetImage(long nativeTexture, long nativeEngine, - int level, int xoffset, int yoffset, int width, int height, - Buffer storage, int remaining, int left, int top, int type, int alignment, - int stride, int format, - Object handler, Runnable callback); - - private static native int nSetImageCompressed(long nativeTexture, long nativeEngine, - int level, int xoffset, int yoffset, int width, int height, - Buffer storage, int remaining, int left, int top, int type, int alignment, - int compressedSizeInBytes, int compressedFormat, - Object handler, Runnable callback); - private static native int nSetImage3D(long nativeTexture, long nativeEngine, int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, Buffer storage, int remaining, int left, int top, int type, int alignment, diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index 7cd0ccb834..275a063090 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -642,50 +642,6 @@ inline constexpr int operator +(TextureCubemapFace rhs) noexcept { return int(rhs); } -//! Face offsets for all faces of a cubemap -struct FaceOffsets { - using size_type = size_t; - union { - struct { - size_type px; //!< +x face offset in bytes - size_type nx; //!< -x face offset in bytes - size_type py; //!< +y face offset in bytes - size_type ny; //!< -y face offset in bytes - size_type pz; //!< +z face offset in bytes - size_type nz; //!< -z face offset in bytes - }; - size_type offsets[6]; - }; - size_type operator[](size_t n) const noexcept { return offsets[n]; } - size_type& operator[](size_t n) { return offsets[n]; } - FaceOffsets() noexcept = default; - explicit FaceOffsets(size_type faceSize) noexcept { - px = faceSize * 0; - nx = faceSize * 1; - py = faceSize * 2; - ny = faceSize * 3; - pz = faceSize * 4; - nz = faceSize * 5; - } - FaceOffsets(const FaceOffsets& rhs) noexcept { - px = rhs.px; - nx = rhs.nx; - py = rhs.py; - ny = rhs.ny; - pz = rhs.pz; - nz = rhs.nz; - } - FaceOffsets& operator=(const FaceOffsets& rhs) noexcept { - px = rhs.px; - nx = rhs.nx; - py = rhs.py; - ny = rhs.ny; - pz = rhs.pz; - nz = rhs.nz; - return *this; - } -}; - //! Sampler Wrap mode enum class SamplerWrapMode : uint8_t { CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity. @@ -1063,7 +1019,6 @@ utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::Textu utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferObjectBinding binding); utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureSwizzle swizzle); utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::AttributeArray& type); -utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::FaceOffsets& type); utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PolygonOffset& po); utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RasterState& rs); utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RenderPassParams& b); diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 3ef00e5889..369671c002 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -337,15 +337,6 @@ DECL_DRIVER_API_N(updateSamplerGroup, backend::SamplerGroupHandle, ubh, backend::SamplerGroup&&, samplerGroup) -DECL_DRIVER_API_N(update2DImage, - backend::TextureHandle, th, - uint32_t, level, - uint32_t, xoffset, - uint32_t, yoffset, - uint32_t, width, - uint32_t, height, - backend::PixelBufferDescriptor&&, data) - DECL_DRIVER_API_N(setMinMaxLevels, backend::TextureHandle, th, uint32_t, minLevel, @@ -362,12 +353,6 @@ DECL_DRIVER_API_N(update3DImage, uint32_t, depth, backend::PixelBufferDescriptor&&, data) -DECL_DRIVER_API_N(updateCubeImage, - backend::TextureHandle, th, - uint32_t, level, - backend::PixelBufferDescriptor&&, data, - backend::FaceOffsets, faceOffsets) - DECL_DRIVER_API_N(generateMipmaps, backend::TextureHandle, th) diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index be4073d80a..d5caddb1d1 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -734,15 +734,6 @@ void MetalDriver::setVertexBufferObject(Handle vbh, uint32_t ind vertexBuffer->buffers[index] = bufferObject->getBuffer(); } -void MetalDriver::update2DImage(Handle th, uint32_t level, uint32_t xoffset, - 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(th); - tex->loadImage(level, MTLRegionMake2D(xoffset, yoffset, width, height), data); - scheduleDestroy(std::move(data)); -} - void MetalDriver::setMinMaxLevels(Handle th, uint32_t minLevel, uint32_t maxLevel) { } @@ -757,15 +748,6 @@ void MetalDriver::update3DImage(Handle th, uint32_t level, scheduleDestroy(std::move(data)); } -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(th); - tex->loadCubeImage(faceOffsets, level, data); - scheduleDestroy(std::move(data)); -} - void MetalDriver::setupExternalImage(void* image) { // This is called when passing in a CVPixelBuffer as either an external image or swap chain. // Here we take ownership of the passed in buffer. It will be released the next time diff --git a/filament/backend/src/metal/MetalHandles.h b/filament/backend/src/metal/MetalHandles.h index 64692c7c4f..b2cc475875 100644 --- a/filament/backend/src/metal/MetalHandles.h +++ b/filament/backend/src/metal/MetalHandles.h @@ -198,12 +198,11 @@ struct MetalTexture : public HwTexture { ~MetalTexture(); void loadImage(uint32_t level, MTLRegion region, PixelBufferDescriptor& p) noexcept; - void loadCubeImage(const FaceOffsets& faceOffsets, int miplevel, PixelBufferDescriptor& p); void loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice, - PixelBufferDescriptor& data) noexcept; - void loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor& data, + PixelBufferDescriptor const& data) noexcept; + void loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor const& data, const PixelBufferShape& shape); - void loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor& data, + void loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region, PixelBufferDescriptor const& data, const PixelBufferShape& shape); void updateLodRange(uint32_t level); diff --git a/filament/backend/src/metal/MetalHandles.mm b/filament/backend/src/metal/MetalHandles.mm index dffbdf2801..dd0bb88143 100644 --- a/filament/backend/src/metal/MetalHandles.mm +++ b/filament/backend/src/metal/MetalHandles.mm @@ -641,6 +641,7 @@ void MetalTexture::loadImage(uint32_t level, MTLRegion region, PixelBufferDescri break; } + case SamplerType::SAMPLER_CUBEMAP: case SamplerType::SAMPLER_2D_ARRAY: { // Metal uses 'slice' (not z offset) to index into individual layers of a texture array. const uint32_t slice = region.origin.z; @@ -659,7 +660,6 @@ void MetalTexture::loadImage(uint32_t level, MTLRegion region, PixelBufferDescri break; } - case SamplerType::SAMPLER_CUBEMAP: case SamplerType::SAMPLER_EXTERNAL: { assert_invariant(false); } @@ -668,26 +668,8 @@ void MetalTexture::loadImage(uint32_t level, MTLRegion region, PixelBufferDescri updateLodRange(level); } -void MetalTexture::loadCubeImage(const FaceOffsets& faceOffsets, int miplevel, - PixelBufferDescriptor& p) { - PixelBufferDescriptor* data = &p; - PixelBufferDescriptor reshapedData; - if(reshape(p, reshapedData)) { - data = &reshapedData; - } - - const NSUInteger faceWidth = width >> miplevel; - - for (NSUInteger slice = 0; slice < 6; slice++) { - FaceOffsets::size_type faceOffset = faceOffsets.offsets[slice]; - loadSlice(miplevel, MTLRegionMake2D(0, 0, faceWidth, faceWidth), faceOffset, slice, *data); - } - - updateLodRange((uint32_t) miplevel); -} - void MetalTexture::loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice, - PixelBufferDescriptor& data) noexcept { + PixelBufferDescriptor const& data) noexcept { const PixelBufferShape shape = PixelBufferShape::compute(data, format, region.size, byteOffset); ASSERT_PRECONDITION(data.size >= shape.totalBytes, @@ -722,7 +704,7 @@ void MetalTexture::loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffs } void MetalTexture::loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion region, - PixelBufferDescriptor& data, const PixelBufferShape& shape) { + PixelBufferDescriptor const& data, const PixelBufferShape& shape) { const size_t stagingBufferSize = shape.totalBytes; auto entry = context.bufferPool->acquireBuffer(stagingBufferSize); memcpy(entry->buffer.contents, @@ -750,7 +732,7 @@ void MetalTexture::loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion } void MetalTexture::loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region, - PixelBufferDescriptor& data, const PixelBufferShape& shape) { + PixelBufferDescriptor const& data, const PixelBufferShape& shape) { MTLPixelFormat stagingPixelFormat = getMetalFormat(data.format, data.type); MTLTextureDescriptor* descriptor = [MTLTextureDescriptor new]; descriptor.textureType = region.size.depth == 1 ? MTLTextureType2D : MTLTextureType3D; diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index d328b422f0..f57147e34c 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -207,12 +207,6 @@ void NoopDriver::setVertexBufferObject(Handle vbh, uint32_t inde Handle boh) { } -void NoopDriver::update2DImage(Handle th, - uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, - PixelBufferDescriptor&& data) { - scheduleDestroy(std::move(data)); -} - void NoopDriver::setMinMaxLevels(Handle th, uint32_t minLevel, uint32_t maxLevel) { } @@ -223,11 +217,6 @@ void NoopDriver::update3DImage(Handle th, scheduleDestroy(std::move(data)); } -void NoopDriver::updateCubeImage(Handle th, uint32_t level, - PixelBufferDescriptor&& data, FaceOffsets faceOffsets) { - scheduleDestroy(std::move(data)); -} - void NoopDriver::setupExternalImage(void* image) { } diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 85eeab225f..624f990d35 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -1753,21 +1753,6 @@ void OpenGLDriver::updateSamplerGroup(Handle sbh, *sb->sb = std::move(samplerGroup); // NOLINT(performance-move-const-arg) } -void OpenGLDriver::update2DImage(Handle th, - uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, - PixelBufferDescriptor&& data) { - DEBUG_MARKER() - - GLTexture* t = handle_cast(th); - if (data.type == PixelDataType::COMPRESSED) { - setCompressedTextureData(t, - level, xoffset, yoffset, 0, width, height, 1, std::move(data), nullptr); - } else { - setTextureData(t, - level, xoffset, yoffset, 0, width, height, 1, std::move(data), nullptr); - } -} - void OpenGLDriver::setMinMaxLevels(Handle th, uint32_t minLevel, uint32_t maxLevel) { DEBUG_MARKER() auto& gl = mContext; @@ -1795,24 +1780,10 @@ void OpenGLDriver::update3DImage(Handle th, GLTexture* t = handle_cast(th); if (data.type == PixelDataType::COMPRESSED) { setCompressedTextureData(t, - level, xoffset, yoffset, zoffset, width, height, depth, std::move(data), nullptr); + level, xoffset, yoffset, zoffset, width, height, depth, std::move(data)); } else { setTextureData(t, - level, xoffset, yoffset, zoffset, width, height, depth, std::move(data), nullptr); - } -} - -void OpenGLDriver::updateCubeImage(Handle th, uint32_t level, - PixelBufferDescriptor&& data, FaceOffsets faceOffsets) { - DEBUG_MARKER() - - GLTexture* t = handle_cast(th); - auto width = std::max(1u, t->width >> level); - auto height = std::max(1u, t->height >> level); - if (data.type == PixelDataType::COMPRESSED) { - setCompressedTextureData(t, level, 0, 0, 0, width, height, 0, std::move(data), &faceOffsets); - } else { - setTextureData(t, level, 0, 0, 0, width, height, 0, std::move(data), &faceOffsets); + level, xoffset, yoffset, zoffset, width, height, depth, std::move(data)); } } @@ -1842,11 +1813,10 @@ bool OpenGLDriver::canGenerateMipmaps() { return true; } -void OpenGLDriver::setTextureData(GLTexture* t, - uint32_t level, +void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, - PixelBufferDescriptor&& p, FaceOffsets const* faceOffsets) { + PixelBufferDescriptor&& p) { auto& gl = mContext; assert_invariant(xoffset + width <= std::max(1u, t->width >> level)); @@ -1861,10 +1831,10 @@ void OpenGLDriver::setTextureData(GLTexture* t, GLenum glFormat = getFormat(p.format); GLenum glType = getType(p.type); - gl.pixelStore(GL_UNPACK_ROW_LENGTH, p.stride); - gl.pixelStore(GL_UNPACK_ALIGNMENT, p.alignment); - gl.pixelStore(GL_UNPACK_SKIP_PIXELS, p.left); - gl.pixelStore(GL_UNPACK_SKIP_ROWS, p.top); + gl.pixelStore(GL_UNPACK_ROW_LENGTH, GLint(p.stride)); + gl.pixelStore(GL_UNPACK_ALIGNMENT, GLint(p.alignment)); + gl.pixelStore(GL_UNPACK_SKIP_PIXELS, GLint(p.left)); + gl.pixelStore(GL_UNPACK_SKIP_ROWS, GLint(p.top)); switch (t->target) { case SamplerType::SAMPLER_EXTERNAL: @@ -1878,7 +1848,7 @@ void OpenGLDriver::setTextureData(GLTexture* t, assert_invariant(t->gl.target == GL_TEXTURE_2D); glTexSubImage2D(t->gl.target, GLint(level), GLint(xoffset), GLint(yoffset), - width, height, glFormat, glType, p.buffer); + GLsizei(width), GLsizei(height), glFormat, glType, p.buffer); break; case SamplerType::SAMPLER_3D: assert_invariant(zoffset + depth <= std::max(1u, t->depth >> level)); @@ -1887,7 +1857,7 @@ void OpenGLDriver::setTextureData(GLTexture* t, assert_invariant(t->gl.target == GL_TEXTURE_3D); glTexSubImage3D(t->gl.target, GLint(level), GLint(xoffset), GLint(yoffset), GLint(zoffset), - width, height, depth, glFormat, glType, p.buffer); + GLsizei(width), GLsizei(height), GLsizei(depth), glFormat, glType, p.buffer); break; case SamplerType::SAMPLER_2D_ARRAY: assert_invariant(zoffset + depth <= t->depth); @@ -1897,19 +1867,25 @@ void OpenGLDriver::setTextureData(GLTexture* t, assert_invariant(t->gl.target == GL_TEXTURE_2D_ARRAY); glTexSubImage3D(t->gl.target, GLint(level), GLint(xoffset), GLint(yoffset), GLint(zoffset), - width, height, depth, glFormat, glType, p.buffer); + GLsizei(width), GLsizei(height), GLsizei(depth), glFormat, glType, p.buffer); break; case SamplerType::SAMPLER_CUBEMAP: { assert_invariant(t->gl.target == GL_TEXTURE_CUBE_MAP); bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t); gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1); - FaceOffsets const& offsets = *faceOffsets; + + assert_invariant(width == height); + const size_t faceSize = PixelBufferDescriptor::computeDataSize( + p.format, p.type, p.stride ? p.stride : width, height, p.alignment); + + assert_invariant(zoffset + depth <= 6); + UTILS_NOUNROLL - for (size_t face = 0; face < 6; face++) { - GLenum target = getCubemapTarget(face); - glTexSubImage2D(target, GLint(level), 0, 0, - width, height, glFormat, glType, - static_cast(p.buffer) + offsets[face]); + for (size_t face = 0; face < depth; face++) { + GLenum target = getCubemapTarget(zoffset + face); + glTexSubImage2D(target, GLint(level), GLint(xoffset), GLint(yoffset), + GLsizei(width), GLsizei(height), glFormat, glType, + static_cast(p.buffer) + faceSize * face); } break; } @@ -1932,10 +1908,10 @@ void OpenGLDriver::setTextureData(GLTexture* t, CHECK_GL_ERROR(utils::slog.e) } -void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level, +void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, - PixelBufferDescriptor&& p, FaceOffsets const* faceOffsets) { + PixelBufferDescriptor&& p) { auto& gl = mContext; assert_invariant(xoffset + width <= std::max(1u, t->width >> level)); @@ -1966,7 +1942,8 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level, assert_invariant(t->gl.target == GL_TEXTURE_2D); glCompressedTexSubImage2D(t->gl.target, GLint(level), GLint(xoffset), GLint(yoffset), - width, height, t->gl.internalFormat, imageSize, p.buffer); + GLsizei(width), GLsizei(height), + t->gl.internalFormat, imageSize, p.buffer); break; case SamplerType::SAMPLER_3D: bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t); @@ -1974,26 +1951,31 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level, assert_invariant(t->gl.target == GL_TEXTURE_3D); glCompressedTexSubImage3D(t->gl.target, GLint(level), GLint(xoffset), GLint(yoffset), GLint(zoffset), - width, height, depth, t->gl.internalFormat, imageSize, p.buffer); + GLsizei(width), GLsizei(height), GLsizei(depth), + t->gl.internalFormat, imageSize, p.buffer); break; case SamplerType::SAMPLER_2D_ARRAY: assert_invariant(t->gl.target == GL_TEXTURE_2D_ARRAY); glCompressedTexSubImage3D(t->gl.target, GLint(level), GLint(xoffset), GLint(yoffset), GLint(zoffset), - width, height, depth, t->gl.internalFormat, imageSize, p.buffer); + GLsizei(width), GLsizei(height), GLsizei(depth), + t->gl.internalFormat, imageSize, p.buffer); break; case SamplerType::SAMPLER_CUBEMAP: { - assert_invariant(faceOffsets); assert_invariant(t->gl.target == GL_TEXTURE_CUBE_MAP); bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t); gl.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1); - FaceOffsets const& offsets = *faceOffsets; + + assert_invariant(width == height); + const size_t faceSize = PixelBufferDescriptor::computeDataSize( + p.format, p.type, p.stride ? p.stride : width, height, p.alignment); + UTILS_NOUNROLL - for (size_t face = 0; face < 6; face++) { - GLenum target = getCubemapTarget(face); - glCompressedTexSubImage2D(target, GLint(level), 0, 0, - width, height, t->gl.internalFormat, - imageSize, static_cast(p.buffer) + offsets[face]); + for (size_t face = 0; face < depth; face++) { + GLenum target = getCubemapTarget(zoffset + face); + glCompressedTexSubImage2D(target, GLint(level), GLint(xoffset), GLint(yoffset), + GLsizei(width), GLsizei(height), t->gl.internalFormat, + imageSize, static_cast(p.buffer) + faceSize * face); } break; } diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index cbb21226fe..2b8df946a1 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -283,13 +283,13 @@ private: uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, - PixelBufferDescriptor&& data, FaceOffsets const* faceOffsets); + PixelBufferDescriptor&& p); void setCompressedTextureData(GLTexture* t, uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, - PixelBufferDescriptor&& data, FaceOffsets const* faceOffsets); + PixelBufferDescriptor&& p); void renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width, uint32_t height, uint8_t samples) const noexcept; diff --git a/filament/backend/src/ostream.cpp b/filament/backend/src/ostream.cpp index 7a4f317be6..148138a852 100644 --- a/filament/backend/src/ostream.cpp +++ b/filament/backend/src/ostream.cpp @@ -401,16 +401,6 @@ io::ostream& operator<<(io::ostream& out, const AttributeArray& type) { return out << "AttributeArray[" << type.max_size() << "]{}"; } -io::ostream& operator<<(io::ostream& out, const FaceOffsets& type) { - return out << "FaceOffsets{" - << type[0] << ", " - << type[1] << ", " - << type[2] << ", " - << type[3] << ", " - << type[4] << ", " - << type[5] << "}"; -} - io::ostream& operator<<(io::ostream& out, const RasterState& rs) { // TODO: implement decoding of enums return out << "RasterState{" diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 717346a5dc..312d3ac6d4 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -937,14 +937,6 @@ void VulkanDriver::resetBufferObject(Handle boh) { // This is only useful if updateBufferObjectUnsynchronized() is implemented unsynchronizedly. } -void VulkanDriver::update2DImage(Handle th, - uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, - PixelBufferDescriptor&& data) { - handle_cast(th)->updateImage(data, width, height, 1, - xoffset, yoffset, 0, level); - scheduleDestroy(std::move(data)); -} - void VulkanDriver::setMinMaxLevels(Handle th, uint32_t minLevel, uint32_t maxLevel) { handle_cast(th)->setPrimaryRange(minLevel, maxLevel); } @@ -959,12 +951,6 @@ void VulkanDriver::update3DImage( scheduleDestroy(std::move(data)); } -void VulkanDriver::updateCubeImage(Handle th, uint32_t level, - PixelBufferDescriptor&& data, FaceOffsets faceOffsets) { - handle_cast(th)->updateCubeImage(data, faceOffsets, level); - scheduleDestroy(std::move(data)); -} - void VulkanDriver::setupExternalImage(void* image) { } @@ -1957,8 +1943,7 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons "loadUniformBuffer", "updateBufferObject", "updateIndexBuffer", - "update2DImage", - "updateCubeImage", + "update3DImage", }; static const utils::StaticString BEGIN_COMMAND = "beginRenderPass"; static const utils::StaticString END_COMMAND = "endRenderPass"; diff --git a/filament/backend/src/vulkan/VulkanTexture.cpp b/filament/backend/src/vulkan/VulkanTexture.cpp index f89d018b32..3465904c5c 100644 --- a/filament/backend/src/vulkan/VulkanTexture.cpp +++ b/filament/backend/src/vulkan/VulkanTexture.cpp @@ -205,7 +205,9 @@ VulkanTexture::~VulkanTexture() { void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height, uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel) { - assert_invariant(width <= this->width && height <= this->height && depth <= this->depth); + assert_invariant(width <= this->width && height <= this->height); + assert_invariant(depth <= this->depth * (target == SamplerType::SAMPLER_CUBEMAP ? 6 : 1)); + const PixelBufferDescriptor* hostData = &data; PixelBufferDescriptor reshapedData; @@ -260,7 +262,7 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt }; // Vulkan specifies subregions for 3D textures differently than from 2D arrays. - if (target == SamplerType::SAMPLER_2D_ARRAY) { + if (target == SamplerType::SAMPLER_2D_ARRAY || target == SamplerType::SAMPLER_CUBEMAP) { copyRegion.imageOffset.z = 0; copyRegion.imageExtent.depth = 1; copyRegion.imageSubresource.baseArrayLayer = zoffset; @@ -313,52 +315,6 @@ void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, u transitionLayout(cmdbuffer, range, getDefaultImageLayout(usage)); } -void VulkanTexture::updateCubeImage(const PixelBufferDescriptor& data, - const FaceOffsets& faceOffsets, uint32_t miplevel) { - assert_invariant(this->target == SamplerType::SAMPLER_CUBEMAP); - const bool reshape = getBytesPerPixel(format) == 3; - const void* cpuData = data.buffer; - const uint32_t numSrcBytes = data.size; - const uint32_t numDstBytes = reshape ? (4 * numSrcBytes / 3) : numSrcBytes; - - // Create and populate the staging buffer. - VulkanStage const* stage = mStagePool.acquireStage(numDstBytes); - void* mapped; - vmaMapMemory(mContext.allocator, stage->memory, &mapped); - if (reshape) { - DataReshaper::reshape(mapped, cpuData, numSrcBytes); - } else { - memcpy(mapped, cpuData, numSrcBytes); - } - vmaUnmapMemory(mContext.allocator, stage->memory); - vmaFlushAllocation(mContext.allocator, stage->memory, 0, numDstBytes); - - const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer; - const uint32_t width = std::max(1u, this->width >> miplevel); - const uint32_t height = std::max(1u, this->height >> miplevel); - - const VkImageSubresourceRange range = { getImageAspect(), miplevel, 1, 0, 6 }; - const VkImageLayout textureLayout = getDefaultImageLayout(usage); - - transitionLayout(cmdbuffer, range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - VkBufferImageCopy regions[6] = {{}}; - VkExtent3D extent { width, height, 1 }; - for (size_t face = 0; face < 6; face++) { - auto& region = regions[face]; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.baseArrayLayer = face; - region.imageSubresource.layerCount = 1; - region.imageSubresource.mipLevel = miplevel; - region.imageExtent = extent; - region.bufferOffset = faceOffsets.offsets[face]; - } - vkCmdCopyBufferToImage(cmdbuffer, stage->buffer, mTextureImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 6, regions); - - transitionLayout(cmdbuffer, range, textureLayout); -} - void VulkanTexture::setPrimaryRange(uint32_t minMiplevel, uint32_t maxMiplevel) { maxMiplevel = filament::math::min(int(maxMiplevel), int(this->levels - 1)); mPrimaryViewRange.baseMipLevel = minMiplevel; diff --git a/filament/backend/src/vulkan/VulkanTexture.h b/filament/backend/src/vulkan/VulkanTexture.h index cb07521c9c..e947beb0b7 100644 --- a/filament/backend/src/vulkan/VulkanTexture.h +++ b/filament/backend/src/vulkan/VulkanTexture.h @@ -43,10 +43,6 @@ struct VulkanTexture : public HwTexture { void updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height, uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel); - // Uploads data into all 6 faces of a cubemap for a given miplevel. - void updateCubeImage(const PixelBufferDescriptor& data, const FaceOffsets& faceOffsets, - uint32_t miplevel); - // Returns the primary image view, which is used for shader sampling. VkImageView getPrimaryImageView() const { return mCachedImageViews.at(mPrimaryViewRange); } diff --git a/filament/backend/test/test_Blit.cpp b/filament/backend/test/test_Blit.cpp index 25bad59d48..3e40aa8ca9 100644 --- a/filament/backend/test/test_Blit.cpp +++ b/filament/backend/test/test_Blit.cpp @@ -176,7 +176,6 @@ static void createFaces(DriverApi& dapi, Handle texture, int baseWidt // Draw a circle on a yellow background. uint32_t* texels = (uint32_t*) buffer0; - FaceOffsets offsets; for (int face = 0; face < 6; face++) { for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { @@ -187,12 +186,11 @@ static void createFaces(DriverApi& dapi, Handle texture, int baseWidt texels[row * width + col] = toUintColor(float4(color, 1.0f)); } } - offsets[face] = face * width * height * 4; - texels += offsets[face] / 4; + texels += face * width * height; } // Upload to the GPU. - dapi.updateCubeImage(texture, level, std::move(pb), offsets); + dapi.update3DImage(texture, level, 0, 0, 0, width, height, 6, std::move(pb)); } TEST_F(BackendTest, CubemapMinify) { diff --git a/filament/backend/test/test_FeedbackLoops.cpp b/filament/backend/test/test_FeedbackLoops.cpp index 3825e75900..022e6c8194 100644 --- a/filament/backend/test/test_FeedbackLoops.cpp +++ b/filament/backend/test/test_FeedbackLoops.cpp @@ -168,7 +168,7 @@ TEST_F(BackendTest, FeedbackLoops) { } auto cb = [](void* buffer, size_t size, void* user) { free(buffer); }; PixelBufferDescriptor pb(buffer, size, PixelDataFormat::RGBA, PixelDataType::UBYTE, cb); - api.update2DImage(texture, 0, 0, 0, kTexWidth, kTexHeight, std::move(pb)); + api.update3DImage(texture, 0, 0, 0, 0, kTexWidth, kTexHeight, 1, std::move(pb)); for (int frame = 0; frame < kNumFrames; frame++) { diff --git a/filament/backend/test/test_LoadImage.cpp b/filament/backend/test/test_LoadImage.cpp index a7a2c4433f..03da9d42ab 100644 --- a/filament/backend/test/test_LoadImage.cpp +++ b/filament/backend/test/test_LoadImage.cpp @@ -309,7 +309,7 @@ TEST_F(BackendTest, UpdateImage2D) { testCases.emplace_back("RGB, UINT_10F_11F_11F_REV -> R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::UINT_10F_11F_11F_REV, TextureFormat::R11F_G11F_B10F); testCases.emplace_back("RGB, HALF -> R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::HALF, TextureFormat::R11F_G11F_B10F); - /* // Test integer format uploads. */ + // Test integer format uploads. // TODO: These cases fail on OpenGL and Vulkan. testCases.emplace_back("RGB_INTEGER, UBYTE -> RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI); testCases.emplace_back("RGB_INTEGER, USHORT -> RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI); @@ -363,14 +363,14 @@ TEST_F(BackendTest, UpdateImage2D) { PixelBufferDescriptor subregion2 = checkerboardPixelBuffer(pf, pt, 256, t.bufferPadding); PixelBufferDescriptor subregion3 = checkerboardPixelBuffer(pf, pt, 256, t.bufferPadding); PixelBufferDescriptor subregion4 = checkerboardPixelBuffer(pf, pt, 256, t.bufferPadding); - api.update2DImage(texture, 0, 0, 0, 256, 256, std::move(subregion1)); - api.update2DImage(texture, 0, 256, 0, 256, 256, std::move(subregion2)); - api.update2DImage(texture, 0, 0, 256, 256, 256, std::move(subregion3)); - api.update2DImage(texture, 0, 256, 256, 256, 256, std::move(subregion4)); + api.update3DImage(texture, 0, 0, 0, 0, 256, 256, 1, std::move(subregion1)); + api.update3DImage(texture, 0, 256, 0, 0, 256, 256, 1, std::move(subregion2)); + api.update3DImage(texture, 0, 0, 256, 0, 256, 256, 1, std::move(subregion3)); + api.update3DImage(texture, 0, 256, 256, 0, 256, 256, 1, std::move(subregion4)); } else { PixelBufferDescriptor descriptor = checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 512, t.bufferPadding); - api.update2DImage(texture, 0, 0, 0, 512, 512, std::move(descriptor)); + api.update3DImage(texture, 0, 0, 0, 0, 512, 512, 1, std::move(descriptor)); } SamplerGroup samplers(1); @@ -454,7 +454,7 @@ TEST_F(BackendTest, UpdateImageSRGB) { } } - api.update2DImage(texture, 0, 0, 0, 512, 512, std::move(descriptor)); + api.update3DImage(texture, 0, 0, 0, 0, 512, 512, 1, std::move(descriptor)); api.beginFrame(0, 0); @@ -524,7 +524,7 @@ TEST_F(BackendTest, UpdateImageMipLevel) { // Create image data. PixelBufferDescriptor descriptor = checkerboardPixelBuffer(pixelFormat, pixelType, 512); - api.update2DImage(texture, 1, 0, 0, 512, 512, std::move(descriptor)); + api.update3DImage(texture, 1, 0, 0, 0, 512, 512, 1, std::move(descriptor)); api.beginFrame(0, 0); diff --git a/filament/include/filament/Texture.h b/filament/include/filament/Texture.h index 2656023e16..1964ba1c4f 100644 --- a/filament/include/filament/Texture.h +++ b/filament/include/filament/Texture.h @@ -68,6 +68,9 @@ class UTILS_PUBLIC Texture : public FilamentAPI { public: static constexpr const size_t BASE_LEVEL = 0; + //! Face offsets for all faces of a cubemap + struct FaceOffsets; + using PixelBufferDescriptor = backend::PixelBufferDescriptor; //!< Geometry of a pixel buffer using Sampler = backend::SamplerType; //!< Type of sampler using InternalFormat = backend::TextureFormat; //!< Internal texel format @@ -75,7 +78,6 @@ public: using Format = backend::PixelDataFormat; //!< Pixel color format using Type = backend::PixelDataType; //!< Pixel data format using CompressedType = backend::CompressedPixelDataType; //!< Compressed pixel data format - using FaceOffsets = backend::FaceOffsets; //!< Cube map faces offsets using Usage = backend::TextureUsage; //!< Usage affects texel layout using Swizzle = backend::TextureSwizzle; //!< Texture swizzle @@ -133,7 +135,8 @@ public: * effectively create a 3D texture. * @param depth Depth of the texture in texels (default: 1). * @return This Builder, for chaining calls. - * @attention This Texture instance must use Sampler::SAMPLER_3D or Sampler::SAMPLER_2D_ARRAY or it has no effect. + * @attention This Texture instance must use Sampler::SAMPLER_3D or + * Sampler::SAMPLER_2D_ARRAY or it has no effect. */ Builder& depth(uint32_t depth) noexcept; @@ -289,59 +292,8 @@ public: InternalFormat getFormat() const noexcept; /** - * Specify the image of a 2D texture for a level. - * - * @param engine Engine this texture is associated to. - * @param level Level to set the image for. - * @param buffer Client-side buffer containing the image to set. - * - * @attention \p engine must be the instance passed to Builder::build() - * @attention \p level must be less than getLevels(). - * @attention \p buffer's Texture::Format must match that of getFormat(). - * @attention This Texture instance must use Sampler::SAMPLER_2D or - * Sampler::SAMPLER_EXTERNAL. IF the later is specified - * and external textures are supported by the driver implementation, - * this method will have no effect, otherwise it will behave as if the - * texture was specified with driver::SamplerType::SAMPLER_2D. - * - * @note - * This is equivalent to calling: - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * setImage(engine, level, 0, 0, getWidth(level), getHeight(level), buffer); - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * @see Builder::sampler() - */ - void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const; - - /** - * Updates a sub-image of a 2D texture for a level. - * - * @param engine Engine this texture is associated to. - * @param level Level to set the image for. - * @param xoffset Left offset of the sub-region to update. - * @param yoffset Bottom offset of the sub-region to update. - * @param width Width of the sub-region to update. - * @param height Height of the sub-region to update. - * @param buffer Client-side buffer containing the image to set. - * - * @attention \p engine must be the instance passed to Builder::build() - * @attention \p level must be less than getLevels(). - * @attention \p buffer's Texture::Format must match that of getFormat(). - * @attention This Texture instance must use Sampler::SAMPLER_2D or - * Sampler::SAMPLER_EXTERNAL. IF the later is specified - * and external textures are supported by the driver implementation, - * this method will have no effect, otherwise it will behave as if the - * texture was specified with Sampler::SAMPLER_2D. - * - * @see Builder::sampler() - */ - void setImage(Engine& engine, size_t level, - uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, - PixelBufferDescriptor&& buffer) const; - - /** - * Updates a sub-image of a 3D texture or 2D texture array for a level. + * Updates a sub-image of a 3D texture or 2D texture array for a level. Cubemaps are treated + * like a 2D array of six layers. * * @param engine Engine this texture is associated to. * @param level Level to set the image for. @@ -356,7 +308,8 @@ public: * @attention \p engine must be the instance passed to Builder::build() * @attention \p level must be less than getLevels(). * @attention \p buffer's Texture::Format must match that of getFormat(). - * @attention This Texture instance must use Sampler::SAMPLER_3D or Sampler::SAMPLER_2D_array. + * @attention This Texture instance must use Sampler::SAMPLER_3D, Sampler::SAMPLER_2D_ARRAY + * or Sampler::SAMPLER_CUBEMAP. * * @see Builder::sampler() */ @@ -365,6 +318,32 @@ public: uint32_t width, uint32_t height, uint32_t depth, PixelBufferDescriptor&& buffer) const; + /** + * inline helper to update a 2D texture + * + * @see setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + inline void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const { + setImage(engine, level, 0, 0, 0, getWidth(level), getHeight(level), 1, std::move(buffer)); + } + + /** + * inline helper to update a 2D texture + * + * @see setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + inline void setImage(Engine& engine, size_t level, + uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, + PixelBufferDescriptor&& buffer) const { + setImage(engine, level, xoffset, yoffset, 0, width, height, 1, std::move(buffer)); + } + /** * Specify all six images of a cube map level. * @@ -382,7 +361,13 @@ public: * @attention This Texture instance must use Sampler::SAMPLER_CUBEMAP or it has no effect * * @see Texture::CubemapFace, Builder::sampler() + * + * @deprecated Instead, use setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) */ + [[deprecated]] void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const; @@ -510,6 +495,51 @@ public: void generatePrefilterMipmap(Engine& engine, PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets, PrefilterOptions const* options = nullptr); + + + /** @deprecated */ + struct FaceOffsets { + using size_type = size_t; + union { + struct { + size_type px; //!< +x face offset in bytes + size_type nx; //!< -x face offset in bytes + size_type py; //!< +y face offset in bytes + size_type ny; //!< -y face offset in bytes + size_type pz; //!< +z face offset in bytes + size_type nz; //!< -z face offset in bytes + }; + size_type offsets[6]; + }; + size_type operator[](size_t n) const noexcept { return offsets[n]; } + size_type& operator[](size_t n) { return offsets[n]; } + FaceOffsets() noexcept = default; + explicit FaceOffsets(size_type faceSize) noexcept { + px = faceSize * 0; + nx = faceSize * 1; + py = faceSize * 2; + ny = faceSize * 3; + pz = faceSize * 4; + nz = faceSize * 5; + } + FaceOffsets(const FaceOffsets& rhs) noexcept { + px = rhs.px; + nx = rhs.nx; + py = rhs.py; + ny = rhs.ny; + pz = rhs.pz; + nz = rhs.nz; + } + FaceOffsets& operator=(const FaceOffsets& rhs) noexcept { + px = rhs.px; + nx = rhs.nx; + py = rhs.py; + ny = rhs.ny; + pz = rhs.pz; + nz = rhs.nz; + return *this; + } + }; }; } // namespace filament diff --git a/filament/src/Froxelizer.cpp b/filament/src/Froxelizer.cpp index 238ab37d69..cc7b5aab10 100644 --- a/filament/src/Froxelizer.cpp +++ b/filament/src/Froxelizer.cpp @@ -502,8 +502,8 @@ std::pair Froxelizer::clipToIndices(float2 const& clip) const no void Froxelizer::commit(backend::DriverApi& driverApi) { // send data to GPU - driverApi.update2DImage(mFroxelTexture, 0, 0, 0, - FROXEL_BUFFER_WIDTH, FROXEL_BUFFER_HEIGHT,{ + driverApi.update3DImage(mFroxelTexture, 0, 0, 0, 0, + FROXEL_BUFFER_WIDTH, FROXEL_BUFFER_HEIGHT, 1, { mFroxelBufferUser.begin(), mFroxelBufferUser.sizeInBytes(), PixelBufferDescriptor::PixelDataFormat::RG_INTEGER, PixelBufferDescriptor::PixelDataType::USHORT }); diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 48722a087b..5efc3c50a2 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -266,33 +266,15 @@ void PostProcessManager::init() noexcept { mStarburstTexture = driver.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::R8, 1, 256, 1, 1, TextureUsage::DEFAULT); - PixelBufferDescriptor dataOne(driver.allocate(4), 4, PixelDataFormat::RGBA, PixelDataType::UBYTE); - PixelBufferDescriptor dataOneArray(driver.allocate(4), 4, PixelDataFormat::RGBA, PixelDataType::UBYTE); - PixelBufferDescriptor dataZero(driver.allocate(4), 4, PixelDataFormat::RGBA, PixelDataType::UBYTE); PixelBufferDescriptor dataStarburst(driver.allocate(256), 256, PixelDataFormat::R, PixelDataType::UBYTE); - *static_cast(dataOne.buffer) = 0xFFFFFFFF; - *static_cast(dataOneArray.buffer) = 0xFFFFFFFF; - *static_cast(dataZero.buffer) = 0; std::generate_n((uint8_t*)dataStarburst.buffer, 256, [&dist = mUniformDistribution, &gen = mEngine.getRandomEngine()]() { float r = 0.5f + 0.5f * dist(gen); return uint8_t(r * 255.0f); }); - driver.update2DImage(engine.getOneTexture(), - 0, 0, 0, 1, 1, - std::move(dataOne)); - - driver.update3DImage(engine.getOneTextureArray(), - 0, 0, 0, 0, 1, 1, 1, - std::move(dataOneArray)); - - driver.update2DImage(engine.getZeroTexture(), - 0, 0, 0, 1, 1, - std::move(dataZero)); - - driver.update2DImage(mStarburstTexture, - 0, 0, 0, 256, 1, + driver.update3DImage(mStarburstTexture, + 0, 0, 0, 0, 256, 1, 1, std::move(dataStarburst)); } diff --git a/filament/src/Texture.cpp b/filament/src/Texture.cpp index d7ea60ccd7..3f83383aa7 100644 --- a/filament/src/Texture.cpp +++ b/filament/src/Texture.cpp @@ -45,18 +45,6 @@ Texture::InternalFormat Texture::getFormat() const noexcept { return upcast(this)->getFormat(); } -void Texture::setImage(Engine& engine, size_t level, - Texture::PixelBufferDescriptor&& buffer) const { - upcast(this)->setImage(upcast(engine), level, std::move(buffer)); -} - -void Texture::setImage(Engine& engine, - size_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, - PixelBufferDescriptor&& buffer) const { - upcast(this)->setImage(upcast(engine), - level, xoffset, yoffset, width, height, std::move(buffer)); -} - void Texture::setImage(Engine& engine, size_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 384aea60ec..404439950d 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -345,38 +345,29 @@ void FEngine::init() { mDummyZeroTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1, TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); - mDummyOneIntegerTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1, - TextureFormat::RGBA8I, 1, 1, 1, 1, TextureUsage::DEFAULT); - mDummyZeroTexture = driverApi.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); // initialize the dummy textures so that their contents are not undefined - using PixelBufferDescriptor = Texture::PixelBufferDescriptor; - - static const uint32_t zeroes = 0; + static const uint32_t zeroes[6] = {0}; static const uint32_t ones = 0xffffffff; - static const uint32_t signedOnes = 0x7f7f7f7f; - mDefaultIblTexture->setImage(*this, 0, - PixelBufferDescriptor(&zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE), {}); + driverApi.update3DImage(mDefaultIblTexture->getHwHandle(), 0, 0, 0, 0, 1, 1, 6, + { zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE }); - driverApi.update2DImage(mDummyOneTexture, 0, 0, 0, 1, 1, - PixelBufferDescriptor(&ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE)); + driverApi.update3DImage(mDummyOneTexture, 0, 0, 0, 0, 1, 1, 1, + { &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); driverApi.update3DImage(mDummyOneTextureArray, 0, 0, 0, 0, 1, 1, 1, - PixelBufferDescriptor(&ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE)); - - driverApi.update3DImage(mDummyOneIntegerTextureArray, 0, 0, 0, 0, 1, 1, 1, - PixelBufferDescriptor(&signedOnes, 4, Texture::Format::RGBA_INTEGER, Texture::Type::BYTE)); + { &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1, - PixelBufferDescriptor(&zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE)); + { zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); driverApi.update3DImage(mDummyZeroTextureArray, 0, 0, 0, 0, 1, 1, 1, - PixelBufferDescriptor(&zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE)); + { zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); mDefaultRenderTarget = driverApi.createDefaultRenderTarget(); @@ -467,7 +458,6 @@ void FEngine::shutdown() { driver.destroyTexture(mDummyOneTexture); driver.destroyTexture(mDummyOneTextureArray); - driver.destroyTexture(mDummyOneIntegerTextureArray); driver.destroyTexture(mDummyZeroTexture); driver.destroyTexture(mDummyZeroTextureArray); diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 5654aa602a..14014ae1fe 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -353,7 +353,6 @@ public: backend::Handle getZeroTexture() const { return mDummyZeroTexture; } backend::Handle getOneTextureArray() const { return mDummyOneTextureArray; } backend::Handle getZeroTextureArray() const { return mDummyZeroTextureArray; } - backend::Handle getOneIntegerTextureArray() const { return mDummyOneIntegerTextureArray; } static constexpr const size_t MiB = 1024u * 1024u; size_t getMinCommandBufferSize() const noexcept { return mConfig.minCommandBufferSizeMB * MiB; } @@ -470,7 +469,6 @@ private: backend::Handle mDummyOneTexture; backend::Handle mDummyOneTextureArray; backend::Handle mDummyZeroTextureArray; - backend::Handle mDummyOneIntegerTextureArray; backend::Handle mDummyZeroTexture; std::thread::id mMainThreadId{}; diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index dc89e3e3e5..0917c13d1e 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -40,6 +40,16 @@ namespace filament { using namespace backend; using namespace math; +// this is a hack to be able to create a std::function<> with a non-copyable closure +template +auto make_copyable_function(F&& f) { + using dF = std::decay_t; + auto spf = std::make_shared(std::forward(f)); + return [spf](auto&& ... args) -> decltype(auto) { + return (*spf)(decltype(args)(args)...); + }; +} + struct Texture::BuilderDetails { intptr_t mImportedId = 0; uint32_t mWidth = 1; @@ -180,76 +190,6 @@ size_t FTexture::getDepth(size_t level) const noexcept { return valueForLevel(level, mDepth); } -void FTexture::setImage(FEngine& engine, size_t level, - Texture::PixelBufferDescriptor&& buffer) const { - setImage(engine, level, 0, 0, - uint32_t(getWidth(level)), uint32_t(getHeight(level)), - std::move(buffer)); -} - -UTILS_NOINLINE -void FTexture::setImage(FEngine& engine, - size_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, - Texture::PixelBufferDescriptor&& buffer) const { - - auto validateTarget = [](SamplerType sampler) -> bool { - switch (sampler) { - case SamplerType::SAMPLER_2D: - case SamplerType::SAMPLER_EXTERNAL: - return true; - case SamplerType::SAMPLER_CUBEMAP: - case SamplerType::SAMPLER_3D: - case SamplerType::SAMPLER_2D_ARRAY: - return false; - } - }; - - if (!ASSERT_POSTCONDITION_NON_FATAL(buffer.type == PixelDataType::COMPRESSED || - validatePixelFormatAndType(mFormat, buffer.format, buffer.type), - "The combination of internal format=%u and {format=%u, type=%u} is not supported.", - unsigned(mFormat), unsigned(buffer.format), unsigned(buffer.type))) { - return; - } - - if (!ASSERT_POSTCONDITION_NON_FATAL(!mStream, "setImage() called on a Stream texture.")) { - return; - } - - if (!ASSERT_POSTCONDITION_NON_FATAL(level < mLevelCount, - "level=%u is >= to levelCount=%u.", unsigned(level), unsigned(mLevelCount))) { - return; - } - - if (!ASSERT_POSTCONDITION_NON_FATAL(validateTarget(mTarget), - "Texture Sampler type (%u) not supported for this operation.", unsigned(mTarget))) { - return; - } - - if (!ASSERT_POSTCONDITION_NON_FATAL(buffer.buffer, "Data buffer is nullptr.")) { - return; - } - - if (!ASSERT_POSTCONDITION_NON_FATAL(mSampleCount <= 1, - "Operation not supported with multisample (%u) texture.", unsigned(mSampleCount))) { - return; - } - - if (!ASSERT_POSTCONDITION_NON_FATAL(xoffset + width <= valueForLevel(level, mWidth), - "xoffset (%u) + width (%u) > texture width (%u) at level (%u)", - unsigned(xoffset), unsigned(width), unsigned(valueForLevel(level, mWidth)), unsigned(level))) { - return; - } - - if (!ASSERT_POSTCONDITION_NON_FATAL(yoffset + height <= valueForLevel(level, mHeight), - "xoffset (%u) + width (%u) > texture width (%u) at level (%u)", - unsigned(yoffset), unsigned(height), unsigned(valueForLevel(level, mHeight)), unsigned(level))) { - return; - } - - engine.getDriverApi().update2DImage(mHandle, - uint8_t(level), xoffset, yoffset, width, height, std::move(buffer)); -} - void FTexture::setImage(FEngine& engine, size_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, @@ -257,12 +197,12 @@ void FTexture::setImage(FEngine& engine, size_t level, auto validateTarget = [](SamplerType sampler) -> bool { switch (sampler) { + case SamplerType::SAMPLER_2D: case SamplerType::SAMPLER_3D: case SamplerType::SAMPLER_2D_ARRAY: - return true; - case SamplerType::SAMPLER_2D: - case SamplerType::SAMPLER_EXTERNAL: case SamplerType::SAMPLER_CUBEMAP: + return true; + case SamplerType::SAMPLER_EXTERNAL: return false; } }; @@ -321,6 +261,7 @@ void FTexture::setImage(FEngine& engine, size_t level, uint8_t(level), xoffset, yoffset, zoffset, width, height, depth, std::move(buffer)); } +// deprecated void FTexture::setImage(FEngine& engine, size_t level, Texture::PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const { @@ -328,9 +269,9 @@ void FTexture::setImage(FEngine& engine, size_t level, switch (sampler) { case SamplerType::SAMPLER_CUBEMAP: return true; + case SamplerType::SAMPLER_2D: case SamplerType::SAMPLER_3D: case SamplerType::SAMPLER_2D_ARRAY: - case SamplerType::SAMPLER_2D: case SamplerType::SAMPLER_EXTERNAL: return false; } @@ -361,8 +302,19 @@ void FTexture::setImage(FEngine& engine, size_t level, return; } - engine.getDriverApi().updateCubeImage(mHandle, uint8_t(level), - std::move(buffer), faceOffsets); + auto w = std::max(1u, mWidth >> level); + auto h = std::max(1u, mHeight >> level); + assert_invariant(w == h); + const size_t faceSize = PixelBufferDescriptor::computeDataSize(buffer.format, buffer.type, + buffer.stride ? buffer.stride : w, h, buffer.alignment); + UTILS_NOUNROLL + for (size_t face = 0; face < 6; face++) { + engine.getDriverApi().update3DImage(mHandle, uint8_t(level), 0, 0, face, w, h, 1, { + (char*)buffer.buffer + faceOffsets[face], + faceSize, buffer.format, buffer.type, buffer.alignment, + buffer.left, buffer.top, buffer.stride }); + } + engine.getDriverApi().queueCommand(make_copyable_function([buffer = std::move(buffer)]() {})); } void FTexture::setExternalImage(FEngine& engine, void* image) noexcept { @@ -495,16 +447,6 @@ size_t FTexture::getFormatSize(InternalFormat format) noexcept { } -// this is a hack to be able to create a std::function<> with a non-copyable closure -template -auto make_copyable_function(F&& f) { - using dF = std::decay_t; - auto spf = std::make_shared(std::forward(f)); - return [spf](auto&& ... args) -> decltype(auto) { - return (*spf)(decltype(args)(args)...); - }; -} - void FTexture::generatePrefilterMipmap(FEngine& engine, PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets, PrefilterOptions const* options) { @@ -676,13 +618,16 @@ void FTexture::generatePrefilterMipmap(FEngine& engine, Texture::PixelBufferDescriptor::PixelDataType::FLOAT, 1, 0, 0, image.getStride()); uintptr_t base = uintptr_t(image.getData()); - backend::FaceOffsets offsets{}; for (size_t j = 0; j < 6; j++) { Image const& faceImage = dst.getImageForFace((Cubemap::Face)j); - offsets[j] = uintptr_t(faceImage.getData()) - base; + auto offset = uintptr_t(faceImage.getData()) - base; + driver.update3DImage(mHandle, level, 0, 0, j, dim, dim, 1, { + (char*)image.getData() + offset, dim * dim * 3 * sizeof(float), + Texture::PixelBufferDescriptor::PixelDataFormat::RGB, + Texture::PixelBufferDescriptor::PixelDataType::FLOAT, 1, + 0, 0, uint32_t(image.getStride()) + }); } - // upload all 6 faces into the texture - driver.updateCubeImage(mHandle, level, std::move(pbd), offsets); // enqueue a commands that holds the image data until it's executed driver.queueCommand(make_copyable_function([data = image.detach()]() {})); diff --git a/filament/src/details/Texture.h b/filament/src/details/Texture.h index cb2dcc5d16..973852672b 100644 --- a/filament/src/details/Texture.h +++ b/filament/src/details/Texture.h @@ -48,17 +48,12 @@ public: InternalFormat getFormat() const noexcept { return mFormat; } Usage getUsage() const noexcept { return mUsage; } - void setImage(FEngine& engine, size_t level, PixelBufferDescriptor&& buffer) const; - - void setImage(FEngine& engine, size_t level, - uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, - PixelBufferDescriptor&& buffer) const; - void setImage(FEngine& engine, size_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, PixelBufferDescriptor&& buffer) const; + [[deprecated]] void setImage(FEngine& engine, size_t level, PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const; diff --git a/libs/filamentapp/include/filamentapp/IBL.h b/libs/filamentapp/include/filamentapp/IBL.h index 4fa273adae..8943823ed9 100644 --- a/libs/filamentapp/include/filamentapp/IBL.h +++ b/libs/filamentapp/include/filamentapp/IBL.h @@ -64,7 +64,7 @@ private: bool loadCubemapLevel(filament::Texture** texture, filament::Texture::PixelBufferDescriptor* outBuffer, - filament::Texture::FaceOffsets* outOffsets, + uint32_t* dim, const utils::Path& path, size_t level = 0, std::string const& levelPrefix = "") const; diff --git a/libs/filamentapp/src/IBL.cpp b/libs/filamentapp/src/IBL.cpp index 0b413c5af6..0ec5474759 100644 --- a/libs/filamentapp/src/IBL.cpp +++ b/libs/filamentapp/src/IBL.cpp @@ -196,10 +196,10 @@ bool IBL::loadFromDirectory(const utils::Path& path) { bool IBL::loadCubemapLevel(filament::Texture** texture, const utils::Path& path, size_t level, std::string const& levelPrefix) const { - Texture::FaceOffsets offsets; + uint32_t dim; Texture::PixelBufferDescriptor buffer; - if (loadCubemapLevel(texture, &buffer, &offsets, path, level, levelPrefix)) { - (*texture)->setImage(mEngine, level, std::move(buffer), offsets); + if (loadCubemapLevel(texture, &buffer, &dim, path, level, levelPrefix)) { + (*texture)->setImage(mEngine, level, 0, 0, dim, dim, std::move(buffer)); return true; } return false; @@ -208,7 +208,7 @@ bool IBL::loadCubemapLevel(filament::Texture** texture, const utils::Path& path, bool IBL::loadCubemapLevel( filament::Texture** texture, Texture::PixelBufferDescriptor* outBuffer, - Texture::FaceOffsets* outOffsets, + uint32_t* dim, const utils::Path& path, size_t level, std::string const& levelPrefix) const { static const char* faceSuffix[6] = { "px", "nx", "py", "ny", "pz", "nz" }; @@ -248,8 +248,8 @@ bool IBL::loadCubemapLevel( // RGB_10_11_11_REV encoding: 4 bytes per pixel const size_t faceSize = size * size * sizeof(uint32_t); + *dim = size; - Texture::FaceOffsets offsets; Texture::PixelBufferDescriptor buffer( malloc(faceSize * 6), faceSize * 6, Texture::Format::RGB, Texture::Type::UINT_10F_11F_11F_REV, @@ -259,8 +259,6 @@ bool IBL::loadCubemapLevel( uint8_t* p = static_cast(buffer.buffer); for (size_t j = 0; j < 6; j++) { - offsets[j] = faceSize * j; - std::string faceName = levelPrefix + faceSuffix[j] + ".rgb32f"; Path facePath(Path::concat(path, faceName)); if (!facePath.exists()) { @@ -284,7 +282,7 @@ bool IBL::loadCubemapLevel( break; } - memcpy(p + offsets[j], data, w * h * sizeof(uint32_t)); + memcpy(p + faceSize * j, data, w * h * sizeof(uint32_t)); stbi_image_free(data); } @@ -292,7 +290,6 @@ bool IBL::loadCubemapLevel( if (!success) return false; *outBuffer = std::move(buffer); - *outOffsets = offsets; return true; } diff --git a/libs/ktxreader/src/Ktx1Reader.cpp b/libs/ktxreader/src/Ktx1Reader.cpp index 9148d861ec..180dbfb482 100644 --- a/libs/ktxreader/src/Ktx1Reader.cpp +++ b/libs/ktxreader/src/Ktx1Reader.cpp @@ -76,25 +76,30 @@ Texture* createTexture(Engine* engine, const Ktx1Bundle& ktx, bool srgb, if (isCompressed(ktxinfo)) { if (ktx.isCubemap()) { for (uint32_t level = 0; level < nmips; ++level) { - ktx.getBlob({level, 0, 0}, &data, &size); - PixelBufferDescriptor pbd(data, size * 6, cdatatype, size, cb, cbuser); - texture->setImage(*engine, level, std::move(pbd), Texture::FaceOffsets(size)); + ktx.getBlob({ level, 0, 0 }, &data, &size); + const uint32_t dim = texture->getWidth(level); + texture->setImage(*engine, level, 0, 0, dim, dim, { + data, size * 6, cdatatype, size, cb, cbuser + }); } return texture; } for (uint32_t level = 0; level < nmips; ++level) { - ktx.getBlob({level, 0, 0}, &data, &size); - PixelBufferDescriptor pbd(data, size, cdatatype, size, cb, cbuser); - texture->setImage(*engine, level, std::move(pbd)); + ktx.getBlob({ level, 0, 0 }, &data, &size); + texture->setImage(*engine, level, { + data, size, cdatatype, size, cb, cbuser + }); } return texture; } if (ktx.isCubemap()) { for (uint32_t level = 0; level < nmips; ++level) { - ktx.getBlob({level, 0, 0}, &data, &size); - PixelBufferDescriptor pbd(data, size * 6, dataformat, datatype, cb, cbuser); - texture->setImage(*engine, level, std::move(pbd), Texture::FaceOffsets(size)); + ktx.getBlob({ level, 0, 0 }, &data, &size); + const uint32_t dim = texture->getWidth(level); + texture->setImage(*engine, level, 0, 0, dim, dim, { + data, size * 6, dataformat, datatype, cb, cbuser + }); } return texture; }