Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-02-11 17:18:55 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-02-11 17:19:04 +0300
commit804e90b42d728ecb1073af8d0bae15a91b13a469 (patch)
tree309de25d99c92286b10c9d27e547fd43a69299c1 /intern/opencolorio
parent58cdab8b9759dd59b55895f2f76b9624addbb324 (diff)
DRW: Color Management improvement
Reviewed By: brecht sergey jbakker Differential Revision: http://developer.blender.org/D6729
Diffstat (limited to 'intern/opencolorio')
-rw-r--r--intern/opencolorio/fallback_impl.cc43
-rw-r--r--intern/opencolorio/gpu_shader_display_transform.glsl183
-rw-r--r--intern/opencolorio/ocio_capi.cc51
-rw-r--r--intern/opencolorio/ocio_capi.h17
-rw-r--r--intern/opencolorio/ocio_impl.cc45
-rw-r--r--intern/opencolorio/ocio_impl.h46
-rw-r--r--intern/opencolorio/ocio_impl_glsl.cc819
7 files changed, 780 insertions, 424 deletions
diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc
index ec63dccf147..8dc95d22233 100644
--- a/intern/opencolorio/fallback_impl.cc
+++ b/intern/opencolorio/fallback_impl.cc
@@ -594,6 +594,43 @@ void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
MEM_freeN(id);
}
+OCIO_GroupTransformRcPtr *FallbackImpl::createGroupTransform(void)
+{
+ FallbackTransform *transform = new FallbackTransform();
+ transform->type = TRANSFORM_UNKNOWN;
+ return (OCIO_GroupTransformRcPtr *)transform;
+}
+
+void FallbackImpl::groupTransformSetDirection(OCIO_GroupTransformRcPtr * /*gt*/,
+ const bool /*forward */)
+{
+}
+
+void FallbackImpl::groupTransformPushBack(OCIO_GroupTransformRcPtr * /*gt*/,
+ OCIO_ConstTransformRcPtr * /*transform*/)
+{
+}
+
+void FallbackImpl::groupTransformRelease(OCIO_GroupTransformRcPtr * /*gt*/)
+{
+}
+
+OCIO_ColorSpaceTransformRcPtr *FallbackImpl::createColorSpaceTransform(void)
+{
+ FallbackTransform *transform = new FallbackTransform();
+ transform->type = TRANSFORM_UNKNOWN;
+ return (OCIO_ColorSpaceTransformRcPtr *)transform;
+}
+
+void FallbackImpl::colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr * /*ct*/,
+ const char * /*name*/)
+{
+}
+
+void FallbackImpl::colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr * /*ct*/)
+{
+}
+
OCIO_ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void)
{
FallbackTransform *transform = new FallbackTransform();
@@ -658,10 +695,12 @@ bool FallbackImpl::supportGLSLDraw(void)
}
bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/,
- OCIO_ConstProcessorRcPtr * /*processor*/,
+ OCIO_ConstProcessorRcPtr * /*ocio_processor_scene_to_ui*/,
+ OCIO_ConstProcessorRcPtr * /*ocio_processor_ui_to_display*/,
OCIO_CurveMappingSettings * /*curve_mapping_settings*/,
float /*dither*/,
- bool /*predivide*/)
+ bool /*predivide*/,
+ bool /*overlay*/)
{
return false;
}
diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl
index 9787398e2ae..f1f77cf7df2 100644
--- a/intern/opencolorio/gpu_shader_display_transform.glsl
+++ b/intern/opencolorio/gpu_shader_display_transform.glsl
@@ -1,70 +1,68 @@
+/* Blender OpenColorIO implementation */
+
+uniform sampler1D curve_mapping_texture;
uniform sampler2D image_texture;
+uniform sampler2D overlay_texture;
uniform sampler3D lut3d_texture;
+uniform sampler3D lut3d_display_texture;
-#ifdef USE_DITHER
uniform float dither;
-#endif
-
-in vec2 texCoord_interp;
-out vec4 fragColor;
+uniform bool predivide;
+uniform bool curve_mapping;
+uniform bool overlay;
-#ifdef USE_CURVE_MAPPING
-/* Curve mapping parameters
- *
- * See documentation for OCIO_CurveMappingSettings to get fields descriptions.
- * (this ones pretyt much copies stuff from C structure.)
- */
-uniform sampler1D curve_mapping_texture;
-uniform int curve_mapping_lut_size;
-uniform int use_curve_mapping_extend_extrapolate;
-uniform vec4 curve_mapping_mintable;
-uniform vec4 curve_mapping_range;
-uniform vec4 curve_mapping_ext_in_x;
-uniform vec4 curve_mapping_ext_in_y;
-uniform vec4 curve_mapping_ext_out_x;
-uniform vec4 curve_mapping_ext_out_y;
-uniform vec4 curve_mapping_first_x;
-uniform vec4 curve_mapping_first_y;
-uniform vec4 curve_mapping_last_x;
-uniform vec4 curve_mapping_last_y;
-uniform vec3 curve_mapping_black;
-uniform vec3 curve_mapping_bwmul;
+layout(std140) uniform OCIO_GLSLCurveMappingParameters
+{
+ /* Curve mapping parameters
+ *
+ * See documentation for OCIO_CurveMappingSettings to get fields descriptions.
+ * (this ones pretty much copies stuff from C structure.)
+ */
+ vec4 curve_mapping_mintable;
+ vec4 curve_mapping_range;
+ vec4 curve_mapping_ext_in_x;
+ vec4 curve_mapping_ext_in_y;
+ vec4 curve_mapping_ext_out_x;
+ vec4 curve_mapping_ext_out_y;
+ vec4 curve_mapping_first_x;
+ vec4 curve_mapping_first_y;
+ vec4 curve_mapping_last_x;
+ vec4 curve_mapping_last_y;
+ vec4 curve_mapping_black;
+ vec4 curve_mapping_bwmul;
+ int curve_mapping_lut_size;
+ int curve_mapping_use_extend_extrapolate;
+};
float read_curve_mapping(int table, int index)
{
- /* TODO(sergey): Without -1 here image is getting darken after applying unite curve.
- * But is it actually correct to subtract 1 here?
- */
- float texture_index = float(index) / float(curve_mapping_lut_size - 1);
- return texture(curve_mapping_texture, texture_index)[table];
+ return texelFetch(curve_mapping_texture, index, 0)[table];
}
float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
{
if (x <= first[0]) {
- if (use_curve_mapping_extend_extrapolate == 0) {
+ if (curve_mapping_use_extend_extrapolate == 0) {
/* horizontal extrapolation */
return first[1];
}
else {
- if (curve_mapping_ext_in_x[table] == 0.0)
- return first[1] + curve_mapping_ext_in_y[table] * 10000.0;
- else
- return first[1] +
- curve_mapping_ext_in_y[table] * (x - first[0]) / curve_mapping_ext_in_x[table];
+ float fac = (curve_mapping_ext_in_x[table] != 0.0) ?
+ ((x - first[0]) / curve_mapping_ext_in_x[table]) :
+ 10000.0;
+ return first[1] + curve_mapping_ext_in_y[table] * fac;
}
}
else if (x >= last[0]) {
- if (use_curve_mapping_extend_extrapolate == 0) {
+ if (curve_mapping_use_extend_extrapolate == 0) {
/* horizontal extrapolation */
return last[1];
}
else {
- if (curve_mapping_ext_out_x[table] == 0.0)
- return last[1] - curve_mapping_ext_out_y[table] * 10000.0;
- else
- return last[1] +
- curve_mapping_ext_out_y[table] * (x - last[0]) / curve_mapping_ext_out_x[table];
+ float fac = (curve_mapping_ext_out_x[table] != 0.0) ?
+ ((x - last[0]) / curve_mapping_ext_out_x[table]) :
+ -10000.0;
+ return last[1] + curve_mapping_ext_out_y[table] * fac;
}
}
return 0.0;
@@ -92,80 +90,91 @@ float curvemap_evaluateF(int table, float value)
vec2(curve_mapping_last_x[table], curve_mapping_last_y[table]));
}
else {
- if (i < 0)
+ if (i < 0) {
return read_curve_mapping(table, 0);
- if (i >= CM_TABLE)
+ }
+ if (i >= CM_TABLE) {
return read_curve_mapping(table, CM_TABLE);
-
+ }
fi = fi - float(i);
- return (1.0 - fi) * read_curve_mapping(table, i) + fi * read_curve_mapping(table, i + 1);
+ float cm1 = read_curve_mapping(table, i);
+ float cm2 = read_curve_mapping(table, i + 1);
+ return mix(cm1, cm2, fi);
}
}
vec4 curvemapping_evaluate_premulRGBF(vec4 col)
{
- vec4 result = col;
- result[0] = curvemap_evaluateF(0, (col[0] - curve_mapping_black[0]) * curve_mapping_bwmul[0]);
- result[1] = curvemap_evaluateF(1, (col[1] - curve_mapping_black[1]) * curve_mapping_bwmul[1]);
- result[2] = curvemap_evaluateF(2, (col[2] - curve_mapping_black[2]) * curve_mapping_bwmul[2]);
- result[3] = col[3];
+ col.rgb = (col.rgb - curve_mapping_black.rgb) * curve_mapping_bwmul.rgb;
+
+ vec4 result;
+ result.r = curvemap_evaluateF(0, col.r);
+ result.g = curvemap_evaluateF(1, col.g);
+ result.b = curvemap_evaluateF(2, col.b);
+ result.a = col.a;
return result;
}
-#endif
-#ifdef USE_DITHER
float dither_random_value(vec2 co)
{
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453) * 0.005 * dither;
}
-vec2 round_to_pixel(vec2 st)
+vec2 round_to_pixel(sampler2D tex, vec2 uv)
{
- vec2 result;
- vec2 size = textureSize(image_texture, 0);
- result.x = float(int(st.x * size.x)) / size.x;
- result.y = float(int(st.y * size.y)) / size.y;
- return result;
+ vec2 size = textureSize(tex, 0);
+ return vec2(ivec2(uv * size)) / size;
}
-vec4 apply_dither(vec2 st, vec4 col)
+vec4 apply_dither(vec4 col, vec2 uv)
{
- vec4 result;
- float random_value = dither_random_value(round_to_pixel(st));
- result.r = col.r + random_value;
- result.g = col.g + random_value;
- result.b = col.b + random_value;
- result.a = col.a;
- return result;
+ col.rgb += dither_random_value(uv);
+ return col;
}
-#endif
-void main()
+vec4 OCIO_ProcessColor(vec4 col, vec4 col_overlay, vec2 noise_uv)
{
- vec4 col = texture(image_texture, texCoord_interp.st);
-#ifdef USE_CURVE_MAPPING
- col = curvemapping_evaluate_premulRGBF(col);
-#endif
-
-#ifdef USE_PREDIVIDE
- if (col[3] > 0.0 && col[3] < 1.0) {
- float inv_alpha = 1.0 / col[3];
- col[0] *= inv_alpha;
- col[1] *= inv_alpha;
- col[2] *= inv_alpha;
+ if (curve_mapping) {
+ col = curvemapping_evaluate_premulRGBF(col);
+ }
+
+ if (predivide) {
+ if (col.a > 0.0 && col.a < 1.0) {
+ col.rgb *= 1.0 / col.a;
+ }
}
-#endif
/* NOTE: This is true we only do de-premul here and NO premul
* and the reason is simple -- opengl is always configured
* for straight alpha at this moment
*/
- vec4 result = OCIODisplay(col, lut3d_texture);
+ col = OCIO_to_display_linear_with_look(col, lut3d_texture);
+
+ if (dither > 0.0) {
+ col = apply_dither(col, noise_uv);
+ }
+
+ if (overlay) {
+ col *= 1.0 - col_overlay.a;
+ col += col_overlay; /* Assumed unassociated alpha. */
+ }
-#ifdef USE_DITHER
- result = apply_dither(texCoord_interp.st, result);
-#endif
+ col = OCIO_to_display_encoded(col, lut3d_display_texture);
- fragColor = result;
+ return col;
}
+
+/* ------------------------------------------------------------------------ */
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+void main()
+{
+ vec4 col = texture(image_texture, texCoord_interp.st);
+ vec4 col_overlay = texture(overlay_texture, texCoord_interp.st);
+ vec2 noise_uv = round_to_pixel(image_texture, texCoord_interp.st);
+
+ fragColor = OCIO_ProcessColor(col, col_overlay, noise_uv);
+} \ No newline at end of file
diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc
index d259ba73e45..84c36de364c 100644
--- a/intern/opencolorio/ocio_capi.cc
+++ b/intern/opencolorio/ocio_capi.cc
@@ -307,6 +307,41 @@ void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
impl->OCIO_PackedImageDescRelease(id);
}
+OCIO_GroupTransformRcPtr *OCIO_createGroupTransform(void)
+{
+ return impl->createGroupTransform();
+}
+
+void OCIO_groupTransformSetDirection(OCIO_GroupTransformRcPtr *gt, const bool forward)
+{
+ impl->groupTransformSetDirection(gt, forward);
+}
+
+void OCIO_groupTransformPushBack(OCIO_GroupTransformRcPtr *gt, OCIO_ConstTransformRcPtr *tr)
+{
+ impl->groupTransformPushBack(gt, tr);
+}
+
+void OCIO_groupTransformRelease(OCIO_GroupTransformRcPtr *gt)
+{
+ impl->groupTransformRelease(gt);
+}
+
+OCIO_ColorSpaceTransformRcPtr *OCIO_createColorSpaceTransform(void)
+{
+ return impl->createColorSpaceTransform();
+}
+
+void OCIO_colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr *ct, const char *name)
+{
+ impl->colorSpaceTransformSetSrc(ct, name);
+}
+
+void OCIO_colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr *ct)
+{
+ impl->colorSpaceTransformRelease(ct);
+}
+
OCIO_ExponentTransformRcPtr *OCIO_createExponentTransform(void)
{
return impl->createExponentTransform();
@@ -350,12 +385,20 @@ int OCIO_supportGLSLDraw(void)
}
int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r,
- OCIO_ConstProcessorRcPtr *processor,
+ OCIO_ConstProcessorRcPtr *ocio_processor_scene_to_ui,
+ OCIO_ConstProcessorRcPtr *ocio_processor_ui_to_display,
OCIO_CurveMappingSettings *curve_mapping_settings,
float dither,
- bool predivide)
-{
- return (int)impl->setupGLSLDraw(state_r, processor, curve_mapping_settings, dither, predivide);
+ bool predivide,
+ bool overlay)
+{
+ return (int)impl->setupGLSLDraw(state_r,
+ ocio_processor_scene_to_ui,
+ ocio_processor_ui_to_display,
+ curve_mapping_settings,
+ dither,
+ predivide,
+ overlay);
}
void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state)
diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h
index 5670b37f892..57799222788 100644
--- a/intern/opencolorio/ocio_capi.h
+++ b/intern/opencolorio/ocio_capi.h
@@ -46,8 +46,10 @@ OCIO_DECLARE_HANDLE(OCIO_ConstContextRcPtr);
OCIO_DECLARE_HANDLE(OCIO_PackedImageDesc);
OCIO_DECLARE_HANDLE(OCIO_DisplayTransformRcPtr);
OCIO_DECLARE_HANDLE(OCIO_ConstTransformRcPtr);
+OCIO_DECLARE_HANDLE(OCIO_ColorSpaceTransformRcPtr);
OCIO_DECLARE_HANDLE(OCIO_ExponentTransformRcPtr);
OCIO_DECLARE_HANDLE(OCIO_MatrixTransformRcPtr);
+OCIO_DECLARE_HANDLE(OCIO_GroupTransformRcPtr);
OCIO_DECLARE_HANDLE(OCIO_ConstLookRcPtr);
/* Standard XYZ to linear sRGB transform, for fallback. */
@@ -198,6 +200,15 @@ OCIO_PackedImageDesc *OCIO_createOCIO_PackedImageDesc(float *data,
void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p);
+OCIO_GroupTransformRcPtr *OCIO_createGroupTransform(void);
+void OCIO_groupTransformSetDirection(OCIO_GroupTransformRcPtr *gt, const bool forward);
+void OCIO_groupTransformPushBack(OCIO_GroupTransformRcPtr *gt, OCIO_ConstTransformRcPtr *tr);
+void OCIO_groupTransformRelease(OCIO_GroupTransformRcPtr *gt);
+
+OCIO_ColorSpaceTransformRcPtr *OCIO_createColorSpaceTransform(void);
+void OCIO_colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr *ct, const char *name);
+void OCIO_colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr *ct);
+
OCIO_ExponentTransformRcPtr *OCIO_createExponentTransform(void);
void OCIO_exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent);
void OCIO_exponentTransformRelease(OCIO_ExponentTransformRcPtr *et);
@@ -212,10 +223,12 @@ void OCIO_matrixTransformScale(float *m44, float *offset4, const float *scale4);
int OCIO_supportGLSLDraw(void);
int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r,
- OCIO_ConstProcessorRcPtr *processor,
+ OCIO_ConstProcessorRcPtr *ocio_processor_scene_to_ui,
+ OCIO_ConstProcessorRcPtr *ocio_processor_ui_to_display,
OCIO_CurveMappingSettings *curve_mapping_settings,
float dither,
- bool predivide);
+ bool predivide,
+ bool overlay);
void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state);
void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state);
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index b838f0e979f..fd749bb4050 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -822,6 +822,51 @@ void OCIOImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
OBJECT_GUARDED_DELETE((PackedImageDesc *)id, PackedImageDesc);
}
+OCIO_GroupTransformRcPtr *OCIOImpl::createGroupTransform(void)
+{
+ GroupTransformRcPtr *gt = OBJECT_GUARDED_NEW(GroupTransformRcPtr);
+
+ *gt = GroupTransform::Create();
+
+ return (OCIO_GroupTransformRcPtr *)gt;
+}
+
+void OCIOImpl::groupTransformSetDirection(OCIO_GroupTransformRcPtr *gt, const bool forward)
+{
+ TransformDirection dir = forward ? TRANSFORM_DIR_FORWARD : TRANSFORM_DIR_INVERSE;
+ (*(GroupTransformRcPtr *)gt)->setDirection(dir);
+}
+
+void OCIOImpl::groupTransformPushBack(OCIO_GroupTransformRcPtr *gt, OCIO_ConstTransformRcPtr *tr)
+{
+ (*(GroupTransformRcPtr *)gt)->push_back(*(ConstTransformRcPtr *)tr);
+}
+
+void OCIOImpl::groupTransformRelease(OCIO_GroupTransformRcPtr *gt)
+{
+ OBJECT_GUARDED_DELETE((GroupTransformRcPtr *)gt, GroupTransformRcPtr);
+}
+
+OCIO_ColorSpaceTransformRcPtr *OCIOImpl::createColorSpaceTransform(void)
+{
+ ColorSpaceTransformRcPtr *ct = OBJECT_GUARDED_NEW(ColorSpaceTransformRcPtr);
+
+ *ct = ColorSpaceTransform::Create();
+ (*ct)->setDirection(TRANSFORM_DIR_FORWARD);
+
+ return (OCIO_ColorSpaceTransformRcPtr *)ct;
+}
+
+void OCIOImpl::colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr *ct, const char *name)
+{
+ (*(ColorSpaceTransformRcPtr *)ct)->setSrc(name);
+}
+
+void OCIOImpl::colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr *ct)
+{
+ OBJECT_GUARDED_DELETE((ColorSpaceTransformRcPtr *)ct, ColorSpaceTransformRcPtr);
+}
+
OCIO_ExponentTransformRcPtr *OCIOImpl::createExponentTransform(void)
{
ExponentTransformRcPtr *et = OBJECT_GUARDED_NEW(ExponentTransformRcPtr);
diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h
index 082aa4a091e..3ffc0a4a475 100644
--- a/intern/opencolorio/ocio_impl.h
+++ b/intern/opencolorio/ocio_impl.h
@@ -117,6 +117,16 @@ class IOCIOImpl {
virtual void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p) = 0;
+ virtual OCIO_GroupTransformRcPtr *createGroupTransform(void) = 0;
+ virtual void groupTransformSetDirection(OCIO_GroupTransformRcPtr *gt, const bool forward) = 0;
+ virtual void groupTransformPushBack(OCIO_GroupTransformRcPtr *gt,
+ OCIO_ConstTransformRcPtr *transform) = 0;
+ virtual void groupTransformRelease(OCIO_GroupTransformRcPtr *gt) = 0;
+
+ virtual OCIO_ColorSpaceTransformRcPtr *createColorSpaceTransform(void) = 0;
+ virtual void colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr *ct, const char *name) = 0;
+ virtual void colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr *ct) = 0;
+
virtual OCIO_ExponentTransformRcPtr *createExponentTransform(void) = 0;
virtual void exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et,
const float *exponent) = 0;
@@ -132,10 +142,12 @@ class IOCIOImpl {
virtual bool supportGLSLDraw(void) = 0;
virtual bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r,
- OCIO_ConstProcessorRcPtr *processor,
+ OCIO_ConstProcessorRcPtr *ocio_processor_scene_to_ui,
+ OCIO_ConstProcessorRcPtr *ocio_processor_ui_to_display,
OCIO_CurveMappingSettings *curve_mapping_settings,
float dither,
- bool predivide) = 0;
+ bool predivide,
+ bool overlay) = 0;
virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0;
virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0;
@@ -229,6 +241,15 @@ class FallbackImpl : public IOCIOImpl {
void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p);
+ OCIO_GroupTransformRcPtr *createGroupTransform(void);
+ void groupTransformSetDirection(OCIO_GroupTransformRcPtr *gt, const bool forward);
+ void groupTransformPushBack(OCIO_GroupTransformRcPtr *gt, OCIO_ConstTransformRcPtr *transform);
+ void groupTransformRelease(OCIO_GroupTransformRcPtr *gt);
+
+ OCIO_ColorSpaceTransformRcPtr *createColorSpaceTransform(void);
+ void colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr *ct, const char *name);
+ void colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr *ct);
+
OCIO_ExponentTransformRcPtr *createExponentTransform(void);
void exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent);
void exponentTransformRelease(OCIO_ExponentTransformRcPtr *et);
@@ -243,10 +264,12 @@ class FallbackImpl : public IOCIOImpl {
bool supportGLSLDraw(void);
bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r,
- OCIO_ConstProcessorRcPtr *processor,
+ OCIO_ConstProcessorRcPtr *ocio_processor_scene_to_ui,
+ OCIO_ConstProcessorRcPtr *ocio_processor_ui_to_display,
OCIO_CurveMappingSettings *curve_mapping_settings,
float dither,
- bool predivide);
+ bool predivide,
+ bool overlay);
void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
void freeGLState(struct OCIO_GLSLDrawState *state_r);
@@ -339,6 +362,15 @@ class OCIOImpl : public IOCIOImpl {
void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *p);
+ OCIO_GroupTransformRcPtr *createGroupTransform(void);
+ void groupTransformSetDirection(OCIO_GroupTransformRcPtr *gt, const bool forward);
+ void groupTransformPushBack(OCIO_GroupTransformRcPtr *gt, OCIO_ConstTransformRcPtr *transform);
+ void groupTransformRelease(OCIO_GroupTransformRcPtr *gt);
+
+ OCIO_ColorSpaceTransformRcPtr *createColorSpaceTransform(void);
+ void colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr *ct, const char *name);
+ void colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr *ct);
+
OCIO_ExponentTransformRcPtr *createExponentTransform(void);
void exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent);
void exponentTransformRelease(OCIO_ExponentTransformRcPtr *et);
@@ -353,10 +385,12 @@ class OCIOImpl : public IOCIOImpl {
bool supportGLSLDraw(void);
bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r,
- OCIO_ConstProcessorRcPtr *processor,
+ OCIO_ConstProcessorRcPtr *ocio_processor_scene_to_ui,
+ OCIO_ConstProcessorRcPtr *ocio_processor_ui_to_display,
OCIO_CurveMappingSettings *curve_mapping_settings,
float dither,
- bool predivide);
+ bool predivide,
+ bool overlay);
void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
void freeGLState(struct OCIO_GLSLDrawState *state_r);
diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc
index a80e29a2dec..df6adc8f34b 100644
--- a/intern/opencolorio/ocio_impl_glsl.cc
+++ b/intern/opencolorio/ocio_impl_glsl.cc
@@ -56,62 +56,108 @@ using namespace OCIO_NAMESPACE;
#include "ocio_impl.h"
static const int LUT3D_EDGE_SIZE = 64;
+static const int LUT3D_TEXTURE_SIZE = sizeof(float) * 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE *
+ LUT3D_EDGE_SIZE;
static const int SHADER_CACHE_SIZE = 4;
+#define UBO_BIND_LOC 0
+
extern "C" char datatoc_gpu_shader_display_transform_glsl[];
extern "C" char datatoc_gpu_shader_display_transform_vertex_glsl[];
/* **** OpenGL drawing routines using GLSL for color space transform ***** */
-typedef struct OCIO_GLSLShader {
- /* Cache ID */
- std::string lut3dCacheID;
- std::string shaderCacheID;
-
- /* LUT */
- bool lut3d_texture_allocated; /* boolean flag indicating whether
- * lut texture is allocated
- */
- bool lut3d_texture_valid;
-
- GLuint lut3d_texture; /* OGL texture ID for 3D LUT */
-
- float *lut3d; /* 3D LUT table */
-
- /* Dither */
- bool use_dither;
-
- /* Curve Mapping */
- bool use_curve_mapping;
- bool curve_mapping_texture_allocated;
- bool curve_mapping_texture_valid;
- GLuint curve_mapping_texture;
- size_t curve_mapping_cache_id;
-
- /* Alpha Predivide */
- bool use_predivide;
-
- /* GLSL stuff */
- GLuint ocio_shader;
- GLuint vert_shader;
+/* Curve mapping parameters
+ *
+ * See documentation for OCIO_CurveMappingSettings to get fields descriptions.
+ * (this ones pretty much copies stuff from C structure.)
+ */
+struct OCIO_GLSLCurveMappingParameters {
+ float curve_mapping_mintable[4];
+ float curve_mapping_range[4];
+ float curve_mapping_ext_in_x[4];
+ float curve_mapping_ext_in_y[4];
+ float curve_mapping_ext_out_x[4];
+ float curve_mapping_ext_out_y[4];
+ float curve_mapping_first_x[4];
+ float curve_mapping_first_y[4];
+ float curve_mapping_last_x[4];
+ float curve_mapping_last_y[4];
+ float curve_mapping_black[4];
+ float curve_mapping_bwmul[4];
+ int curve_mapping_lut_size;
+ int curve_mapping_use_extend_extrapolate;
+ int _pad[2];
+ /** WARNING: Needs to be 16byte aligned. Used as UBO data. */
+};
+
+struct OCIO_GLSLShader {
+ /** Cache IDs */
+ std::string cacheId;
+ /** TODO(fclem): Remove. IMM shader interface. */
+ struct GPUShaderInterface *interface;
+ /** OpenGL Shader objects handles. */
+ GLuint frag;
+ GLuint vert;
GLuint program;
- GPUShaderInterface *shader_interface;
-} GLSLDrawState;
-
-typedef struct OCIO_GLSLDrawState {
+ /** Uniform locations. */
+ GLint dither_loc;
+ GLint overlay_loc;
+ GLint overlay_tex_loc;
+ GLint predivide_loc;
+ GLint curve_mapping_loc;
+ /** Error checking. */
+ bool valid;
+};
+
+struct OCIO_GLSLLut3d {
+ /** Cache IDs */
+ std::string cacheId;
+ /** OpenGL Texture handles. 0 if not allocated. */
+ GLuint texture;
+ GLuint texture_display;
+ /** Error checking. */
+ bool valid;
+};
+
+struct OCIO_GLSLCurveMappping {
+ /** Cache IDs */
+ size_t cacheId;
+ /** OpenGL Uniform Buffer handle. 0 if not allocated. */
+ GLuint buffer;
+ /** OpenGL Texture handles. 0 if not allocated. */
+ GLuint texture;
+ /** Error checking. */
+ bool valid;
+};
+
+struct OCIO_GLSLCacheHandle {
+ size_t cache_id;
+ void *data;
+};
+
+struct OCIO_GLSLDrawState {
/* Shader Cache */
- OCIO_GLSLShader *shader_cache[SHADER_CACHE_SIZE];
+ OCIO_GLSLCacheHandle shader_cache[SHADER_CACHE_SIZE];
+ OCIO_GLSLCacheHandle lut3d_cache[SHADER_CACHE_SIZE];
+ OCIO_GLSLCacheHandle curvemap_cache[SHADER_CACHE_SIZE];
+};
+
+static OCIO_GLSLDrawState *allocateOpenGLState(void)
+{
+ return (OCIO_GLSLDrawState *)MEM_callocN(sizeof(OCIO_GLSLDrawState), "OCIO OpenGL State struct");
+}
- /* Previous OpenGL state. */
- GLint last_texture, last_texture_unit;
-} OCIO_GLSLDrawState;
+/* -------------------------------------------------------------------- */
+/** \name Shader
+ * \{ */
-static GLuint compileShaderText(GLenum shaderType, const char *text)
+static GLuint compileShaderText(GLenum shader_type, const char *text)
{
GLuint shader;
GLint stat;
- shader = glCreateShader(shaderType);
+ shader = glCreateShader(shader_type);
glShaderSource(shader, 1, (const GLchar **)&text, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
@@ -127,15 +173,16 @@ static GLuint compileShaderText(GLenum shaderType, const char *text)
return shader;
}
-static GLuint linkShaders(GLuint ocio_shader, GLuint vert_shader)
+static GLuint linkShaders(GLuint frag, GLuint vert)
{
- if (!ocio_shader || !vert_shader)
+ if (!frag || !vert) {
return 0;
+ }
GLuint program = glCreateProgram();
- glAttachShader(program, ocio_shader);
- glAttachShader(program, vert_shader);
+ glAttachShader(program, frag);
+ glAttachShader(program, vert);
glLinkProgram(program);
@@ -155,133 +202,379 @@ static GLuint linkShaders(GLuint ocio_shader, GLuint vert_shader)
return program;
}
-static OCIO_GLSLDrawState *allocateOpenGLState(void)
+static void updateGLSLShader(OCIO_GLSLShader *shader,
+ ConstProcessorRcPtr *processor_scene_to_ui,
+ ConstProcessorRcPtr *processpr_ui_to_display,
+ GpuShaderDesc *shader_desc,
+ const std::string &cache_id)
{
- return (OCIO_GLSLDrawState *)MEM_callocN(sizeof(OCIO_GLSLDrawState), "OCIO OpenGL State struct");
+ if (shader->cacheId == cache_id) {
+ return;
+ }
+
+ /* Delete any previous shader. */
+ glDeleteProgram(shader->program);
+ glDeleteShader(shader->frag);
+ glDeleteShader(shader->vert);
+
+ if (shader->interface) {
+ GPU_shaderinterface_discard(shader->interface);
+ }
+
+ {
+ /* Vertex shader */
+ std::ostringstream osv;
+
+ osv << "#version 330\n";
+ osv << datatoc_gpu_shader_display_transform_vertex_glsl;
+
+ shader->vert = compileShaderText(GL_VERTEX_SHADER, osv.str().c_str());
+ }
+ {
+ /* Fragment shader */
+ std::ostringstream os;
+
+ os << "#version 330\n";
+ /* Work around OpenColorIO not supporting latest GLSL yet. */
+ os << "#define texture2D texture\n";
+ os << "#define texture3D texture\n";
+
+ shader_desc->setFunctionName("OCIO_to_display_linear_with_look");
+ os << (*processor_scene_to_ui)->getGpuShaderText(*shader_desc) << "\n";
+
+ shader_desc->setFunctionName("OCIO_to_display_encoded");
+ os << (*processpr_ui_to_display)->getGpuShaderText(*shader_desc) << "\n";
+
+ os << datatoc_gpu_shader_display_transform_glsl;
+
+ shader->frag = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
+ }
+
+ /* shader_Program */
+ if (shader->frag && shader->vert) {
+ shader->program = linkShaders(shader->frag, shader->vert);
+ }
+
+ if (shader->program) {
+ shader->dither_loc = glGetUniformLocation(shader->program, "dither");
+ shader->overlay_tex_loc = glGetUniformLocation(shader->program, "overlay_texture");
+ shader->overlay_loc = glGetUniformLocation(shader->program, "overlay");
+ shader->predivide_loc = glGetUniformLocation(shader->program, "predivide");
+ shader->curve_mapping_loc = glGetUniformLocation(shader->program, "curve_mapping");
+
+ glUseProgram(shader->program);
+ /* Set texture bind point uniform once. This is saved by the shader. */
+ glUniform1i(glGetUniformLocation(shader->program, "image_texture"), 0);
+ glUniform1i(glGetUniformLocation(shader->program, "lut3d_texture"), 2);
+ glUniform1i(glGetUniformLocation(shader->program, "lut3d_display_texture"), 3);
+ glUniform1i(glGetUniformLocation(shader->program, "curve_mapping_texture"), 4);
+
+ /* Set UBO binding location. */
+ GLuint index = glGetUniformBlockIndex(shader->program, "OCIO_GLSLCurveMappingParameters");
+ glUniformBlockBinding(shader->program, index, UBO_BIND_LOC);
+
+ /* TODO(fclem) Remove this. Make caller always assume viewport space and
+ * specify texco via vertex attribs. */
+ shader->interface = GPU_shaderinterface_create(shader->program);
+ }
+
+ shader->cacheId = cache_id;
+ shader->valid = (shader->program != 0);
}
-/* Ensure LUT texture and array are allocated */
-static bool ensureLUT3DAllocated(OCIO_GLSLShader *shader)
+static void ensureGLSLShader(OCIO_GLSLShader **shader_ptr,
+ ConstProcessorRcPtr *processor_scene_to_ui,
+ ConstProcessorRcPtr *processpr_ui_to_display,
+ GpuShaderDesc *shader_desc,
+ const std::string &cache_id)
{
- int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE;
+ if (*shader_ptr != NULL) {
+ return;
+ }
- if (shader->lut3d_texture_allocated)
- return shader->lut3d_texture_valid;
+ OCIO_GLSLShader *shader = OBJECT_GUARDED_NEW(OCIO_GLSLShader);
- glGenTextures(1, &shader->lut3d_texture);
+ updateGLSLShader(shader, processor_scene_to_ui, processpr_ui_to_display, shader_desc, cache_id);
- shader->lut3d = (float *)MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT");
+ *shader_ptr = shader;
+}
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_3D, shader->lut3d_texture);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+static void freeGLSLShader(OCIO_GLSLShader *shader)
+{
+ glDeleteProgram(shader->program);
+ glDeleteShader(shader->frag);
+ glDeleteShader(shader->vert);
- /* clean glError buffer */
- while (glGetError() != GL_NO_ERROR) {
+ if (shader->interface) {
+ GPU_shaderinterface_discard(shader->interface);
}
- glTexImage3D(GL_TEXTURE_3D,
- 0,
- GL_RGB16F_ARB,
- LUT3D_EDGE_SIZE,
- LUT3D_EDGE_SIZE,
- LUT3D_EDGE_SIZE,
- 0,
- GL_RGB,
- GL_FLOAT,
- shader->lut3d);
-
- shader->lut3d_texture_allocated = true;
-
- /* GL_RGB16F_ARB could be not supported at some drivers
- * in this case we could not use GLSL display
- */
- shader->lut3d_texture_valid = glGetError() == GL_NO_ERROR;
-
- return shader->lut3d_texture_valid;
+ OBJECT_GUARDED_DELETE(shader, OCIO_GLSLShader);
}
-static bool ensureCurveMappingAllocated(OCIO_GLSLShader *shader,
- OCIO_CurveMappingSettings *curve_mapping_settings)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lut3D
+ * \{ */
+
+static void updateGLSLLut3d(OCIO_GLSLLut3d *lut3d,
+ ConstProcessorRcPtr *processor_scene_to_ui,
+ ConstProcessorRcPtr *processpr_ui_to_display,
+ GpuShaderDesc *shader_desc,
+ const std::string &cache_id)
{
- if (shader->curve_mapping_texture_allocated)
- return shader->curve_mapping_texture_valid;
+ if (lut3d->cacheId == cache_id)
+ return;
+
+ float *lut_data = (float *)MEM_mallocN(LUT3D_TEXTURE_SIZE, __func__);
+
+ ConstProcessorRcPtr *ocio_processors[2] = {processor_scene_to_ui, processpr_ui_to_display};
- glGenTextures(1, &shader->curve_mapping_texture);
+ for (int i = 0; i < 2; i++) {
+ ConstProcessorRcPtr *processor = ocio_processors[i];
+ GLuint texture = (&lut3d->texture)[i];
+
+ (*processor)->getGpuLut3D(lut_data, *shader_desc);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_3D, texture);
+
+ glTexSubImage3D(GL_TEXTURE_3D,
+ 0,
+ 0,
+ 0,
+ 0,
+ LUT3D_EDGE_SIZE,
+ LUT3D_EDGE_SIZE,
+ LUT3D_EDGE_SIZE,
+ GL_RGB,
+ GL_FLOAT,
+ lut_data);
+ }
+
+ MEM_freeN(lut_data);
+
+ lut3d->cacheId = cache_id;
+}
+
+static void ensureGLSLLut3d(OCIO_GLSLLut3d **lut3d_ptr,
+ ConstProcessorRcPtr *processor_scene_to_ui,
+ ConstProcessorRcPtr *processpr_ui_to_display,
+ GpuShaderDesc *shaderDesc,
+ const std::string &cache_id)
+{
+ if (*lut3d_ptr != NULL) {
+ return;
+ }
+
+ OCIO_GLSLLut3d *lut3d = OBJECT_GUARDED_NEW(OCIO_GLSLLut3d);
+
+ glGenTextures(3, &lut3d->texture);
+
+ for (int i = 0; i < 2; i++) {
+ GLuint texture = (&lut3d->texture)[i];
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_3D, texture);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+
+ glTexImage3D(GL_TEXTURE_3D,
+ 0,
+ GL_RGB16F,
+ LUT3D_EDGE_SIZE,
+ LUT3D_EDGE_SIZE,
+ LUT3D_EDGE_SIZE,
+ 0,
+ GL_RGB,
+ GL_FLOAT,
+ NULL);
+ }
+
+ updateGLSLLut3d(lut3d, processor_scene_to_ui, processpr_ui_to_display, shaderDesc, cache_id);
+
+ lut3d->valid = (lut3d->texture != 0);
+
+ *lut3d_ptr = lut3d;
+}
+
+static void freeGLSLLut3d(OCIO_GLSLLut3d *lut3d)
+{
+ glDeleteTextures(1, &lut3d->texture);
+
+ OBJECT_GUARDED_DELETE(lut3d, OCIO_GLSLLut3d);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Mapping
+ * \{ */
+static void allocateCurveMappingTexture(OCIO_GLSLCurveMappping *curvemap,
+ OCIO_CurveMappingSettings *curve_mapping_settings)
+{
+ glGenTextures(1, &curvemap->texture);
glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_1D, shader->curve_mapping_texture);
+ glBindTexture(GL_TEXTURE_1D, curvemap->texture);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- /* clean glError buffer */
- while (glGetError() != GL_NO_ERROR) {
+ /* Do not initialize. Only if used. */
+ int lut_size = curve_mapping_settings ? curve_mapping_settings->lut_size : 1;
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA16F, lut_size, 0, GL_RGBA, GL_FLOAT, NULL);
+}
+
+/* curve_mapping_settings can be null. In this case we alloc a dummy curvemap. */
+static void ensureGLSLCurveMapping(OCIO_GLSLCurveMappping **curvemap_ptr,
+ OCIO_CurveMappingSettings *curve_mapping_settings)
+{
+ if (*curvemap_ptr != NULL) {
+ return;
}
- glTexImage1D(GL_TEXTURE_1D,
- 0,
- GL_RGBA16F,
- curve_mapping_settings->lut_size,
- 0,
- GL_RGBA,
- GL_FLOAT,
- curve_mapping_settings->lut);
+ OCIO_GLSLCurveMappping *curvemap = OBJECT_GUARDED_NEW(OCIO_GLSLCurveMappping);
+
+ /* Texture. */
+ allocateCurveMappingTexture(curvemap, curve_mapping_settings);
- shader->curve_mapping_texture_allocated = true;
+ /* Uniform buffer object. */
+ glGenBuffers(1, &curvemap->buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, curvemap->buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(OCIO_GLSLCurveMappingParameters), 0, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
- /* GL_RGB16F_ARB could be not supported at some drivers
- * in this case we could not use GLSL display
- */
- shader->curve_mapping_texture_valid = glGetError() == GL_NO_ERROR;
+ curvemap->valid = (curvemap->texture != 0);
+ curvemap->cacheId = 0;
- return shader->curve_mapping_texture_valid;
+ *curvemap_ptr = curvemap;
}
-static void freeGLSLShader(OCIO_GLSLShader *shader)
+static void freeGLSLCurveMapping(OCIO_GLSLCurveMappping *curvemap)
{
- if (shader->curve_mapping_texture_allocated) {
- glDeleteTextures(1, &shader->curve_mapping_texture);
- }
+ glDeleteTextures(1, &curvemap->texture);
+ glDeleteBuffers(1, &curvemap->buffer);
- if (shader->lut3d_texture_allocated) {
- glDeleteTextures(1, &shader->lut3d_texture);
- }
+ OBJECT_GUARDED_DELETE(curvemap, OCIO_GLSLCurveMappping);
+}
+
+static void updateGLSLCurveMapping(OCIO_GLSLCurveMappping *curvemap,
+ OCIO_CurveMappingSettings *curve_mapping_settings,
+ size_t cacheId)
+{
+ /* No need to continue if curvemapping is not used. Just use whatever is in this cache. */
+ if (curve_mapping_settings == NULL)
+ return;
+
+ if (curvemap->cacheId == cacheId)
+ return;
- if (shader->lut3d) {
- MEM_freeN(shader->lut3d);
+ if (curvemap->cacheId == 0) {
+ /* This cache was previously used as dummy. Recreate the texture. */
+ glDeleteTextures(1, &curvemap->texture);
+ allocateCurveMappingTexture(curvemap, curve_mapping_settings);
}
- if (shader->program) {
- glDeleteProgram(shader->program);
+ /* Update texture. */
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_1D, curvemap->texture);
+ glTexSubImage1D(GL_TEXTURE_1D,
+ 0,
+ 0,
+ curve_mapping_settings->lut_size,
+ GL_RGBA,
+ GL_FLOAT,
+ curve_mapping_settings->lut);
+
+ /* Update uniforms. */
+ OCIO_GLSLCurveMappingParameters data;
+ for (int i = 0; i < 4; i++) {
+ data.curve_mapping_range[i] = curve_mapping_settings->range[i];
+ data.curve_mapping_mintable[i] = curve_mapping_settings->mintable[i];
+ data.curve_mapping_ext_in_x[i] = curve_mapping_settings->ext_in_x[i];
+ data.curve_mapping_ext_in_y[i] = curve_mapping_settings->ext_in_y[i];
+ data.curve_mapping_ext_out_x[i] = curve_mapping_settings->ext_out_x[i];
+ data.curve_mapping_ext_out_y[i] = curve_mapping_settings->ext_out_y[i];
+ data.curve_mapping_first_x[i] = curve_mapping_settings->first_x[i];
+ data.curve_mapping_first_y[i] = curve_mapping_settings->first_y[i];
+ data.curve_mapping_last_x[i] = curve_mapping_settings->last_x[i];
+ data.curve_mapping_last_y[i] = curve_mapping_settings->last_y[i];
+ }
+ for (int i = 0; i < 3; i++) {
+ data.curve_mapping_black[i] = curve_mapping_settings->black[i];
+ data.curve_mapping_bwmul[i] = curve_mapping_settings->bwmul[i];
}
+ data.curve_mapping_lut_size = curve_mapping_settings->lut_size;
+ data.curve_mapping_use_extend_extrapolate = curve_mapping_settings->use_extend_extrapolate;
+
+ glBindBuffer(GL_UNIFORM_BUFFER, curvemap->buffer);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OCIO_GLSLCurveMappingParameters), &data);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ curvemap->cacheId = cacheId;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name LRU cache
+ * \{ */
- if (shader->shader_interface) {
- GPU_shaderinterface_discard(shader->shader_interface);
+static size_t hash_string(const char *str)
+{
+ size_t i = 0, c;
+ while ((c = *str++)) {
+ i = i * 37 + c;
}
+ return i;
+}
- if (shader->ocio_shader) {
- glDeleteShader(shader->ocio_shader);
+static OCIO_GLSLCacheHandle *cacheSearch(OCIO_GLSLCacheHandle cache[SHADER_CACHE_SIZE],
+ size_t cache_id)
+{
+ OCIO_GLSLCacheHandle *cached_item = &cache[0];
+ for (int i = 0; i < SHADER_CACHE_SIZE; i++, cached_item++) {
+ if (cached_item->data == NULL) {
+ continue;
+ }
+ else if (cached_item->cache_id == cache_id) {
+ /* LRU cache, so move to front. */
+ OCIO_GLSLCacheHandle found_item = *cached_item;
+ for (int j = i; j > 0; j--) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = found_item;
+ return &cache[0];
+ }
+ }
+ /* LRU cache, shift other items back so we can insert at the front. */
+ OCIO_GLSLCacheHandle last_item = cache[SHADER_CACHE_SIZE - 1];
+ for (int j = SHADER_CACHE_SIZE - 1; j > 0; j--) {
+ cache[j] = cache[j - 1];
}
+ /* Copy last to front and let the caller initialize it. */
+ cache[0] = last_item;
+ return &cache[0];
+}
- using std::string;
- shader->lut3dCacheID.~string();
- shader->shaderCacheID.~string();
+/** \} */
- MEM_freeN(shader);
-}
+/* -------------------------------------------------------------------- */
+/** \name OCIO GLSL Implementation
+ * \{ */
/* Detect if we can support GLSL drawing */
bool OCIOImpl::supportGLSLDraw()
{
- /* uses GL_RGB16F_ARB */
- return GLEW_VERSION_3_0 || GLEW_ARB_texture_float;
+ /* Minimum supported version 3.3 does meet all requirements. */
+ return true;
}
/**
@@ -295,14 +588,21 @@ bool OCIOImpl::supportGLSLDraw()
* restore OpenGL context to it's pre-GLSL draw state.
*/
bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r,
- OCIO_ConstProcessorRcPtr *processor,
+ OCIO_ConstProcessorRcPtr *ocio_processor_scene_to_ui,
+ OCIO_ConstProcessorRcPtr *ocio_processor_ui_to_display,
OCIO_CurveMappingSettings *curve_mapping_settings,
float dither,
- bool use_predivide)
+ bool use_predivide,
+ bool use_overlay)
{
- ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *)processor;
+ ConstProcessorRcPtr processor_scene_to_ui = *(ConstProcessorRcPtr *)ocio_processor_scene_to_ui;
+ ConstProcessorRcPtr processpr_ui_to_display = *(
+ ConstProcessorRcPtr *)ocio_processor_ui_to_display;
bool use_curve_mapping = curve_mapping_settings != NULL;
- bool use_dither = dither > std::numeric_limits<float>::epsilon();
+
+ if (!processor_scene_to_ui || !processor_scene_to_ui) {
+ return false;
+ }
/* Create state if needed. */
OCIO_GLSLDrawState *state;
@@ -310,235 +610,108 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r,
*state_r = allocateOpenGLState();
state = *state_r;
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &state->last_texture);
- glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit);
-
/* Compute cache IDs. */
GpuShaderDesc shaderDesc;
shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_3);
shaderDesc.setFunctionName("OCIODisplay");
shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
- std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc);
- std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
+ const char *shader_cache_str = processor_scene_to_ui->getGpuShaderTextCacheID(shaderDesc);
+ const char *lut3d_cache_str = processor_scene_to_ui->getGpuLut3DCacheID(shaderDesc);
+ /* Used for comparison. */
+ std::string shaderCacheID = shader_cache_str;
+ std::string lut3dCacheID = lut3d_cache_str;
- /* Find matching cached shader. */
- OCIO_GLSLShader *shader = NULL;
- for (int i = 0; i < SHADER_CACHE_SIZE; i++) {
- OCIO_GLSLShader *cached_shader = state->shader_cache[i];
- if (cached_shader == NULL) {
- continue;
- }
+ size_t shader_cache_id = hash_string(shader_cache_str);
+ size_t lut3d_cache_id = hash_string(lut3d_cache_str);
+ size_t curvemap_cache_id = curve_mapping_settings ? curve_mapping_settings->cache_id : 0;
- if (cached_shader->lut3dCacheID == lut3dCacheID &&
- cached_shader->shaderCacheID == shaderCacheID &&
- cached_shader->use_predivide == use_predivide &&
- cached_shader->use_curve_mapping == use_curve_mapping &&
- cached_shader->use_dither == use_dither) {
- /* LRU cache, so move to front. */
- for (int j = i; j > 0; j--) {
- state->shader_cache[j] = state->shader_cache[j - 1];
- }
- state->shader_cache[0] = cached_shader;
+ OCIO_GLSLCacheHandle *shader_handle = cacheSearch(state->shader_cache, shader_cache_id);
+ OCIO_GLSLCacheHandle *lut3d_handle = cacheSearch(state->lut3d_cache, lut3d_cache_id);
+ /* We cannot keep more than one cache for curvemap because their cache id is a pointer.
+ * The pointer cannot be the same for one update but can be the same after a second update. */
+ OCIO_GLSLCacheHandle *curvemap_handle = &state->curvemap_cache[0];
- shader = cached_shader;
- break;
- }
- }
-
- if (shader == NULL) {
- /* LRU cache, shift other items back so we can insert at the front. */
- OCIO_GLSLShader *last_shader = state->shader_cache[SHADER_CACHE_SIZE - 1];
- if (last_shader) {
- freeGLSLShader(last_shader);
- }
- for (int j = SHADER_CACHE_SIZE - 1; j > 0; j--) {
- state->shader_cache[j] = state->shader_cache[j - 1];
- }
-
- /* Allocate memory for shader. */
- shader = (OCIO_GLSLShader *)MEM_callocN(sizeof(OCIO_GLSLShader), "OCIO GLSL Shader");
- state->shader_cache[0] = shader;
-
- new (&shader->lut3dCacheID) std::string();
- new (&shader->shaderCacheID) std::string();
-
- shader->lut3dCacheID = lut3dCacheID;
- shader->shaderCacheID = shaderCacheID;
- shader->use_curve_mapping = use_curve_mapping;
- shader->use_dither = use_dither;
- shader->use_predivide = use_predivide;
-
- bool valid = true;
-
- /* Compute 3D LUT. */
- if (valid && ensureLUT3DAllocated(shader)) {
- ocio_processor->getGpuLut3D(shader->lut3d, shaderDesc);
-
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_3D, shader->lut3d_texture);
- glTexSubImage3D(GL_TEXTURE_3D,
- 0,
- 0,
- 0,
- 0,
- LUT3D_EDGE_SIZE,
- LUT3D_EDGE_SIZE,
- LUT3D_EDGE_SIZE,
- GL_RGB,
- GL_FLOAT,
- shader->lut3d);
- }
- else {
- valid = false;
- }
-
- /* Allocate curve mapping texture. */
- if (valid && use_curve_mapping) {
- if (!ensureCurveMappingAllocated(shader, curve_mapping_settings)) {
- valid = false;
- }
- }
-
- if (valid) {
- /* Vertex shader */
- std::ostringstream osv;
-
- osv << "#version 330\n";
- osv << datatoc_gpu_shader_display_transform_vertex_glsl;
-
- shader->vert_shader = compileShaderText(GL_VERTEX_SHADER, osv.str().c_str());
-
- /* Fragment shader */
- std::ostringstream os;
+ OCIO_GLSLShader **shader_ptr = (OCIO_GLSLShader **)&shader_handle->data;
+ OCIO_GLSLLut3d **lut3d_ptr = (OCIO_GLSLLut3d **)&lut3d_handle->data;
+ OCIO_GLSLCurveMappping **curvemap_ptr = (OCIO_GLSLCurveMappping **)&curvemap_handle->data;
- os << "#version 330\n";
+ ensureGLSLShader(
+ shader_ptr, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, shaderCacheID);
+ ensureGLSLLut3d(
+ lut3d_ptr, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, shaderCacheID);
+ ensureGLSLCurveMapping(curvemap_ptr, curve_mapping_settings);
- /* Work around OpenColorIO not supporting latest GLSL yet. */
- os << "#define texture2D texture\n";
- os << "#define texture3D texture\n";
+ OCIO_GLSLShader *shader = (OCIO_GLSLShader *)shader_handle->data;
+ OCIO_GLSLLut3d *shader_lut = (OCIO_GLSLLut3d *)lut3d_handle->data;
+ OCIO_GLSLCurveMappping *shader_curvemap = (OCIO_GLSLCurveMappping *)curvemap_handle->data;
- if (use_predivide) {
- os << "#define USE_PREDIVIDE\n";
- }
+ updateGLSLShader(
+ shader, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, shaderCacheID);
+ updateGLSLLut3d(
+ shader_lut, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, lut3dCacheID);
+ updateGLSLCurveMapping(shader_curvemap, curve_mapping_settings, curvemap_cache_id);
- if (use_dither) {
- os << "#define USE_DITHER\n";
- }
+ /* Update handles cache keys. */
+ shader_handle->cache_id = shader_cache_id;
+ lut3d_handle->cache_id = lut3d_cache_id;
+ curvemap_handle->cache_id = curvemap_cache_id;
- if (use_curve_mapping) {
- os << "#define USE_CURVE_MAPPING\n";
- }
+ if (shader->valid && shader_lut->valid && shader_curvemap->valid) {
+ /* Bind textures to sampler units. Texture 0 is set by caller.
+ * Uniforms have already been set for texture bind points.*/
- os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
- os << datatoc_gpu_shader_display_transform_glsl;
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_3D, shader_lut->texture);
- shader->ocio_shader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
+ glActiveTexture(GL_TEXTURE3);
+ glBindTexture(GL_TEXTURE_3D, shader_lut->texture_display);
- /* Program */
- if (shader->ocio_shader && shader->vert_shader) {
- shader->program = linkShaders(shader->ocio_shader, shader->vert_shader);
- }
-
- if (shader->program) {
- if (shader->shader_interface) {
- GPU_shaderinterface_discard(shader->shader_interface);
- }
- shader->shader_interface = GPU_shaderinterface_create(shader->program);
- }
- }
- }
-
- /* Update curve mapping texture. */
- if (use_curve_mapping && shader->curve_mapping_texture_allocated) {
- if (shader->curve_mapping_cache_id != curve_mapping_settings->cache_id) {
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_1D, shader->curve_mapping_texture);
- glTexSubImage1D(GL_TEXTURE_1D,
- 0,
- 0,
- curve_mapping_settings->lut_size,
- GL_RGBA,
- GL_FLOAT,
- curve_mapping_settings->lut);
- }
- }
-
- /* Bind Shader. */
- if (shader->program) {
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_3D, shader->lut3d_texture);
-
- if (use_curve_mapping) {
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_1D, shader->curve_mapping_texture);
- }
+ glActiveTexture(GL_TEXTURE4);
+ glBindTexture(GL_TEXTURE_1D, shader_curvemap->texture);
glActiveTexture(GL_TEXTURE0);
- /* IMM needs vertex format even if we don't draw with it.
- *
- * NOTE: The only reason why it's here is because of Cycles viewport.
- * All other areas are managing their own vertex formats.
- * Doing it here is probably harmless, but kind of stupid.
- *
- * TODO(sergey): Look into some nicer solution.
- */
- GPUVertFormat *format = immVertexFormat();
- GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindProgram(shader->program, shader->shader_interface);
-
- immUniform1i("image_texture", 0);
- immUniform1i("lut3d_texture", 1);
-
- if (use_dither) {
- immUniform1f("dither", dither);
- }
+ /* Bind UBO. */
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, shader_curvemap->buffer);
- if (use_curve_mapping) {
- immUniform1i("curve_mapping_texture", 2);
- immUniform1i("curve_mapping_lut_size", curve_mapping_settings->lut_size);
- immUniform1i("use_curve_mapping_extend_extrapolate",
- curve_mapping_settings->use_extend_extrapolate);
- immUniform4fv("curve_mapping_mintable", curve_mapping_settings->mintable);
- immUniform4fv("curve_mapping_range", curve_mapping_settings->range);
- immUniform4fv("curve_mapping_ext_in_x", curve_mapping_settings->ext_in_x);
- immUniform4fv("curve_mapping_ext_in_y", curve_mapping_settings->ext_in_y);
- immUniform4fv("curve_mapping_ext_out_x", curve_mapping_settings->ext_out_x);
- immUniform4fv("curve_mapping_ext_out_y", curve_mapping_settings->ext_out_y);
- immUniform4fv("curve_mapping_first_x", curve_mapping_settings->first_x);
- immUniform4fv("curve_mapping_first_y", curve_mapping_settings->first_y);
- immUniform4fv("curve_mapping_last_x", curve_mapping_settings->last_x);
- immUniform4fv("curve_mapping_last_y", curve_mapping_settings->last_y);
- immUniform3fv("curve_mapping_black", curve_mapping_settings->black);
- immUniform3fv("curve_mapping_bwmul", curve_mapping_settings->bwmul);
- }
+ /* TODO(fclem) remove remains of IMM. */
+ immBindProgram(shader->program, shader->interface);
+
+ /* Bind Shader and set uniforms. */
+ // glUseProgram(shader->program);
+ glUniform1f(shader->dither_loc, dither);
+ glUniform1i(shader->overlay_tex_loc, use_overlay ? 1 : 0);
+ glUniform1i(shader->overlay_loc, use_overlay);
+ glUniform1i(shader->predivide_loc, use_predivide);
+ glUniform1i(shader->curve_mapping_loc, use_curve_mapping);
return true;
}
- else {
- glActiveTexture(state->last_texture_unit);
- glBindTexture(GL_TEXTURE_2D, state->last_texture);
- return false;
- }
+ return false;
}
-void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
+void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState * /*state*/)
{
- glActiveTexture(state->last_texture_unit);
- glBindTexture(GL_TEXTURE_2D, state->last_texture);
immUnbindProgram();
}
void OCIOImpl::freeGLState(OCIO_GLSLDrawState *state)
{
for (int i = 0; i < SHADER_CACHE_SIZE; i++) {
- if (state->shader_cache[i]) {
- freeGLSLShader(state->shader_cache[i]);
+ if (state->shader_cache[i].data) {
+ freeGLSLShader((OCIO_GLSLShader *)state->shader_cache[i].data);
+ }
+ if (state->lut3d_cache[i].data) {
+ freeGLSLLut3d((OCIO_GLSLLut3d *)state->lut3d_cache[i].data);
+ }
+ if (state->curvemap_cache[i].data) {
+ freeGLSLCurveMapping((OCIO_GLSLCurveMappping *)state->curvemap_cache[i].data);
}
}
MEM_freeN(state);
}
+
+/** \} */