diff options
author | Brecht Van Lommel <brecht@blender.org> | 2022-01-20 21:09:41 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2022-01-20 22:40:55 +0300 |
commit | 24e00c115c5191da273e3ecf63f366ae7963bc57 (patch) | |
tree | 24c3cf77134280944b6089aae8031ea7e6ea9706 /intern/cycles | |
parent | 2559d79d2f8db16ad6152529345290f47e8cc31e (diff) |
Fix T94712: Cycles missing colorspace transform on grayscale images
Diffstat (limited to 'intern/cycles')
-rw-r--r-- | intern/cycles/scene/colorspace.cpp | 89 | ||||
-rw-r--r-- | intern/cycles/scene/colorspace.h | 6 | ||||
-rw-r--r-- | intern/cycles/scene/image.cpp | 12 |
3 files changed, 83 insertions, 24 deletions
diff --git a/intern/cycles/scene/colorspace.cpp b/intern/cycles/scene/colorspace.cpp index c1a308fcbaa..f0b7eb724de 100644 --- a/intern/cycles/scene/colorspace.cpp +++ b/intern/cycles/scene/colorspace.cpp @@ -263,7 +263,9 @@ template<typename T> inline void cast_from_float4(T *data, float4 value) /* Slower versions for other all data types, which needs to convert to float and back. */ template<typename T, bool compress_as_srgb = false> -inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels, size_t num_pixels) +inline void processor_apply_pixels_rgba(const OCIO::Processor *processor, + T *pixels, + size_t num_pixels) { /* TODO: implement faster version for when we know the conversion * is a simple matrix transform between linear spaces. In that case @@ -310,25 +312,79 @@ inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels, } } } + +template<typename T, bool compress_as_srgb = false> +inline void processor_apply_pixels_grayscale(const OCIO::Processor *processor, + T *pixels, + size_t num_pixels) +{ + OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor(); + + /* Process large images in chunks to keep temporary memory requirement down. */ + const size_t chunk_size = std::min((size_t)(16 * 1024 * 1024), num_pixels); + vector<float> float_pixels(chunk_size * 3); + + for (size_t j = 0; j < num_pixels; j += chunk_size) { + size_t width = std::min(chunk_size, num_pixels - j); + + /* Convert to 3 channels, since that's the minimum required by OpenColorIO. */ + { + const T *pixel = pixels + j; + float *fpixel = float_pixels.data(); + for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) { + const float f = util_image_cast_to_float<T>(*pixel); + fpixel[0] = f; + fpixel[1] = f; + fpixel[2] = f; + } + } + + OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, 1, 3); + device_processor->apply(desc); + + { + T *pixel = pixels + j; + const float *fpixel = float_pixels.data(); + for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) { + float f = average(make_float3(fpixel[0], fpixel[1], fpixel[2])); + if (compress_as_srgb) { + f = color_linear_to_srgb(f); + } + *pixel = util_image_cast_from_float<T>(f); + } + } + } +} + #endif template<typename T> -void ColorSpaceManager::to_scene_linear(ustring colorspace, - T *pixels, - size_t num_pixels, - bool compress_as_srgb) +void ColorSpaceManager::to_scene_linear( + ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb) { #ifdef WITH_OCIO const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace); if (processor) { - if (compress_as_srgb) { - /* Compress output as sRGB. */ - processor_apply_pixels<T, true>(processor, pixels, num_pixels); + if (is_rgba) { + if (compress_as_srgb) { + /* Compress output as sRGB. */ + processor_apply_pixels_rgba<T, true>(processor, pixels, num_pixels); + } + else { + /* Write output as scene linear directly. */ + processor_apply_pixels_rgba<T>(processor, pixels, num_pixels); + } } else { - /* Write output as scene linear directly. */ - processor_apply_pixels<T>(processor, pixels, num_pixels); + if (compress_as_srgb) { + /* Compress output as sRGB. */ + processor_apply_pixels_grayscale<T, true>(processor, pixels, num_pixels); + } + else { + /* Write output as scene linear directly. */ + processor_apply_pixels_grayscale<T>(processor, pixels, num_pixels); + } } } #else @@ -348,6 +404,11 @@ void ColorSpaceManager::to_scene_linear(ColorSpaceProcessor *processor_, if (processor) { OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor(); + if (channels == 1) { + float3 rgb = make_float3(pixel[0], pixel[0], pixel[0]); + device_processor->applyRGB(&rgb.x); + pixel[0] = average(rgb); + } if (channels == 3) { device_processor->applyRGB(pixel); } @@ -390,9 +451,9 @@ void ColorSpaceManager::free_memory() } /* Template instantiations so we don't have to inline functions. */ -template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool); -template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool); -template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool); -template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool); +template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool, bool); +template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool, bool); +template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool, bool); +template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool, bool); CCL_NAMESPACE_END diff --git a/intern/cycles/scene/colorspace.h b/intern/cycles/scene/colorspace.h index 7f7bc604f07..f02c1231a44 100644 --- a/intern/cycles/scene/colorspace.h +++ b/intern/cycles/scene/colorspace.h @@ -43,10 +43,8 @@ class ColorSpaceManager { /* Convert pixels in the specified colorspace to scene linear color for * rendering. Must be a colorspace returned from detect_known_colorspace. */ template<typename T> - static void to_scene_linear(ustring colorspace, - T *pixels, - size_t num_pixels, - bool compress_as_srgb); + static void to_scene_linear( + ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb); /* Efficiently convert pixels to scene linear colorspace at render time, * for OSL where the image texture cache contains original pixels. The diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp index 3595ca55a46..dbc8bf213af 100644 --- a/intern/cycles/scene/image.cpp +++ b/intern/cycles/scene/image.cpp @@ -576,13 +576,13 @@ bool ImageManager::file_load_image(Image *img, int texture_limit) pixels[i * 4 + 3] = one; } } + } - if (img->metadata.colorspace != u_colorspace_raw && - img->metadata.colorspace != u_colorspace_srgb) { - /* Convert to scene linear. */ - ColorSpaceManager::to_scene_linear( - img->metadata.colorspace, pixels, num_pixels, img->metadata.compress_as_srgb); - } + if (img->metadata.colorspace != u_colorspace_raw && + img->metadata.colorspace != u_colorspace_srgb) { + /* Convert to scene linear. */ + ColorSpaceManager::to_scene_linear( + img->metadata.colorspace, pixels, num_pixels, is_rgba, img->metadata.compress_as_srgb); } /* Make sure we don't have buggy values. */ |