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:
Pixelflinger
2020-07-24 16:05:32 -07:00
committed by Mathias Agopian
parent 087e2480d1
commit e34db6fc29
6 changed files with 67 additions and 12 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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
}
}

View File

@@ -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;

View File

@@ -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); }
}
);