diff options
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r-- | source/blender/imbuf/IMB_colormanagement.h | 13 | ||||
-rw-r--r-- | source/blender/imbuf/intern/IMB_colormanagement_intern.h | 7 | ||||
-rw-r--r-- | source/blender/imbuf/intern/colormanagement.c | 91 |
3 files changed, 111 insertions, 0 deletions
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 620f8984d9f..e683d38a0aa 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -58,6 +58,10 @@ void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char * const char *IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf); const char *IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf); +bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace); +bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace); +bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace); + BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]); BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]); BLI_INLINE void IMB_colormangement_xyz_to_rgb(float rgb[3], const float xyz[3]); @@ -124,6 +128,14 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, struct ColorSpace *colorspace, bool predivide); +void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *rect, + const int x, + const int y, + const int width, + const int height, + const struct ImBuf *ibuf, + const bool compress_as_srgb); + void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]); void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]); @@ -340,6 +352,7 @@ enum { COLOR_ROLE_DEFAULT_SEQUENCER, COLOR_ROLE_DEFAULT_BYTE, COLOR_ROLE_DEFAULT_FLOAT, + COLOR_ROLE_DATA, }; #include "intern/colormanagement_inline.c" diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h index 2566016ffdd..a83f2d60b8c 100644 --- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h +++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h @@ -48,6 +48,13 @@ typedef struct ColorSpace { bool is_invertible; bool is_data; + + /* Additional info computed only when needed since it's not cheap. */ + struct { + bool cached; + bool is_srgb; + bool is_scene_linear; + } info; } ColorSpace; typedef struct ColorManagedDisplay { diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index f31d4ede693..b460d268d38 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -65,6 +65,7 @@ #define DISPLAY_BUFFER_CHANNELS 4 /* ** list of all supported color spaces, displays and views */ +static char global_role_data[MAX_COLORSPACE_NAME]; static char global_role_scene_linear[MAX_COLORSPACE_NAME]; static char global_role_color_picking[MAX_COLORSPACE_NAME]; static char global_role_texture_painting[MAX_COLORSPACE_NAME]; @@ -488,6 +489,7 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) const char *name; /* get roles */ + colormanage_role_color_space_name_get(config, global_role_data, OCIO_ROLE_DATA, NULL); colormanage_role_color_space_name_get( config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, NULL); colormanage_role_color_space_name_get( @@ -1260,6 +1262,8 @@ void IMB_colormanagement_validate_settings(const ColorManagedDisplaySettings *di const char *IMB_colormanagement_role_colorspace_name_get(int role) { switch (role) { + case COLOR_ROLE_DATA: + return global_role_data; case COLOR_ROLE_SCENE_LINEAR: return global_role_scene_linear; case COLOR_ROLE_COLOR_PICKING: @@ -1341,6 +1345,42 @@ const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf) } } +bool IMB_colormanagement_space_is_data(ColorSpace *colorspace) +{ + return (colorspace && colorspace->is_data); +} + +static void colormanage_ensure_srgb_scene_linear_info(ColorSpace *colorspace) +{ + if (!colorspace->info.cached) { + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config, + colorspace->name); + + bool is_scene_linear, is_srgb; + OCIO_colorSpaceIsBuiltin(config, ocio_colorspace, &is_scene_linear, &is_srgb); + + OCIO_colorSpaceRelease(ocio_colorspace); + OCIO_configRelease(config); + + colorspace->info.is_scene_linear = is_scene_linear; + colorspace->info.is_srgb = is_srgb; + colorspace->info.cached = true; + } +} + +bool IMB_colormanagement_space_is_scene_linear(ColorSpace *colorspace) +{ + colormanage_ensure_srgb_scene_linear_info(colorspace); + return (colorspace && colorspace->info.is_scene_linear); +} + +bool IMB_colormanagement_space_is_srgb(ColorSpace *colorspace) +{ + colormanage_ensure_srgb_scene_linear_info(colorspace); + return (colorspace && colorspace->info.is_srgb); +} + /*********************** Threaded display buffer transform routines *************************/ typedef struct DisplayBufferThread { @@ -2111,6 +2151,57 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, } } +void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *out_buffer, + const int offset_x, + const int offset_y, + const int width, + const int height, + const struct ImBuf *ibuf, + const bool compress_as_srgb) +{ + /* Convert byte buffer for texture storage on the GPU. These have builtin + * support for converting sRGB to linear, which allows us to store textures + * without precision or performance loss at minimal memory usage. */ + BLI_assert(ibuf->rect && ibuf->rect_float == NULL); + + OCIO_ConstProcessorRcPtr *processor = NULL; + if (compress_as_srgb && ibuf->rect_colorspace && + !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) { + processor = colorspace_to_scene_linear_processor(ibuf->rect_colorspace); + } + + /* TODO(brecht): make this multithreaded, or at least process in batches. */ + const unsigned char *in_buffer = (unsigned char *)ibuf->rect; + + for (int y = 0; y < height; y++) { + const size_t in_offset = (offset_y + y) * ibuf->x + offset_x; + const size_t out_offset = y * width; + const unsigned char *in = in_buffer + in_offset * 4; + unsigned char *out = out_buffer + out_offset * 4; + + if (processor) { + /* Convert to scene linear, to sRGB and premultiply. */ + for (int x = 0; x < width; x++, in += 4, out += 4) { + float pixel[4]; + rgba_uchar_to_float(pixel, in); + OCIO_processorApplyRGB(processor, pixel); + linearrgb_to_srgb_v3_v3(pixel, pixel); + mul_v3_fl(pixel, pixel[3]); + rgba_float_to_uchar(out, pixel); + } + } + else { + /* Premultiply only. */ + for (int x = 0; x < width; x++, in += 4, out += 4) { + out[0] = (in[0] * in[3]) >> 8; + out[1] = (in[1] * in[3]) >> 8; + out[2] = (in[2] * in[3]) >> 8; + out[3] = in[3]; + } + } + } +} + /* Conversion between color picking role. Typically we would expect such a * requirements: * - It is approximately perceptually linear, so that the HSV numbers and |