fix a few issues with color grading
- we were not clamping the color grading output to [0,1] - we were not using a supported input (cpu) pixel format for the 3d LUT in low and medium quality
This commit is contained in:
committed by
Mathias Agopian
parent
087e2480d1
commit
e34db6fc29
@@ -283,7 +283,8 @@ enum class PixelDataType : uint8_t {
|
||||
FLOAT, //!< float (32-bits float)
|
||||
COMPRESSED, //!< compressed pixels, @see CompressedPixelDataType
|
||||
UINT_10F_11F_11F_REV, //!< three low precision floating-point numbers
|
||||
USHORT_565 //!< unsigned int (16-bit), encodes 3 RGB channels
|
||||
USHORT_565, //!< unsigned int (16-bit), encodes 3 RGB channels
|
||||
UINT_2_10_10_10_REV, //!< unsigned normalized 10 bits RGB, 2 bits alpha
|
||||
};
|
||||
|
||||
//! Compressed pixel data types
|
||||
|
||||
@@ -170,6 +170,11 @@ public:
|
||||
assert(format == PixelDataFormat::RGB);
|
||||
bpp = 4;
|
||||
break;
|
||||
case PixelDataType::UINT_2_10_10_10_REV:
|
||||
// Special case, format must be RGBA and uses 4 bytes
|
||||
assert(format == PixelDataFormat::RGBA);
|
||||
bpp = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t bpr = bpp * stride;
|
||||
|
||||
@@ -302,6 +302,8 @@ io::ostream& operator<<(io::ostream& out, PixelDataType format) {
|
||||
CASE(PixelDataType, FLOAT)
|
||||
CASE(PixelDataType, COMPRESSED)
|
||||
CASE(PixelDataType, UINT_10F_11F_11F_REV)
|
||||
CASE(PixelDataType, USHORT_565)
|
||||
CASE(PixelDataType, UINT_2_10_10_10_REV)
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@ constexpr inline GLenum getType(backend::PixelDataType type) noexcept {
|
||||
case PixelDataType::FLOAT: return GL_FLOAT;
|
||||
case PixelDataType::UINT_10F_11F_11F_REV: return GL_UNSIGNED_INT_10F_11F_11F_REV;
|
||||
case PixelDataType::USHORT_565: return GL_UNSIGNED_SHORT_5_6_5;
|
||||
case PixelDataType::UINT_2_10_10_10_REV: return GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
case PixelDataType::COMPRESSED: return 0; // should never happen
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ VkFormat getVkFormat(TextureFormat format) {
|
||||
case TextureFormat::RGBA8: return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case TextureFormat::SRGB8_A8: return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
case TextureFormat::RGBA8_SNORM: return VK_FORMAT_R8G8B8A8_SNORM;
|
||||
case TextureFormat::RGB10_A2: return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
|
||||
case TextureFormat::RGB10_A2: return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
|
||||
case TextureFormat::RGBA8UI: return VK_FORMAT_R8G8B8A8_UINT;
|
||||
case TextureFormat::RGBA8I: return VK_FORMAT_R8G8B8A8_SINT;
|
||||
case TextureFormat::DEPTH32F: return VK_FORMAT_D32_SFLOAT;
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace utils;
|
||||
@@ -368,17 +370,35 @@ size_t selectLutDimension(ColorGrading::QualityLevel quality) {
|
||||
}
|
||||
}
|
||||
|
||||
TextureFormat selectLutTextureFormat(ColorGrading::QualityLevel quality) {
|
||||
void selectLutTextureParams(ColorGrading::QualityLevel quality,
|
||||
TextureFormat& internalFormat, PixelDataFormat& format, PixelDataType& type) {
|
||||
// We use RGBA16F for high quality modes instead of RGB16F because RGB16F
|
||||
// is not supported everywhere
|
||||
switch (quality) {
|
||||
case ColorGrading::QualityLevel::LOW: return TextureFormat::RGB10_A2;
|
||||
case ColorGrading::QualityLevel::MEDIUM: return TextureFormat::RGB10_A2;
|
||||
case ColorGrading::QualityLevel::HIGH: return TextureFormat::RGBA16F;
|
||||
case ColorGrading::QualityLevel::ULTRA: return TextureFormat::RGBA16F;
|
||||
case ColorGrading::QualityLevel::LOW:
|
||||
internalFormat = TextureFormat::RGB10_A2;
|
||||
format = PixelDataFormat::RGBA;
|
||||
type = PixelDataType::UINT_2_10_10_10_REV;
|
||||
break;
|
||||
case ColorGrading::QualityLevel::MEDIUM:
|
||||
internalFormat = TextureFormat::RGB10_A2;
|
||||
format = PixelDataFormat::RGBA;
|
||||
type = PixelDataType::UINT_2_10_10_10_REV;
|
||||
break;
|
||||
case ColorGrading::QualityLevel::HIGH:
|
||||
internalFormat = TextureFormat::RGBA16F;
|
||||
format = PixelDataFormat::RGBA;
|
||||
type = PixelDataType::HALF;
|
||||
break;
|
||||
case ColorGrading::QualityLevel::ULTRA:
|
||||
internalFormat = TextureFormat::RGBA16F;
|
||||
format = PixelDataFormat::RGBA;
|
||||
type = PixelDataType::HALF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tone mapping
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -433,8 +453,8 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
|
||||
size_t lutElementCount = config.lutDimension * config.lutDimension * config.lutDimension;
|
||||
|
||||
constexpr size_t elementSize = sizeof(half4);
|
||||
void* const data = malloc(lutElementCount * elementSize);
|
||||
size_t elementSize = sizeof(half4);
|
||||
void* data = malloc(lutElementCount * elementSize);
|
||||
|
||||
//auto now = std::chrono::steady_clock::now();
|
||||
|
||||
@@ -508,6 +528,8 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
// TODO: allow to customize the output color space,
|
||||
v = config.colorGradingTransformOut * v;
|
||||
|
||||
v = saturate(v);
|
||||
|
||||
// Apply OECF
|
||||
v = OECF_sRGB(v);
|
||||
|
||||
@@ -525,17 +547,41 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
//std::chrono::duration<float, std::milli> duration = std::chrono::steady_clock::now() - now;
|
||||
//slog.d << "LUT generation time: " << duration.count() << " ms" << io::endl;
|
||||
|
||||
TextureFormat textureFormat = selectLutTextureFormat(builder->quality);
|
||||
TextureFormat textureFormat;
|
||||
PixelDataFormat format;
|
||||
PixelDataType type;
|
||||
selectLutTextureParams(builder->quality, textureFormat, format, type);
|
||||
|
||||
mLutHandle = driver.createTexture(SamplerType::SAMPLER_3D, 1, textureFormat, 0,
|
||||
config.lutDimension, config.lutDimension, config.lutDimension, TextureUsage::DEFAULT);
|
||||
|
||||
// convert input to UINT_2_10_10_10_REV if needed
|
||||
if (type == PixelDataType::UINT_2_10_10_10_REV) {
|
||||
uint32_t* const UTILS_RESTRICT dst = (uint32_t*)malloc(lutElementCount * sizeof(uint32_t));
|
||||
half4 const* UTILS_RESTRICT src = (half4*)data;
|
||||
|
||||
// we use a vectorize width of 8 because, on ARMv8 it allows the compiler to write eight
|
||||
// 32-bits results in one go.
|
||||
const size_t count = lutElementCount & ~0x7; // tell the compiler that we're a multiple of 8
|
||||
#pragma clang loop vectorize_width(8)
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
float4 v{ src[i] };
|
||||
uint32_t r = uint32_t(floorf(v.x * 1023.0f + 0.5f));
|
||||
uint32_t g = uint32_t(floorf(v.y * 1023.0f + 0.5f));
|
||||
uint32_t b = uint32_t(floorf(v.z * 1023.0f + 0.5f));
|
||||
dst[i] = (b << 20u) | (g << 10u) | r;
|
||||
}
|
||||
|
||||
free(data);
|
||||
data = (void*)dst;
|
||||
elementSize = sizeof(uint32_t);
|
||||
}
|
||||
|
||||
driver.update3DImage(mLutHandle, 0,
|
||||
0, 0, 0,
|
||||
config.lutDimension, config.lutDimension, config.lutDimension,
|
||||
PixelBufferDescriptor{
|
||||
data, lutElementCount * elementSize,
|
||||
PixelDataFormat::RGBA, PixelDataType::HALF,
|
||||
data, lutElementCount * elementSize,format, type,
|
||||
[](void* buffer, size_t, void*) { free(buffer); }
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user