Implement texture swizzling

This commit is contained in:
Pixelflinger
2020-04-14 18:46:21 -07:00
committed by Mathias Agopian
parent 8094955fc1
commit ed326e1e68
12 changed files with 126 additions and 0 deletions
+1
View File
@@ -26,6 +26,7 @@ A new header is inserted each time a *tag* is created.
- Fix several issues related to multi-view support. (⚠️ **API breakage**) removed
`View::setClearColor()`, a similar functionality is now handled by `Renderer::setClearOptions()`
and `Skybox`, the later now can be set to a constant color.
- Textures can now be swizzled.
## v1.5.2
@@ -113,6 +113,14 @@ Java_com_google_android_filament_Texture_nBuilderUsage(JNIEnv*, jclass,
builder->usage((Texture::Usage) flags);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Texture_nBuilderSwizzle(JNIEnv *, jclass ,
jlong nativeBuilder, jint r, jint g, jint b, jint a) {
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
builder->swizzle(
(Texture::Swizzle)r, (Texture::Swizzle)g, (Texture::Swizzle)b, (Texture::Swizzle)a);
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Texture_nBuilderBuild(JNIEnv*, jclass,
jlong nativeBuilder, jlong nativeEngine) {
@@ -297,6 +297,18 @@ public class Texture {
USHORT_565,
}
/**
* Texture swizzling channels
*/
public enum Swizzle {
SUBSTITUTE_ZERO, //!< specified component is substituted with 0
SUBSTITUTE_ONE, //!< specified component is substituted with 1
CHANNEL_0, //!< specified component taken from channel 0
CHANNEL_1, //!< specified component taken from channel 1
CHANNEL_2, //!< specified component taken from channel 2
CHANNEL_3 //!< specified component taken from channel 3
}
/**
* A descriptor to an image in main memory, typically used to transfer image data from the CPU
* to the GPU.
@@ -645,6 +657,21 @@ public class Texture {
return this;
}
/**
* Specifies how a texture's channels map to color components
*
* @param r texture channel for red component
* @param g texture channel for green component
* @param b texture channel for blue component
* @param a texture channel for alpha component
* @return This Builder, for chaining calls.
*/
@NonNull
public Builder swizzle(@NonNull Swizzle r, @NonNull Swizzle g, @NonNull Swizzle b, @NonNull Swizzle a) {
nBuilderSwizzle(mNativeBuilder, r.ordinal(), g.ordinal(), b.ordinal(), a.ordinal());
return this;
}
/**
* Creates a new <code>Texture</code> instance.
* @param engine The {@link Engine} to associate this <code>Texture</code> with.
@@ -1061,6 +1088,7 @@ public class Texture {
private static native void nBuilderSampler(long nativeBuilder, int sampler);
private static native void nBuilderFormat(long nativeBuilder, int format);
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 long nBuilderBuild(long nativeBuilder, long nativeEngine);
private static native int nGetWidth(long nativeTexture, int level);
@@ -477,6 +477,16 @@ enum class TextureUsage : uint8_t {
DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage
};
//! Texture swizzle
enum class TextureSwizzle {
SUBSTITUTE_ZERO,
SUBSTITUTE_ONE,
CHANNEL_0,
CHANNEL_1,
CHANNEL_2,
CHANNEL_3
};
//! returns whether this format a compressed format
static constexpr bool isCompressedFormat(TextureFormat format) noexcept {
return format >= TextureFormat::EAC_R11;
@@ -292,6 +292,13 @@ DECL_DRIVER_API_N(updateSamplerGroup,
backend::SamplerGroupHandle, ubh,
backend::SamplerGroup&&, samplerGroup)
DECL_DRIVER_API_N(setTextureSwizzle,
backend::TextureHandle, th,
backend::TextureSwizzle, r,
backend::TextureSwizzle, g,
backend::TextureSwizzle, b,
backend::TextureSwizzle, a)
DECL_DRIVER_API_N(update2DImage,
backend::TextureHandle, th,
uint32_t, level,
@@ -575,6 +575,11 @@ void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&
ib->buffer.copyIntoBuffer(data.buffer, data.size);
}
void MetalDriver::setTextureSwizzle(Handle<HwTexture> th,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
// TODO: implement setTextureSwizzle
}
void MetalDriver::update2DImage(Handle<HwTexture> th, uint32_t level, uint32_t xoffset,
uint32_t yoffset, uint32_t width, uint32_t height, PixelBufferDescriptor&& data) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
+4
View File
@@ -157,6 +157,10 @@ void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&&
scheduleDestroy(std::move(p));
}
void NoopDriver::setTextureSwizzle(Handle<HwTexture> th,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
}
void NoopDriver::update2DImage(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
PixelBufferDescriptor&& data) {
+18
View File
@@ -274,6 +274,24 @@ constexpr inline GLenum getType(backend::PixelDataType type) noexcept {
}
}
constexpr inline GLenum getSwizzleChannel(backend::TextureSwizzle c) noexcept {
using TextureSwizzle = backend::TextureSwizzle;
switch (c) {
case TextureSwizzle::SUBSTITUTE_ZERO:
return GL_ZERO;
case TextureSwizzle::SUBSTITUTE_ONE:
return GL_ONE;
case TextureSwizzle::CHANNEL_0:
return GL_RED;
case TextureSwizzle::CHANNEL_1:
return GL_GREEN;
case TextureSwizzle::CHANNEL_2:
return GL_BLUE;
case TextureSwizzle::CHANNEL_3:
return GL_ALPHA;
}
}
// clang looses it on this one, and generates a huge jump table when
// inlined. So we don't mark it as inline (only constexpr) which solves the problem,
// strangely, when not inlined, clang simply generates an array lookup.
@@ -1603,6 +1603,19 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
*sb->sb = std::move(samplerGroup); // NOLINT(performance-move-const-arg)
}
void OpenGLDriver::setTextureSwizzle(Handle<HwTexture> th,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
DEBUG_MARKER()
GLTexture* t = handle_cast<GLTexture *>(th);
bindTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1, t);
mContext.activeTexture(OpenGLContext::MAX_TEXTURE_UNIT_COUNT - 1);
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_R, getSwizzleChannel(r));
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_G, getSwizzleChannel(g));
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_B, getSwizzleChannel(b));
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_A, getSwizzleChannel(a));
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::update2DImage(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
PixelBufferDescriptor&& data) {
@@ -691,6 +691,11 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
scheduleDestroy(std::move(p));
}
void VulkanDriver::setTextureSwizzle(Handle<HwTexture> th,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
// TODO: implement setTextureSwizzle
}
void VulkanDriver::update2DImage(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
PixelBufferDescriptor&& data) {
+12
View File
@@ -79,6 +79,7 @@ public:
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
static bool isTextureFormatSupported(Engine& engine, InternalFormat format) noexcept;
@@ -175,6 +176,17 @@ public:
*/
Builder& usage(Usage usage) noexcept;
/**
* Specifies how a texture's channels map to color components
*
* @param r texture channel for red component
* @param g texture channel for green component
* @param b texture channel for blue component
* @param a texture channel for alpha component
* @return This Builder, for chaining calls.
*/
Builder& swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept;
/**
* Creates the Texture object and returns a pointer to it.
*
+15
View File
@@ -47,6 +47,10 @@ struct Texture::BuilderDetails {
Sampler mTarget = Sampler::SAMPLER_2D;
InternalFormat mFormat = InternalFormat::RGBA8;
Usage mUsage = Usage::DEFAULT;
bool mTextureIsSwizzled = false;
std::array<Swizzle, 4> mSwizzle = {
Swizzle::CHANNEL_0, Swizzle::CHANNEL_1,
Swizzle::CHANNEL_2, Swizzle::CHANNEL_3 };
};
using BuilderType = Texture;
@@ -99,6 +103,12 @@ Texture::Builder& Texture::Builder::import(intptr_t id) noexcept {
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 };
return *this;
}
Texture* Texture::Builder::build(Engine& engine) {
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
if (!ASSERT_POSTCONDITION_NON_FATAL(Texture::isTextureFormatSupported(engine, mImpl->mFormat),
@@ -130,6 +140,11 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) {
mHandle = driver.importTexture(builder->mImportedId,
mTarget, mLevelCount, mFormat, mSampleCount, mWidth, mHeight, mDepth, mUsage);
}
if (UTILS_UNLIKELY(builder->mTextureIsSwizzled)) {
driver.setTextureSwizzle(mHandle,
builder->mSwizzle[0], builder->mSwizzle[1], builder->mSwizzle[2],
builder->mSwizzle[3]);
}
}
// frees driver resources, object becomes invalid