16# include <OpenColorIO/OpenColorIO.h>
17namespace OCIO = OCIO_NAMESPACE;
31static unordered_map<ustring, ustring, ustringHash> cached_colorspaces;
32static unordered_map<ustring, OCIO::ConstProcessorRcPtr, ustringHash> cached_processors;
45 OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
53 if (cached_processors.find(colorspace) == cached_processors.end()) {
55 cached_processors[colorspace] = config->getProcessor(colorspace.c_str(),
"scene_linear");
57 catch (OCIO::Exception &exception) {
58 cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
60 <<
" can't be converted to scene_linear: " << exception.what();
64 const OCIO::Processor *processor = cached_processors[colorspace].get();
65 return (ColorSpaceProcessor *)processor;
82 OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
88 OCIO::ConstColorSpaceRcPtr space = config->getColorSpace(colorspace.c_str());
89 return space && space->isData();
91 catch (OCIO::Exception &) {
100 const char *file_colorspace,
101 const char *file_format,
107 bool srgb = (strcmp(file_colorspace,
"sRGB") == 0 ||
108 strcmp(file_colorspace,
"GammaCorrected") == 0 ||
109 (file_colorspace[0] ==
'\0' &&
110 (strcmp(file_format,
"png") == 0 || strcmp(file_format,
"jpeg") == 0 ||
111 strcmp(file_format,
"tiff") == 0 || strcmp(file_format,
"dpx") == 0 ||
112 strcmp(file_format,
"jpeg2000") == 0)));
129 if (cached_colorspaces.find(colorspace) != cached_colorspaces.end()) {
130 return cached_colorspaces[colorspace];
135 bool is_scene_linear, is_srgb;
136 is_builtin_colorspace(colorspace, is_scene_linear, is_srgb);
139 if (is_scene_linear) {
140 VLOG_INFO <<
"Colorspace " << colorspace.string() <<
" is no-op";
145 VLOG_INFO <<
"Colorspace " << colorspace.string() <<
" is sRGB";
152 OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
153 if (!config || !config->getColorSpace(colorspace.c_str())) {
154 VLOG_WARNING <<
"Colorspace " << colorspace.c_str() <<
" not found, using raw instead";
158 <<
" can't be converted to scene_linear, using raw instead";
165 VLOG_INFO <<
"Colorspace " << colorspace.string() <<
" handled through OpenColorIO";
166 cached_colorspaces[colorspace] = colorspace;
170 <<
" not available, built without OpenColorIO";
176void ColorSpaceManager::is_builtin_colorspace(ustring colorspace,
177 bool &is_scene_linear,
181 const OCIO::Processor *processor = (
const OCIO::Processor *)
get_processor(colorspace);
183 is_scene_linear =
false;
188 OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
189 is_scene_linear =
true;
191 for (
int i = 0; i < 256; i++) {
192 float v = i / 255.0f;
194 float cR[3] = {
v, 0, 0};
195 float cG[3] = {0,
v, 0};
196 float cB[3] = {0, 0,
v};
197 float cW[3] = {
v,
v,
v};
198 device_processor->applyRGB(cR);
199 device_processor->applyRGB(cG);
200 device_processor->applyRGB(cB);
201 device_processor->applyRGB(cW);
204 if (
fabsf(cR[1]) > 1e-5f ||
fabsf(cR[2]) > 1e-5f ||
fabsf(cG[0]) > 1e-5f ||
207 is_scene_linear =
false;
215 is_scene_linear =
false;
221 is_scene_linear =
false;
228 is_scene_linear =
false;
236 is_scene_linear =
false;
243template<
typename T>
inline float4 cast_to_float4(T *data)
251template<
typename T>
inline void cast_from_float4(T *data, float4 value)
260template<
typename T,
bool compress_as_srgb = false>
261inline void processor_apply_pixels_rgba(
const OCIO::Processor *processor,
268 OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
271 const size_t chunk_size = std::min((
size_t)(16 * 1024 * 1024), num_pixels);
274 for (
size_t j = 0; j < num_pixels; j += chunk_size) {
275 size_t width = std::min(chunk_size, num_pixels - j);
277 for (
size_t i = 0; i < width; i++) {
278 float4 value = cast_to_float4(pixels + 4 * (j + i));
280 if (!(value.w <= 0.0f || value.w == 1.0f)) {
281 float inv_alpha = 1.0f / value.w;
282 value.x *= inv_alpha;
283 value.y *= inv_alpha;
284 value.z *= inv_alpha;
287 float_pixels[i] = value;
290 OCIO::PackedImageDesc desc((
float *)float_pixels.data(), width, 1, 4);
291 device_processor->apply(desc);
293 for (
size_t i = 0; i < width; i++) {
294 float4 value = float_pixels[i];
296 if (compress_as_srgb) {
300 if (!(value.w <= 0.0f || value.w == 1.0f)) {
306 cast_from_float4(pixels + 4 * (j + i), value);
311template<
typename T,
bool compress_as_srgb = false>
312inline void processor_apply_pixels_grayscale(
const OCIO::Processor *processor,
316 OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
319 const size_t chunk_size = std::min((
size_t)(16 * 1024 * 1024), num_pixels);
322 for (
size_t j = 0; j < num_pixels; j += chunk_size) {
323 size_t width = std::min(chunk_size, num_pixels - j);
327 const T *pixel = pixels + j;
328 float *fpixel = float_pixels.data();
329 for (
size_t i = 0; i < width; i++, pixel++, fpixel += 3) {
337 OCIO::PackedImageDesc desc((
float *)float_pixels.data(), width, 1, 3);
338 device_processor->apply(desc);
341 T *pixel = pixels + j;
342 const float *fpixel = float_pixels.data();
343 for (
size_t i = 0; i < width; i++, pixel++, fpixel += 3) {
345 if (compress_as_srgb) {
358 ustring colorspace, T *pixels,
size_t num_pixels,
bool is_rgba,
bool compress_as_srgb)
361 const OCIO::Processor *processor = (
const OCIO::Processor *)
get_processor(colorspace);
365 if (compress_as_srgb) {
367 processor_apply_pixels_rgba<T, true>(processor, pixels, num_pixels);
371 processor_apply_pixels_rgba<T>(processor, pixels, num_pixels);
375 if (compress_as_srgb) {
377 processor_apply_pixels_grayscale<T, true>(processor, pixels, num_pixels);
381 processor_apply_pixels_grayscale<T>(processor, pixels, num_pixels);
390 (void)compress_as_srgb;
399 const OCIO::Processor *processor = (
const OCIO::Processor *)processor_;
402 OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
405 device_processor->applyRGB(&rgb.
x);
409 device_processor->applyRGB(pixel);
411 else if (channels == 4) {
412 if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
414 device_processor->applyRGB(pixel);
419 float alpha = pixel[3];
420 float inv_alpha = 1.0f / alpha;
422 pixel[0] *= inv_alpha;
423 pixel[1] *= inv_alpha;
424 pixel[2] *= inv_alpha;
426 device_processor->applyRGB(pixel);
452 OCIO::SetCurrentConfig(OCIO::Config::CreateRaw());
ATTR_WARN_UNUSED_RESULT const BMVert * v
static bool colorspace_is_data(ustring colorspace)
static ustring detect_known_colorspace(ustring colorspace, const char *file_colorspace, const char *file_format, bool is_float)
static void to_scene_linear(ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb)
static void free_memory()
static ColorSpaceProcessor * get_processor(ustring colorspace)
static void init_fallback_config()
CCL_NAMESPACE_BEGIN ustring u_colorspace_auto
ustring u_colorspace_srgb
CCL_NAMESPACE_BEGIN ustring u_colorspace_auto
float util_image_cast_to_float(T value)
T util_image_cast_from_float(float value)
static void map_free_memory(T &data)
#define CCL_NAMESPACE_END
ccl_device_inline float average(const float2 a)
VecBase< float, 4 > float4
std::unique_lock< std::mutex > thread_scoped_lock
CCL_NAMESPACE_BEGIN typedef std::mutex thread_mutex
ccl_device float color_linear_to_srgb(float c)
ccl_device float4 color_linear_to_srgb_v4(float4 c)
ccl_device float color_srgb_to_linear(float c)
ccl_device_inline bool compare_floats(float a, float b, float abs_diff, int ulp_diff)