Implementation of curve mapping in GLSL

The title says it all, now having curve mapping
enabled in color management settings wouldn't
force fallback from GLSL to CPU based color space
conversion.
This commit is contained in:
Sergey Sharybin 2013-10-09 15:57:32 +00:00
parent d917bdb095
commit 6e1fe4ddd9
14 changed files with 433 additions and 93 deletions

View File

@ -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")

View File

@ -62,6 +62,8 @@ if(WITH_OPENCOLORIO)
${BOOST_INCLUDE_DIR}
)
endif()
data_to_c_simple(gpu_shader_display_transform.glsl SRC)
endif()

View File

@ -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')

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -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);
};

View File

@ -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;
std::ostringstream os;
os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
os << g_fragShaderText;
if (state->fragShader)
glDeleteShader(state->fragShader);
state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
if (state->fragShader) {
if (state->program)
glDeleteProgram(state->program);
state->program = linkShaders(state->fragShader);
if (state->program) {
glDeleteProgram(state->program);
}
if (state->ocio_shader) {
glDeleteShader(state->ocio_shader);
}
std::ostringstream os;
if (use_curve_mapping) {
os << "#define USE_CURVE_MAPPING\n";
}
os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
os << datatoc_gpu_shader_display_transform_glsl;
state->ocio_shader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
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();

View File

@ -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,

View File

@ -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) {

View File

@ -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 */

View File

@ -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 */

View File

@ -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))