colorspace.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /*
  2. * Copyright 2011-2013 Blender Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "render/colorspace.h"
  17. #include "util/util_color.h"
  18. #include "util/util_image.h"
  19. #include "util/util_half.h"
  20. #include "util/util_logging.h"
  21. #include "util/util_math.h"
  22. #include "util/util_thread.h"
  23. #include "util/util_vector.h"
  24. #ifdef WITH_OCIO
  25. # include <OpenColorIO/OpenColorIO.h>
  26. namespace OCIO = OCIO_NAMESPACE;
  27. #endif
  28. CCL_NAMESPACE_BEGIN
  29. /* Builtin colorspaces. */
  30. ustring u_colorspace_auto;
  31. ustring u_colorspace_raw("__builtin_raw");
  32. ustring u_colorspace_srgb("__builtin_srgb");
  33. /* Cached data. */
  34. #ifdef WITH_OCIO
  35. static thread_mutex cache_colorspaces_mutex;
  36. static thread_mutex cache_processors_mutex;
  37. static unordered_map<ustring, ustring, ustringHash> cached_colorspaces;
  38. static unordered_map<ustring, OCIO::ConstProcessorRcPtr, ustringHash> cached_processors;
  39. #endif
  40. ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace)
  41. {
  42. #ifdef WITH_OCIO
  43. /* Only use this for OpenColorIO color spaces, not the builtin ones. */
  44. assert(colorspace != u_colorspace_srgb && colorspace != u_colorspace_auto);
  45. if (colorspace == u_colorspace_raw) {
  46. return NULL;
  47. }
  48. OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
  49. if (!config) {
  50. return NULL;
  51. }
  52. /* Cache processor until free_memory(), memory overhead is expected to be
  53. * small and the processor is likely to be reused. */
  54. thread_scoped_lock cache_processors_lock(cache_processors_mutex);
  55. if (cached_processors.find(colorspace) == cached_processors.end()) {
  56. try {
  57. cached_processors[colorspace] = config->getProcessor(colorspace.c_str(), "scene_linear");
  58. }
  59. catch (OCIO::Exception &exception) {
  60. cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
  61. VLOG(1) << "Colorspace " << colorspace.c_str()
  62. << " can't be converted to scene_linear: " << exception.what();
  63. }
  64. }
  65. const OCIO::Processor *processor = cached_processors[colorspace].get();
  66. return (ColorSpaceProcessor *)processor;
  67. #else
  68. /* No OpenColorIO. */
  69. (void)colorspace;
  70. return NULL;
  71. #endif
  72. }
  73. bool ColorSpaceManager::colorspace_is_data(ustring colorspace)
  74. {
  75. if (colorspace == u_colorspace_auto || colorspace == u_colorspace_raw ||
  76. colorspace == u_colorspace_srgb) {
  77. return false;
  78. }
  79. #ifdef WITH_OCIO
  80. OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
  81. if (!config) {
  82. return false;
  83. }
  84. try {
  85. OCIO::ConstColorSpaceRcPtr space = config->getColorSpace(colorspace.c_str());
  86. return space && space->isData();
  87. }
  88. catch (OCIO::Exception &) {
  89. return false;
  90. }
  91. #else
  92. return false;
  93. #endif
  94. }
  95. ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
  96. const char *file_format,
  97. bool is_float)
  98. {
  99. if (colorspace == u_colorspace_auto) {
  100. /* Auto detect sRGB or raw if none specified. */
  101. if (is_float) {
  102. bool srgb = (colorspace == "sRGB" || colorspace == "GammaCorrected" ||
  103. (colorspace.empty() &&
  104. (strcmp(file_format, "png") == 0 || strcmp(file_format, "tiff") == 0 ||
  105. strcmp(file_format, "dpx") == 0 || strcmp(file_format, "jpeg2000") == 0)));
  106. return srgb ? u_colorspace_srgb : u_colorspace_raw;
  107. }
  108. else {
  109. return u_colorspace_srgb;
  110. }
  111. }
  112. else if (colorspace == u_colorspace_srgb || colorspace == u_colorspace_raw) {
  113. /* Builtin colorspaces. */
  114. return colorspace;
  115. }
  116. else {
  117. /* Use OpenColorIO. */
  118. #ifdef WITH_OCIO
  119. {
  120. thread_scoped_lock cache_lock(cache_colorspaces_mutex);
  121. /* Cached lookup. */
  122. if (cached_colorspaces.find(colorspace) != cached_colorspaces.end()) {
  123. return cached_colorspaces[colorspace];
  124. }
  125. }
  126. /* Detect if it matches a simple builtin colorspace. */
  127. bool is_scene_linear, is_srgb;
  128. is_builtin_colorspace(colorspace, is_scene_linear, is_srgb);
  129. thread_scoped_lock cache_lock(cache_colorspaces_mutex);
  130. if (is_scene_linear) {
  131. VLOG(1) << "Colorspace " << colorspace.string() << " is no-op";
  132. cached_colorspaces[colorspace] = u_colorspace_raw;
  133. return u_colorspace_raw;
  134. }
  135. else if (is_srgb) {
  136. VLOG(1) << "Colorspace " << colorspace.string() << " is sRGB";
  137. cached_colorspaces[colorspace] = u_colorspace_srgb;
  138. return u_colorspace_srgb;
  139. }
  140. /* Verify if we can convert from the requested color space. */
  141. if (!get_processor(colorspace)) {
  142. OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
  143. if (!config || !config->getColorSpace(colorspace.c_str())) {
  144. VLOG(1) << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
  145. }
  146. else {
  147. VLOG(1) << "Colorspace " << colorspace.c_str()
  148. << " can't be converted to scene_linear, using raw instead";
  149. }
  150. cached_colorspaces[colorspace] = u_colorspace_raw;
  151. return u_colorspace_raw;
  152. }
  153. /* Convert to/from colorspace with OpenColorIO. */
  154. VLOG(1) << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
  155. cached_colorspaces[colorspace] = colorspace;
  156. return colorspace;
  157. #else
  158. VLOG(1) << "Colorspace " << colorspace.c_str() << " not available, built without OpenColorIO";
  159. return u_colorspace_raw;
  160. #endif
  161. }
  162. }
  163. void ColorSpaceManager::is_builtin_colorspace(ustring colorspace,
  164. bool &is_scene_linear,
  165. bool &is_srgb)
  166. {
  167. #ifdef WITH_OCIO
  168. const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
  169. if (!processor) {
  170. is_scene_linear = false;
  171. is_srgb = false;
  172. return;
  173. }
  174. is_scene_linear = true;
  175. is_srgb = true;
  176. for (int i = 0; i < 256; i++) {
  177. float v = i / 255.0f;
  178. float cR[3] = {v, 0, 0};
  179. float cG[3] = {0, v, 0};
  180. float cB[3] = {0, 0, v};
  181. float cW[3] = {v, v, v};
  182. processor->applyRGB(cR);
  183. processor->applyRGB(cG);
  184. processor->applyRGB(cB);
  185. processor->applyRGB(cW);
  186. /* Make sure that there is no channel crosstalk. */
  187. if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f ||
  188. fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f) {
  189. is_scene_linear = false;
  190. is_srgb = false;
  191. break;
  192. }
  193. /* Make sure that the three primaries combine linearly. */
  194. if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) ||
  195. !compare_floats(cB[2], cW[2], 1e-6f, 64)) {
  196. is_scene_linear = false;
  197. is_srgb = false;
  198. break;
  199. }
  200. /* Make sure that the three channels behave identically. */
  201. if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) {
  202. is_scene_linear = false;
  203. is_srgb = false;
  204. break;
  205. }
  206. float out_v = average(make_float3(cW[0], cW[1], cW[2]));
  207. if (!compare_floats(v, out_v, 1e-6f, 64)) {
  208. is_scene_linear = false;
  209. }
  210. if (!compare_floats(color_srgb_to_linear(v), out_v, 1e-6f, 64)) {
  211. is_srgb = false;
  212. }
  213. }
  214. #else
  215. (void)colorspace;
  216. is_scene_linear = false;
  217. is_srgb = false;
  218. #endif
  219. }
  220. #ifdef WITH_OCIO
  221. template<typename T> inline float4 cast_to_float4(T *data)
  222. {
  223. return make_float4(util_image_cast_to_float(data[0]),
  224. util_image_cast_to_float(data[1]),
  225. util_image_cast_to_float(data[2]),
  226. util_image_cast_to_float(data[3]));
  227. }
  228. template<typename T> inline void cast_from_float4(T *data, float4 value)
  229. {
  230. data[0] = util_image_cast_from_float<T>(value.x);
  231. data[1] = util_image_cast_from_float<T>(value.y);
  232. data[2] = util_image_cast_from_float<T>(value.z);
  233. data[3] = util_image_cast_from_float<T>(value.w);
  234. }
  235. /* Slower versions for other all data types, which needs to convert to float and back. */
  236. template<typename T, bool compress_as_srgb = false>
  237. inline void processor_apply_pixels(const OCIO::Processor *processor,
  238. T *pixels,
  239. size_t width,
  240. size_t height)
  241. {
  242. /* TODO: implement faster version for when we know the conversion
  243. * is a simple matrix transform between linear spaces. In that case
  244. * unpremultiply is not needed. */
  245. /* Process large images in chunks to keep temporary memory requirement down. */
  246. size_t y_chunk_size = max(1, 16 * 1024 * 1024 / (sizeof(float4) * width));
  247. vector<float4> float_pixels(y_chunk_size * width);
  248. for (size_t y0 = 0; y0 < height; y0 += y_chunk_size) {
  249. size_t y1 = std::min(y0 + y_chunk_size, height);
  250. size_t i = 0;
  251. for (size_t y = y0; y < y1; y++) {
  252. for (size_t x = 0; x < width; x++, i++) {
  253. float4 value = cast_to_float4(pixels + 4 * (y * width + x));
  254. if (!(value.w == 0.0f || value.w == 1.0f)) {
  255. float inv_alpha = 1.0f / value.w;
  256. value.x *= inv_alpha;
  257. value.y *= inv_alpha;
  258. value.z *= inv_alpha;
  259. }
  260. float_pixels[i] = value;
  261. }
  262. }
  263. OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, y_chunk_size, 4);
  264. processor->apply(desc);
  265. i = 0;
  266. for (size_t y = y0; y < y1; y++) {
  267. for (size_t x = 0; x < width; x++, i++) {
  268. float4 value = float_pixels[i];
  269. value.x *= value.w;
  270. value.y *= value.w;
  271. value.z *= value.w;
  272. if (compress_as_srgb) {
  273. value = color_linear_to_srgb_v4(value);
  274. }
  275. cast_from_float4(pixels + 4 * (y * width + x), value);
  276. }
  277. }
  278. }
  279. }
  280. #endif
  281. template<typename T>
  282. void ColorSpaceManager::to_scene_linear(ustring colorspace,
  283. T *pixels,
  284. size_t width,
  285. size_t height,
  286. size_t depth,
  287. bool compress_as_srgb)
  288. {
  289. #ifdef WITH_OCIO
  290. const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
  291. if (processor) {
  292. if (compress_as_srgb) {
  293. /* Compress output as sRGB. */
  294. for (size_t z = 0; z < depth; z++) {
  295. processor_apply_pixels<T, true>(processor, &pixels[z * width * height], width, height);
  296. }
  297. }
  298. else {
  299. /* Write output as scene linear directly. */
  300. for (size_t z = 0; z < depth; z++) {
  301. processor_apply_pixels<T>(processor, &pixels[z * width * height], width, height);
  302. }
  303. }
  304. }
  305. #else
  306. (void)colorspace;
  307. (void)pixels;
  308. (void)width;
  309. (void)height;
  310. (void)depth;
  311. (void)compress_as_srgb;
  312. #endif
  313. }
  314. void ColorSpaceManager::to_scene_linear(ColorSpaceProcessor *processor_,
  315. float *pixel,
  316. int channels)
  317. {
  318. #ifdef WITH_OCIO
  319. const OCIO::Processor *processor = (const OCIO::Processor *)processor_;
  320. if (processor) {
  321. if (channels == 3) {
  322. processor->applyRGB(pixel);
  323. }
  324. else if (channels == 4) {
  325. if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
  326. /* Fast path for RGBA. */
  327. processor->applyRGB(pixel);
  328. }
  329. else {
  330. /* Unassociate and associate alpha since color management should not
  331. * be affected by transparency. */
  332. float alpha = pixel[3];
  333. float inv_alpha = 1.0f / alpha;
  334. pixel[0] *= inv_alpha;
  335. pixel[1] *= inv_alpha;
  336. pixel[2] *= inv_alpha;
  337. processor->applyRGB(pixel);
  338. pixel[0] *= alpha;
  339. pixel[1] *= alpha;
  340. pixel[2] *= alpha;
  341. }
  342. }
  343. }
  344. #else
  345. (void)processor_;
  346. (void)pixel;
  347. (void)channels;
  348. #endif
  349. }
  350. void ColorSpaceManager::free_memory()
  351. {
  352. #ifdef WITH_OCIO
  353. map_free_memory(cached_colorspaces);
  354. map_free_memory(cached_colorspaces);
  355. #endif
  356. }
  357. /* Template instanstations so we don't have to inline functions. */
  358. template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, size_t, size_t, bool);
  359. template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, size_t, size_t, bool);
  360. template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, size_t, size_t, bool);
  361. template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, size_t, size_t, bool);
  362. CCL_NAMESPACE_END