diff options
-rw-r--r-- | SConstruct | 1 | ||||
-rw-r--r-- | intern/opencolorio/CMakeLists.txt | 2 | ||||
-rw-r--r-- | intern/opencolorio/SConscript | 7 | ||||
-rw-r--r-- | intern/opencolorio/fallback_impl.cc | 3 | ||||
-rw-r--r-- | intern/opencolorio/gpu_shader_display_transform.glsl | 123 | ||||
-rw-r--r-- | intern/opencolorio/ocio_capi.cc | 5 | ||||
-rw-r--r-- | intern/opencolorio/ocio_capi.h | 59 | ||||
-rw-r--r-- | intern/opencolorio/ocio_impl.h | 9 | ||||
-rw-r--r-- | intern/opencolorio/ocio_impl_glsl.cc | 164 | ||||
-rw-r--r-- | source/blender/editors/render/render_internal.c | 2 | ||||
-rw-r--r-- | source/blender/editors/screen/glutil.c | 9 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_colormanagement.h | 9 | ||||
-rw-r--r-- | source/blender/imbuf/intern/colormanagement.c | 119 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_render.c | 4 |
14 files changed, 428 insertions, 88 deletions
diff --git a/SConstruct b/SConstruct index 539414d6fba..f9fa289a2b0 100644 --- a/SConstruct +++ b/SConstruct @@ -552,6 +552,7 @@ if B.targets != ['cudakernels']: data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vertex.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl") + data_to_c_simple("intern/opencolorio/gpu_shader_display_transform.glsl") # --- blender --- data_to_c_simple("release/datafiles/bfont.pfb") diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index 30a74baa646..3a139dc64cf 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -62,6 +62,8 @@ if(WITH_OPENCOLORIO) ${BOOST_INCLUDE_DIR} ) endif() + + data_to_c_simple(gpu_shader_display_transform.glsl SRC) endif() diff --git a/intern/opencolorio/SConscript b/intern/opencolorio/SConscript index 7f050f25cae..70aa9000719 100644 --- a/intern/opencolorio/SConscript +++ b/intern/opencolorio/SConscript @@ -39,6 +39,13 @@ if env['WITH_BF_OCIO']: if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): incs += ' ' + env['BF_BOOST_INC'] + + # generated data files + import os + sources.extend(( + os.path.join(env['DATA_SOURCES'], "gpu_shader_display_transform.glsl.c"), + )) + else: sources.remove('ocio_impl.cc') sources.remove('ocio_impl_glsl.cc') diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index 36dac689287..ca999eab569 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -418,7 +418,8 @@ bool FallbackImpl::supportGLSLDraw(void) return false; } -bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/, OCIO_ConstProcessorRcPtr * /*processor*/, bool /*predivide*/) +bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/, OCIO_ConstProcessorRcPtr * /*processor*/, + OCIO_CurveMappingSettings * /*curve_mapping_settings*/, bool /*predivide*/) { return false; } diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl new file mode 100644 index 00000000000..6ba3fa55e8f --- /dev/null +++ b/intern/opencolorio/gpu_shader_display_transform.glsl @@ -0,0 +1,123 @@ +uniform sampler2D image_texture; +uniform sampler3D lut3d_texture; +uniform bool predivide; + +#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 ivec4 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; + +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 texture1D(curve_mapping_texture, texture_index) [table]; +} + +float curvemap_calc_extend(int table, float x, vec2 first, vec2 last) +{ + if (x <= first[0]) { + if (use_curve_mapping_extend_extrapolate[table] == 0) { + /* no extrapolate */ + 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]; + } + } + else if (x >= last[0]) { + if (use_curve_mapping_extend_extrapolate[table] == 0) { + /* no extrapolate */ + 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]; + } + } + return 0.0; +} + +float curvemap_evaluateF(int table, float value) +{ + float mintable_ = curve_mapping_mintable[table]; + float range = curve_mapping_range[table]; + float mintable = 0.0; + int CM_TABLE = curve_mapping_lut_size - 1; + + float fi; + int i; + + /* index in table */ + fi = (value - mintable) * range; + i = int(fi); + + /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */ + if (fi < 0.0 || fi > float(CM_TABLE)) { + return curvemap_calc_extend(table, value, + vec2(curve_mapping_first_x[table], curve_mapping_first_y[table]), + vec2(curve_mapping_last_x[table], curve_mapping_last_y[table])); + } + else { + if (i < 0) return read_curve_mapping(table, 0); + 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); + } +} + +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]; + return result; +} +#endif + +void main() +{ + vec4 col = texture2D(image_texture, gl_TexCoord[0].st); +#ifdef USE_CURVE_MAPPING + col = curvemapping_evaluate_premulRGBF(col); +#endif + if (predivide && 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; + } + + /* 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 + */ + gl_FragColor = OCIODisplay(col, lut3d_texture); +} diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc index 1656ad9cbc0..30668dff245 100644 --- a/intern/opencolorio/ocio_capi.cc +++ b/intern/opencolorio/ocio_capi.cc @@ -323,9 +323,10 @@ int OCIO_supportGLSLDraw(void) return (int) impl->supportGLSLDraw(); } -int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, int predivide) +int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, + OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide) { - return (int) impl->setupGLSLDraw(state_r, processor, (bool) predivide); + return (int) impl->setupGLSLDraw(state_r, processor, curve_mapping_settings, predivide); } void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state) diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h index 0846b8ff7b3..5532ade1f3a 100644 --- a/intern/opencolorio/ocio_capi.h +++ b/intern/opencolorio/ocio_capi.h @@ -54,6 +54,62 @@ OCIO_DECLARE_HANDLE(OCIO_ExponentTransformRcPtr); OCIO_DECLARE_HANDLE(OCIO_MatrixTransformRcPtr); OCIO_DECLARE_HANDLE(OCIO_ConstLookRcPtr); +/* This structure is used to pass curve mapping settings from + * blender's DNA structure stored in view transform settings + * to a generic OpenColorIO C-API. + */ +typedef struct OCIO_CurveMappingSettings { + /* This is a LUT which contain values for all 4 curve mapping tables + * (combined, R, G and B). + * + * Element I for table T is stored at I * 4 + T element of this LUT. + * + * This array is usually returned by curvemapping_table_RGBA(). + */ + float *lut; + + /* Size of single curve mapping table, 1/4 size of lut array. */ + int lut_size; + + /* Extend extrapolation flags for all the tables. + * if use_extend_extrapolate[T] != 0 means extrapolation for + * table T is needed. + */ + int use_extend_extrapolate[4]; + + /* Minimal X value of the curve mapping tables. */ + float mintable[4]; + + /* Per curve mapping table range. */ + float range[4]; + + /* Lower extension value, stored as per-component arrays. */ + float ext_in_x[4], ext_in_y[4]; + + /* Higher extension value, stored as per-component arrays. */ + float ext_out_x[4], ext_out_y[4]; + + /* First points of the tables, both X and Y values. + * Needed for easier and faster access when extrapolating. + */ + float first_x[4], first_y[4]; + + /* Last points of the tables, both X and Y values. + * Needed for easier and faster access when extrapolating. + */ + float last_x[4], last_y[4]; + + /* Premultiplication settings: black level and scale to match + * with white level. + */ + float black[3], bwmul[3]; + + /* Cache id of the original curve mapping, used to detect when + * upload of new settings to GPU is needed. + */ + size_t cache_id; +} OCIO_CurveMappingSettings; + void OCIO_init(void); void OCIO_exit(void); @@ -132,7 +188,8 @@ void OCIO_matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt); 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, int predivide); +int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, + OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide); void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state); void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state); diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h index 48d18fa78ea..8b666e8ae14 100644 --- a/intern/opencolorio/ocio_impl.h +++ b/intern/opencolorio/ocio_impl.h @@ -106,7 +106,8 @@ public: virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0; virtual bool supportGLSLDraw(void) = 0; - virtual bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide) = 0; + virtual bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, + OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide) = 0; virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0; virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0; }; @@ -189,7 +190,8 @@ public: void matrixTransformScale(float *m44, float *offset4, const float *scale4); bool supportGLSLDraw(void); - bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide); + bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, + OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide); void finishGLSLDraw(struct OCIO_GLSLDrawState *state); void freeGLState(struct OCIO_GLSLDrawState *state_r); }; @@ -273,7 +275,8 @@ public: void matrixTransformScale(float * m44, float * offset4, const float * scale4); bool supportGLSLDraw(void); - bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide); + bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, + OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide); 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 1a3132fa4b3..a10afcad200 100644 --- a/intern/opencolorio/ocio_impl_glsl.cc +++ b/intern/opencolorio/ocio_impl_glsl.cc @@ -48,6 +48,8 @@ using namespace OCIO_NAMESPACE; static const int LUT3D_EDGE_SIZE = 64; +extern char datatoc_gpu_shader_display_transform_glsl[]; + /* **** OpenGL drawing routines using GLSL for color space transform ***** */ typedef struct OCIO_GLSLDrawState { @@ -60,42 +62,24 @@ typedef struct OCIO_GLSLDrawState { float *lut3d; /* 3D LUT table */ + bool curve_mapping_used; + bool curve_mapping_texture_allocated; + bool curve_mapping_texture_valid; + GLuint curve_mapping_texture; + size_t curve_mapping_cache_id; + /* Cache */ std::string lut3dcacheid; std::string shadercacheid; /* GLSL stuff */ - GLuint fragShader; + GLuint ocio_shader; GLuint program; /* Previous OpenGL state. */ GLint last_texture, last_texture_unit; } OCIO_GLSLDrawState; -/* Hardcoded to do alpha predivide before color space conversion */ -/* 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 - */ -static const char *g_fragShaderText = "" -"\n" -"uniform sampler2D tex1;\n" -"uniform sampler3D tex2;\n" -"uniform bool predivide;\n" -"\n" -"void main()\n" -"{\n" -" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n" -" if (predivide && col[3] > 0.0 && col[3] < 1.0) {\n" -" float inv_alpha = 1.0 / col[3];\n" -" col[0] *= inv_alpha;\n" -" col[1] *= inv_alpha;\n" -" col[2] *= inv_alpha;\n" -" }\n" -" gl_FragColor = OCIODisplay(col, tex2);\n" -"\n" -"}\n"; - static GLuint compileShaderText(GLenum shaderType, const char *text) { GLuint shader; @@ -117,15 +101,14 @@ static GLuint compileShaderText(GLenum shaderType, const char *text) return shader; } -static GLuint linkShaders(GLuint fragShader) +static GLuint linkShaders(GLuint ocio_shader) { - if (!fragShader) + if (!ocio_shader) return 0; GLuint program = glCreateProgram(); - if (fragShader) - glAttachShader(program, fragShader); + glAttachShader(program, ocio_shader); glLinkProgram(program); @@ -197,6 +180,37 @@ static bool ensureLUT3DAllocated(OCIO_GLSLDrawState *state) return state->lut3d_texture_valid; } +static bool ensureCurveMappingAllocated(OCIO_GLSLDrawState *state, OCIO_CurveMappingSettings *curve_mapping_settings) +{ + if (state->curve_mapping_texture_allocated) + return state->curve_mapping_texture_valid; + + glGenTextures(1, &state->curve_mapping_texture); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_1D, state->curve_mapping_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) {} + + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA16F_ARB, curve_mapping_settings->lut_size, + 0, GL_RGBA, GL_FLOAT, curve_mapping_settings->lut); + + state->curve_mapping_texture_allocated = true; + + /* GL_RGB16F_ARB could be not supported at some drivers + * in this case we could not use GLSL display + */ + state->curve_mapping_texture_valid = glGetError() == GL_NO_ERROR; + + return state->curve_mapping_texture_valid; +} + /* Detect if we can support GLSL drawing */ bool OCIOImpl::supportGLSLDraw() { @@ -214,9 +228,11 @@ bool OCIOImpl::supportGLSLDraw() * When all drawing is finished, finishGLSLDraw shall be called to * restore OpenGL context to it's pre-GLSL draw state. */ -bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide) +bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, + OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide) { ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor; + bool use_curve_mapping = curve_mapping_settings != NULL; /* Create state if needed. */ OCIO_GLSLDrawState *state; @@ -234,12 +250,36 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc return false; } + if (use_curve_mapping) { + if (!ensureCurveMappingAllocated(state, curve_mapping_settings)) { + glActiveTexture(state->last_texture_unit); + glBindTexture(GL_TEXTURE_2D, state->last_texture); + + return false; + } + } + else { + if (state->curve_mapping_texture_allocated) { + glDeleteTextures(1, &state->curve_mapping_texture); + state->curve_mapping_texture_allocated = false; + } + } + /* Step 1: Create a GPU Shader Description */ GpuShaderDesc shaderDesc; shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0); shaderDesc.setFunctionName("OCIODisplay"); shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE); + if (use_curve_mapping) { + if (state->curve_mapping_cache_id != curve_mapping_settings->cache_id) { + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_1D, state->curve_mapping_texture); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, curve_mapping_settings->lut_size, + GL_RGBA, GL_FLOAT, curve_mapping_settings->lut); + } + } + /* Step 2: Compute the 3D LUT */ std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc); if (lut3dCacheID != state->lut3dcacheid) { @@ -255,37 +295,73 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc /* Step 3: Compute the Shader */ std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc); - if (state->program == 0 || shaderCacheID != state->shadercacheid) { + if (state->program == 0 || + shaderCacheID != state->shadercacheid || + use_curve_mapping != state->curve_mapping_used) + { state->shadercacheid = shaderCacheID; + if (state->program) { + glDeleteProgram(state->program); + } + + if (state->ocio_shader) { + glDeleteShader(state->ocio_shader); + } + std::ostringstream os; - os << ocio_processor->getGpuShaderText(shaderDesc) << "\n"; - os << g_fragShaderText; - if (state->fragShader) - glDeleteShader(state->fragShader); + if (use_curve_mapping) { + os << "#define USE_CURVE_MAPPING\n"; + } - state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str()); + os << ocio_processor->getGpuShaderText(shaderDesc) << "\n"; + os << datatoc_gpu_shader_display_transform_glsl; - if (state->fragShader) { - if (state->program) - glDeleteProgram(state->program); + state->ocio_shader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str()); - state->program = linkShaders(state->fragShader); + if (state->ocio_shader) { + state->program = linkShaders(state->ocio_shader); } + + state->curve_mapping_used = use_curve_mapping; } if (state->program) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_3D, state->lut3d_texture); + if (use_curve_mapping) { + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_1D, state->curve_mapping_texture); + } + glActiveTexture(GL_TEXTURE0); glUseProgram(state->program); - glUniform1i(glGetUniformLocation(state->program, "tex1"), 0); - glUniform1i(glGetUniformLocation(state->program, "tex2"), 1); + + glUniform1i(glGetUniformLocation(state->program, "image_texture"), 0); + glUniform1i(glGetUniformLocation(state->program, "lut3d_texture"), 1); glUniform1i(glGetUniformLocation(state->program, "predivide"), predivide); + if (use_curve_mapping) { + glUniform1i(glGetUniformLocation(state->program, "curve_mapping_texture"), 2); + glUniform1i(glGetUniformLocation(state->program, "curve_mapping_lut_size"), curve_mapping_settings->lut_size); + glUniform4iv(glGetUniformLocation(state->program, "use_curve_mapping_extend_extrapolate"), 1, curve_mapping_settings->use_extend_extrapolate); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_mintable"), 1, curve_mapping_settings->mintable); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_range"), 1, curve_mapping_settings->range); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_in_x"), 1, curve_mapping_settings->ext_in_x); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_in_y"), 1, curve_mapping_settings->ext_in_y); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_out_x"), 1, curve_mapping_settings->ext_out_x); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_out_y"), 1, curve_mapping_settings->ext_out_y); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_first_x"), 1, curve_mapping_settings->first_x); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_first_y"), 1, curve_mapping_settings->first_y); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_last_x"), 1, curve_mapping_settings->last_x); + glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_last_y"), 1, curve_mapping_settings->last_y); + glUniform3fv(glGetUniformLocation(state->program, "curve_mapping_black"), 1, curve_mapping_settings->black); + glUniform3fv(glGetUniformLocation(state->program, "curve_mapping_bwmul"), 1, curve_mapping_settings->bwmul); + } + return true; } else { @@ -316,8 +392,8 @@ void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state) if (state->program) glDeleteProgram(state->program); - if (state->fragShader) - glDeleteShader(state->fragShader); + if (state->ocio_shader) + glDeleteShader(state->ocio_shader); state->lut3dcacheid.~string(); state->shadercacheid.~string(); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 39d6f836815..df8d5ec4e84 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -1152,7 +1152,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) /* Try using GLSL display transform. */ if (force_fallback == false) { - if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, true, false)) { + if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, true)) { glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glaDrawPixelsTex(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_FLOAT, diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 70e5aab6628..b70b06f2aa4 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -1091,18 +1091,15 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, if (ibuf->rect_float) { if (ibuf->float_colorspace) { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - ibuf->float_colorspace, - true, false); + ibuf->float_colorspace, true); } else { - ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, - true, false); + ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, true); } } else { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - ibuf->rect_colorspace, - false, false); + ibuf->rect_colorspace, false); } if (ok) { diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 64a2bbb72d9..8af86389db3 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -174,19 +174,16 @@ void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processo /* ** OpenGL drawing routines using GLSL for color space transform ** */ /* Test if GLSL drawing is supported for combination of graphics card and this configuration */ -bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings *view_settings, - bool skip_curves); +bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings *view_settings); /* Configures GLSL shader for conversion from scene linear to display space */ bool IMB_colormanagement_setup_glsl_draw(const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, - bool predivide, - bool skip_curves); + bool predivide); /* Same as above, but display space conversion happens from a specified space */ bool IMB_colormanagement_setup_glsl_draw_from_space(const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, struct ColorSpace *colorspace, - bool predivide, - bool skip_curves); + bool predivide); /* Same as setup_glsl_draw, but color management settings are guessing from a given context */ bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C, bool predivide); /* Same as setup_glsl_draw_from_space, but color management settings are guessing from a given context */ diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 61051464c7f..cf9cc0c2e6f 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -119,6 +119,11 @@ static struct global_glsl_state { char input[MAX_COLORSPACE_NAME]; float exposure, gamma; + CurveMapping *curve_mapping, *orig_curve_mapping; + bool use_curve_mapping; + int curve_mapping_timestamp; + OCIO_CurveMappingSettings curve_mapping_settings; + /* Container for GLSL state needed for OCIO module. */ struct OCIO_GLSLDrawState *ocio_glsl_state; struct OCIO_GLSLDrawState *transform_ocio_glsl_state; @@ -663,6 +668,12 @@ void colormanagement_exit(void) if (global_glsl_state.processor) OCIO_processorRelease(global_glsl_state.processor); + if (global_glsl_state.curve_mapping) + curvemapping_free(global_glsl_state.curve_mapping); + + if (global_glsl_state.curve_mapping_settings.lut) + MEM_freeN(global_glsl_state.curve_mapping_settings.lut); + if (global_glsl_state.ocio_glsl_state) OCIO_freeOGLState(global_glsl_state.ocio_glsl_state); @@ -2937,16 +2948,61 @@ static bool check_glsl_display_processor_changed(const ColorManagedViewSettings STREQ(global_glsl_state.input, from_colorspace)); } +static void curve_mapping_to_ocio_settings(CurveMapping *curve_mapping, + OCIO_CurveMappingSettings *curve_mapping_settings) +{ + int i; + + curvemapping_initialize(curve_mapping); + curvemapping_premultiply(curve_mapping, false); + curvemapping_table_RGBA(curve_mapping, + &curve_mapping_settings->lut, + &curve_mapping_settings->lut_size); + + for (i = 0; i < 4; i++) { + CurveMap *cuma = curve_mapping->cm + i; + curve_mapping_settings->use_extend_extrapolate[i] = (cuma->flag & CUMA_EXTEND_EXTRAPOLATE) != 0; + curve_mapping_settings->range[i] = cuma->range; + curve_mapping_settings->mintable[i] = cuma->mintable; + curve_mapping_settings->ext_in_x[i] = cuma->ext_in[0]; + curve_mapping_settings->ext_in_y[i] = cuma->ext_in[1]; + curve_mapping_settings->ext_out_x[i] = cuma->ext_out[0]; + curve_mapping_settings->ext_out_y[i] = cuma->ext_out[1]; + curve_mapping_settings->first_x[i] = cuma->table[0].x; + curve_mapping_settings->first_y[i] = cuma->table[0].y; + curve_mapping_settings->last_x[i] = cuma->table[CM_TABLE].x; + curve_mapping_settings->last_y[i] = cuma->table[CM_TABLE].y; + } + + copy_v3_v3(curve_mapping_settings->black, curve_mapping->black); + copy_v3_v3(curve_mapping_settings->bwmul, curve_mapping->bwmul); + + curve_mapping_settings->cache_id = (size_t) curve_mapping; +} + static void update_glsl_display_processor(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, const char *from_colorspace) { + bool use_curve_mapping = (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) != 0; + bool need_update = false; + + need_update = global_glsl_state.processor == NULL || + check_glsl_display_processor_changed(view_settings, display_settings, from_colorspace) || + use_curve_mapping != global_glsl_state.use_curve_mapping; + + if (use_curve_mapping && need_update == false) { + need_update |= view_settings->curve_mapping->changed_timestamp != global_glsl_state.curve_mapping_timestamp || + view_settings->curve_mapping != global_glsl_state.orig_curve_mapping; + } + /* Update state if there's no processor yet or * processor settings has been changed. */ - if (global_glsl_state.processor == NULL || - check_glsl_display_processor_changed(view_settings, display_settings, from_colorspace)) - { + if (need_update) { + OCIO_CurveMappingSettings *curve_mapping_settings = &global_glsl_state.curve_mapping_settings; + CurveMapping *new_curve_mapping = NULL; + /* Store settings of processor for further comparison. */ BLI_strncpy(global_glsl_state.look, view_settings->look, MAX_COLORSPACE_NAME); BLI_strncpy(global_glsl_state.view, view_settings->view_transform, MAX_COLORSPACE_NAME); @@ -2955,6 +3011,35 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s global_glsl_state.exposure = view_settings->exposure; global_glsl_state.gamma = view_settings->gamma; + /* We're using curve mapping's address as a acache ID, + * so we need to make sure re-allocation gives new address here. + * We do this by allocating new curve mapping before freeing ol one. + */ + if (use_curve_mapping) { + new_curve_mapping = curvemapping_copy(view_settings->curve_mapping); + } + + if (global_glsl_state.curve_mapping) { + curvemapping_free(global_glsl_state.curve_mapping); + MEM_freeN(curve_mapping_settings->lut); + global_glsl_state.curve_mapping = NULL; + curve_mapping_settings->lut = NULL; + } + + /* Fill in OCIO's curve mapping settings. */ + if (use_curve_mapping) { + curve_mapping_to_ocio_settings(new_curve_mapping, &global_glsl_state.curve_mapping_settings); + + global_glsl_state.curve_mapping = new_curve_mapping; + global_glsl_state.curve_mapping_timestamp = view_settings->curve_mapping->changed_timestamp; + global_glsl_state.orig_curve_mapping = view_settings->curve_mapping; + global_glsl_state.use_curve_mapping = true; + } + else { + global_glsl_state.orig_curve_mapping = NULL; + global_glsl_state.use_curve_mapping = false; + } + /* Free old processor, if any. */ if (global_glsl_state.processor) OCIO_processorRelease(global_glsl_state.processor); @@ -2970,14 +3055,8 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s } } -bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *view_settings, - bool skip_curves) +bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSED(view_settings)) { - /* curves not supported yet */ - if (!skip_curves) - if (view_settings && (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES)) - return 0; - return OCIO_supportGLSLDraw(); } @@ -2996,8 +3075,7 @@ bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *view_ */ bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, - struct ColorSpace *from_colorspace, bool predivide, - bool skip_curves) + struct ColorSpace *from_colorspace, bool predivide) { ColorManagedViewSettings default_view_settings; const ColorManagedViewSettings *applied_view_settings; @@ -3014,25 +3092,22 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettin applied_view_settings = &default_view_settings; } - /* RGB curves mapping is not supported on GPU yet. */ - if (!skip_curves) - if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) - return false; - /* Make sure OCIO processor is up-to-date. */ update_glsl_display_processor(applied_view_settings, display_settings, from_colorspace ? from_colorspace->name : global_role_scene_linear); - return OCIO_setupGLSLDraw(&global_glsl_state.ocio_glsl_state, global_glsl_state.processor, predivide); + return OCIO_setupGLSLDraw(&global_glsl_state.ocio_glsl_state, global_glsl_state.processor, + global_glsl_state.use_curve_mapping ? &global_glsl_state.curve_mapping_settings : NULL, + predivide); } /* Configures GLSL shader for conversion from scene linear to display space */ bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, - bool predivide, bool skip_curves) + bool predivide) { return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - NULL, predivide, skip_curves); + NULL, predivide); } /* Same as setup_glsl_draw_from_space, but color management settings are guessing from a given context */ @@ -3043,7 +3118,7 @@ bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings); - return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, from_colorspace, predivide, false); + return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, from_colorspace, predivide); } /* Same as setup_glsl_draw, but color management settings are guessing from a given context */ @@ -3082,7 +3157,7 @@ bool IMB_colormanagement_setup_transform_from_role_glsl(int role, bool predivide processor = colorspace_to_scene_linear_processor(colorspace); - return OCIO_setupGLSLDraw(&global_glsl_state.transform_ocio_glsl_state, processor, predivide); + return OCIO_setupGLSLDraw(&global_glsl_state.transform_ocio_glsl_state, processor, NULL, predivide); } /* Finish GLSL-based color space conversion */ diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 5b809a51705..7ebbcf7b39b 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -66,14 +66,14 @@ static void engine_tag_update(RenderEngine *engine) static int engine_support_display_space_shader(RenderEngine *UNUSED(engine), Scene *scene) { - return IMB_colormanagement_support_glsl_draw(&scene->view_settings, true); + return IMB_colormanagement_support_glsl_draw(&scene->view_settings); } static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene *scene) { IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, - false, true); + false); } static void engine_unbind_display_space_shader(RenderEngine *UNUSED(engine)) |