16# include <OpenColorIO/OpenColorIO.h>
17namespace OCIO = OCIO_NAMESPACE;
31static unordered_map<ustring, ustring> cached_colorspaces;
32static unordered_map<ustring, OCIO::ConstProcessorRcPtr> 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);
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());
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
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)