Implement texture swizzling
This commit is contained in:
committed by
Mathias Agopian
parent
8094955fc1
commit
ed326e1e68
@@ -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),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user