28 # include <OpenColorIO/OpenColorIO.h>
29 namespace OCIO = OCIO_NAMESPACE;
43 static unordered_map<ustring, ustring, ustringHash> cached_colorspaces;
44 static unordered_map<ustring, OCIO::ConstProcessorRcPtr, ustringHash> cached_processors;
57 OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
65 if (cached_processors.find(colorspace) == cached_processors.end()) {
67 cached_processors[colorspace] = config->getProcessor(colorspace.c_str(),
"scene_linear");
69 catch (OCIO::Exception &exception) {
70 cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
71 VLOG(1) <<
"Colorspace " << colorspace.c_str()
72 <<
" can't be converted to scene_linear: " << exception.what();
76 const OCIO::Processor *processor = cached_processors[colorspace].get();
77 return (ColorSpaceProcessor *)processor;
93 OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
99 OCIO::ConstColorSpaceRcPtr space = config->getColorSpace(colorspace.c_str());
100 return space && space->isData();
102 catch (OCIO::Exception &) {
111 const char *file_format,
117 bool srgb = (colorspace ==
"sRGB" || colorspace ==
"GammaCorrected" ||
118 (colorspace.empty() &&
119 (strcmp(file_format,
"png") == 0 || strcmp(file_format,
"tiff") == 0 ||
120 strcmp(file_format,
"dpx") == 0 || strcmp(file_format,
"jpeg2000") == 0)));
137 if (cached_colorspaces.find(colorspace) != cached_colorspaces.end()) {
138 return cached_colorspaces[colorspace];
143 bool is_scene_linear, is_srgb;
144 is_builtin_colorspace(colorspace, is_scene_linear, is_srgb);
147 if (is_scene_linear) {
148 VLOG(1) <<
"Colorspace " << colorspace.string() <<
" is no-op";
153 VLOG(1) <<
"Colorspace " << colorspace.string() <<
" is sRGB";
160 OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
161 if (!config || !config->getColorSpace(colorspace.c_str())) {
162 VLOG(1) <<
"Colorspace " << colorspace.c_str() <<
" not found, using raw instead";
165 VLOG(1) <<
"Colorspace " << colorspace.c_str()
166 <<
" can't be converted to scene_linear, using raw instead";
173 VLOG(1) <<
"Colorspace " << colorspace.string() <<
" handled through OpenColorIO";
174 cached_colorspaces[colorspace] = colorspace;
177 VLOG(1) <<
"Colorspace " << colorspace.c_str() <<
" not available, built without OpenColorIO";
183 void ColorSpaceManager::is_builtin_colorspace(ustring colorspace,
184 bool &is_scene_linear,
188 const OCIO::Processor *processor = (
const OCIO::Processor *)
get_processor(colorspace);
190 is_scene_linear =
false;
195 OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
196 is_scene_linear =
true;
198 for (
int i = 0; i < 256; i++) {
199 float v = i / 255.0f;
201 float cR[3] = {
v, 0, 0};
202 float cG[3] = {0,
v, 0};
203 float cB[3] = {0, 0,
v};
204 float cW[3] = {
v,
v,
v};
205 device_processor->applyRGB(cR);
206 device_processor->applyRGB(cG);
207 device_processor->applyRGB(cB);
208 device_processor->applyRGB(cW);
211 if (
fabsf(cR[1]) > 1e-5f ||
fabsf(cR[2]) > 1e-5f ||
fabsf(cG[0]) > 1e-5f ||
212 fabsf(cG[2]) > 1e-5f ||
fabsf(cB[0]) > 1e-5f ||
fabsf(cB[1]) > 1e-5f) {
213 is_scene_linear =
false;
220 is_scene_linear =
false;
226 is_scene_linear =
false;
233 is_scene_linear =
false;
241 is_scene_linear =
false;
248 template<
typename T>
inline float4 cast_to_float4(
T *
data)
256 template<
typename T>
inline void cast_from_float4(
T *
data, float4 value)
258 data[0] = util_image_cast_from_float<T>(value.x);
259 data[1] = util_image_cast_from_float<T>(value.y);
260 data[2] = util_image_cast_from_float<T>(value.z);
261 data[3] = util_image_cast_from_float<T>(value.w);
265 template<
typename T,
bool compress_as_srgb = false>
266 inline void processor_apply_pixels(
const OCIO::Processor *processor,
T *pixels,
size_t num_pixels)
271 OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
274 const size_t chunk_size =
std::min((
size_t)(16 * 1024 * 1024), num_pixels);
277 for (
size_t j = 0; j < num_pixels; j += chunk_size) {
280 for (
size_t i = 0; i <
width; i++) {
281 float4 value = cast_to_float4(pixels + 4 * (j + i));
283 if (!(value.w <= 0.0f || value.w == 1.0f)) {
284 float inv_alpha = 1.0f / value.w;
285 value.x *= inv_alpha;
286 value.y *= inv_alpha;
287 value.z *= inv_alpha;
290 float_pixels[i] = value;
293 OCIO::PackedImageDesc desc((
float *)float_pixels.data(),
width, 1, 4);
294 device_processor->apply(desc);
296 for (
size_t i = 0; i <
width; i++) {
297 float4 value = float_pixels[i];
299 if (compress_as_srgb) {
303 if (!(value.w <= 0.0f || value.w == 1.0f)) {
309 cast_from_float4(pixels + 4 * (j + i), value);
319 bool compress_as_srgb)
322 const OCIO::Processor *processor = (
const OCIO::Processor *)
get_processor(colorspace);
325 if (compress_as_srgb) {
327 processor_apply_pixels<T, true>(processor, pixels, num_pixels);
331 processor_apply_pixels<T>(processor, pixels, num_pixels);
338 (void)compress_as_srgb;
347 const OCIO::Processor *processor = (
const OCIO::Processor *)processor_;
350 OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
352 device_processor->applyRGB(pixel);
354 else if (channels == 4) {
355 if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
357 device_processor->applyRGB(pixel);
362 float alpha = pixel[3];
363 float inv_alpha = 1.0f /
alpha;
365 pixel[0] *= inv_alpha;
366 pixel[1] *= inv_alpha;
367 pixel[2] *= inv_alpha;
369 device_processor->applyRGB(pixel);
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
ATTR_WARN_UNUSED_RESULT const BMVert * v
static bool colorspace_is_data(ustring colorspace)
static void free_memory()
static void to_scene_linear(ustring colorspace, T *pixels, size_t num_pixels, bool compress_as_srgb)
static ColorSpaceProcessor * get_processor(ustring colorspace)
static ustring detect_known_colorspace(ustring colorspace, const char *file_format, bool is_float)
ustring u_colorspace_srgb("__builtin_srgb")
CCL_NAMESPACE_BEGIN ustring u_colorspace_auto
ustring u_colorspace_raw("__builtin_raw")
static CCL_NAMESPACE_BEGIN const double alpha
#define CCL_NAMESPACE_END
#define make_float4(x, y, z, w)
#define make_float3(x, y, z)
ccl_device float4 color_linear_to_srgb_v4(float4 c)
ccl_device float color_srgb_to_linear(float c)
float util_image_cast_to_float(T value)
static void map_free_memory(T &data)
ccl_device_inline float compare_floats(float a, float b, float abs_diff, int ulp_diff)
ccl_device_inline float average(const float2 &a)
std::unique_lock< std::mutex > thread_scoped_lock
CCL_NAMESPACE_BEGIN typedef std::mutex thread_mutex