diff options
-rw-r--r-- | intern/opencolorio/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/opencolorio/SConscript | 1 | ||||
-rw-r--r-- | intern/opencolorio/fallback_impl.cc | 12 | ||||
-rw-r--r-- | intern/opencolorio/ocio_capi.cc | 15 | ||||
-rw-r--r-- | intern/opencolorio/ocio_capi.h | 6 | ||||
-rw-r--r-- | intern/opencolorio/ocio_impl.cc | 235 | ||||
-rw-r--r-- | intern/opencolorio/ocio_impl.h | 12 | ||||
-rw-r--r-- | intern/opencolorio/ocio_impl_glsl.cc | 274 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 1 | ||||
-rw-r--r-- | source/blender/editors/include/ED_clip.h | 7 | ||||
-rw-r--r-- | source/blender/editors/screen/glutil.c | 9 | ||||
-rw-r--r-- | source/blender/editors/space_clip/clip_draw.c | 113 | ||||
-rw-r--r-- | source/blender/editors/space_clip/clip_editor.c | 161 | ||||
-rw-r--r-- | source/blender/editors/space_clip/space_clip.c | 3 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_colormanagement.h | 8 | ||||
-rw-r--r-- | source/blender/imbuf/intern/colormanagement.c | 88 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_space_types.h | 2 |
17 files changed, 728 insertions, 220 deletions
diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index c281a6e7bbb..91bf6550f27 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -52,6 +52,7 @@ if(WITH_OPENCOLORIO) list(APPEND SRC ocio_impl.cc + ocio_impl_glsl.cc ) if(WIN32 AND NOT MINGW) diff --git a/intern/opencolorio/SConscript b/intern/opencolorio/SConscript index 6e7c467f64f..e4a0d3ebb7c 100644 --- a/intern/opencolorio/SConscript +++ b/intern/opencolorio/SConscript @@ -40,5 +40,6 @@ if env['WITH_BF_OCIO']: incs += ' ' + env['BF_BOOST_INC'] else: sources.remove('ocio_impl.cc') + sources.remove('ocio_impl_glsl.cc') env.BlenderLib( 'bf_intern_opencolorio', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185]) diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index d01d8d4c8f4..47c648e9cba 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -380,3 +380,15 @@ void FallbackImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr *) void FallbackImpl::matrixTransformScale(float * , float * , const float *) { } + +void FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) +{ +} + +void FallbackImpl::finishGLSLDraw(OCIO_GLSLDrawState *state) +{ +} + +void FallbackImpl::freeGLState(struct OCIO_GLSLDrawState *state_r) +{ +} diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc index 4f839a61fad..73d8af295f2 100644 --- a/intern/opencolorio/ocio_capi.cc +++ b/intern/opencolorio/ocio_capi.cc @@ -282,3 +282,18 @@ void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4 { impl->matrixTransformScale(m44, offset4, scale4f); } + +void OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) +{ + impl->setupGLSLDraw(state_r, processor); +} + +void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state) +{ + impl->finishGLSLDraw(state); +} + +void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state) +{ + impl->freeGLState(state); +} diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h index 19fd8fe643b..3c42e0a1a1e 100644 --- a/intern/opencolorio/ocio_capi.h +++ b/intern/opencolorio/ocio_capi.h @@ -32,6 +32,8 @@ extern "C" { #endif +struct OCIO_GLSLDrawState; + #define OCIO_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name #define OCIO_ROLE_SCENE_LINEAR "scene_linear" @@ -119,6 +121,10 @@ void OCIO_matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt); void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale4); +void OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor); +void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state); +void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state); + #ifdef __cplusplus } #endif diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc index b073a038f0d..8803814ce3f 100644 --- a/intern/opencolorio/ocio_impl.cc +++ b/intern/opencolorio/ocio_impl.cc @@ -26,8 +26,16 @@ */ #include <iostream> +#include <sstream> #include <string.h> +#ifdef __APPLE__ +#include <OpenGL/gl.h> +#include <OpenGL/glu.h> +#else +#include <GL/glew.h> +#endif + #include <OpenColorIO/OpenColorIO.h> using namespace OCIO_NAMESPACE; @@ -50,6 +58,8 @@ using namespace OCIO_NAMESPACE; #define MEM_NEW(type) new(MEM_mallocN(sizeof(type), __func__)) type() #define MEM_DELETE(what, type) if(what) { ((type*)(what))->~type(); MEM_freeN(what); } (void)0 +static const int LUT3D_EDGE_SIZE = 32; + static void OCIO_reportError(const char *err) { std::cerr << "OpenColorIO Error: " << err << std::endl; @@ -541,3 +551,228 @@ void OCIOImpl::matrixTransformScale(float * m44, float * offset4, const float *s { MatrixTransform::Scale(m44, offset4, scale4f); } + +/* **** OpenGL drawing routines using GLSL for color space transform ***** */ + +/* Some of the GLSL transform related functions below are adopted from + * ociodisplay utility of OpenColorIO project which are originally + * + * Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved. + */ + +typedef struct OCIO_GLSLDrawState { + bool lut3d_texture_allocated; /* boolean flag indicating whether + * lut texture is allocated + */ + + GLuint lut3d_texture; /* OGL texture ID for 3D LUT */ + + float *lut3d; /* 3D LUT table */ + + /* Cache */ + std::string lut3dcacheid; + std::string shadercacheid; + + /* GLSL stuff */ + GLuint fragShader; + GLuint program; + + /* Previous OpenGL state. */ + GLint last_texture, last_texture_unit; +} OCIO_GLSLDrawState; + +static const char * g_fragShaderText = "" +"\n" +"uniform sampler2D tex1;\n" +"uniform sampler3D tex2;\n" +"\n" +"void main()\n" +"{\n" +" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n" +" gl_FragColor = OCIODisplay(col, tex2);\n" +"}\n"; + +static GLuint compileShaderText(GLenum shaderType, const char *text) +{ + GLuint shader; + GLint stat; + + shader = glCreateShader(shaderType); + glShaderSource(shader, 1, (const GLchar **) &text, NULL); + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &stat); + + if (!stat) { + GLchar log[1000]; + GLsizei len; + glGetShaderInfoLog(shader, 1000, &len, log); + return 0; + } + + return shader; +} + +static GLuint linkShaders(GLuint fragShader) +{ + if (!fragShader) + return 0; + + GLuint program = glCreateProgram(); + + if (fragShader) + glAttachShader(program, fragShader); + + glLinkProgram(program); + + /* check link */ + { + GLint stat; + glGetProgramiv(program, GL_LINK_STATUS, &stat); + if (!stat) { + GLchar log[1000]; + GLsizei len; + glGetProgramInfoLog(program, 1000, &len, log); + fprintf(stderr, "Shader link error:\n%s\n", log); + return 0; + } + } + + return program; +} + +static OCIO_GLSLDrawState *allocateOpenGLState(void) +{ + OCIO_GLSLDrawState *state; + + /* Allocate memory for state. */ + state = (OCIO_GLSLDrawState *) MEM_callocN(sizeof(OCIO_GLSLDrawState), + "OCIO OpenGL State struct"); + + /* Call constructors on new memory. */ + new (&state->lut3dcacheid) std::string(""); + new (&state->shadercacheid) std::string(""); + + return state; +} + +/* Ensure LUT texture and array are allocated */ +static void ensureLUT3DAllocated(OCIO_GLSLDrawState *state) +{ + int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE; + + if (state->lut3d_texture_allocated) + return; + + glGenTextures(1, &state->lut3d_texture); + + state->lut3d = (float *) MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT"); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, state->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); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB, + LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, + 0, GL_RGB,GL_FLOAT, &state->lut3d); + + state->lut3d_texture_allocated = true; +} + +/** + * Setup OpenGL contexts for a transform defined by processor using GLSL + * All LUT allocating baking and shader compilation happens here. + * + * Once this function is called, callee could start drawing images + * using regular 2D texture. + * + * When all drawing is finished, finishGLSLDraw shall be called to + * restore OpenGL context to it's pre-GLSL draw state. + */ +void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) +{ + ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor; + + /* Create state if needed. */ + OCIO_GLSLDrawState *state; + if (!*state_r) + *state_r = allocateOpenGLState(); + state = *state_r; + + glGetIntegerv(GL_TEXTURE_2D, &state->last_texture); + glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit); + + ensureLUT3DAllocated(state); + + /* Step 1: Create a GPU Shader Description */ + GpuShaderDesc shaderDesc; + shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0); + shaderDesc.setFunctionName("OCIODisplay"); + shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE); + + /* Step 2: Compute the 3D LUT */ + std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc); + if (lut3dCacheID != state->lut3dcacheid) { + state->lut3dcacheid = lut3dCacheID; + ocio_processor->getGpuLut3D(state->lut3d, shaderDesc); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, state->lut3d_texture); + glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, + LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, + GL_RGB, GL_FLOAT, state->lut3d); + } + + /* Step 3: Compute the Shader */ + std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc); + if (state->program == 0 || shaderCacheID != state->shadercacheid) { + 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->program) + glDeleteProgram(state->program); + + state->program = linkShaders(state->fragShader); + } + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, state->lut3d_texture); + + glActiveTexture(GL_TEXTURE0); + + glUseProgram(state->program); + glUniform1i(glGetUniformLocation(state->program, "tex1"), 0); + glUniform1i(glGetUniformLocation(state->program, "tex2"), 1); +} + +void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state) +{ + glActiveTexture(state->last_texture_unit); + glBindTexture(GL_TEXTURE_2D, state->last_texture); + glUseProgram(0); +} + +void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state) +{ + using std::string; + + if (state->lut3d_texture_allocated) + glDeleteTextures(1, &state->lut3d_texture); + + if (state->lut3d) + MEM_freeN(state->lut3d); + + state->lut3dcacheid.~string(); + state->shadercacheid.~string(); + + MEM_freeN(state); +} diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h index b6bbc912e5b..2a1f88be5f4 100644 --- a/intern/opencolorio/ocio_impl.h +++ b/intern/opencolorio/ocio_impl.h @@ -95,6 +95,10 @@ public: virtual void matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt) = 0; virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0; + + virtual void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) = 0; + virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0; + virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0; }; class FallbackImpl : public IOCIOImpl { @@ -164,6 +168,10 @@ public: void matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt); void matrixTransformScale(float * m44, float * offset4, const float * scale4); + + void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor); + void finishGLSLDraw(struct OCIO_GLSLDrawState *state); + void freeGLState(struct OCIO_GLSLDrawState *state_r); }; #ifdef WITH_OCIO @@ -234,6 +242,10 @@ public: void matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt); void matrixTransformScale(float * m44, float * offset4, const float * scale4); + + void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor); + void finishGLSLDraw(struct OCIO_GLSLDrawState *state); + void freeGLState(struct OCIO_GLSLDrawState *state_r); }; #endif diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc new file mode 100644 index 00000000000..c79593779cf --- /dev/null +++ b/intern/opencolorio/ocio_impl_glsl.cc @@ -0,0 +1,274 @@ +/* + * Adapted from OpenColorIO with this license: + * + * Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Modifications Copyright 2013, Blender Foundation. + * + * Contributor(s): Sergey Sharybin + * + */ + +#include <sstream> +#include <string.h> + +#ifdef __APPLE__ +#include <OpenGL/gl.h> +#include <OpenGL/glu.h> +#else +#include <GL/glew.h> +#endif + +#include <OpenColorIO/OpenColorIO.h> + +using namespace OCIO_NAMESPACE; + +#include "MEM_guardedalloc.h" + +#include "ocio_impl.h" + +static const int LUT3D_EDGE_SIZE = 32; + + +/* **** OpenGL drawing routines using GLSL for color space transform ***** */ + +typedef struct OCIO_GLSLDrawState { + bool lut3d_texture_allocated; /* boolean flag indicating whether + * lut texture is allocated + */ + + GLuint lut3d_texture; /* OGL texture ID for 3D LUT */ + + float *lut3d; /* 3D LUT table */ + + /* Cache */ + std::string lut3dcacheid; + std::string shadercacheid; + + /* GLSL stuff */ + GLuint fragShader; + GLuint program; + + /* Previous OpenGL state. */ + GLint last_texture, last_texture_unit; +} OCIO_GLSLDrawState; + +static const char * g_fragShaderText = "" +"\n" +"uniform sampler2D tex1;\n" +"uniform sampler3D tex2;\n" +"\n" +"void main()\n" +"{\n" +" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n" +" gl_FragColor = OCIODisplay(col, tex2);\n" +"}\n"; + +static GLuint compileShaderText(GLenum shaderType, const char *text) +{ + GLuint shader; + GLint stat; + + shader = glCreateShader(shaderType); + glShaderSource(shader, 1, (const GLchar **) &text, NULL); + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &stat); + + if (!stat) { + GLchar log[1000]; + GLsizei len; + glGetShaderInfoLog(shader, 1000, &len, log); + return 0; + } + + return shader; +} + +static GLuint linkShaders(GLuint fragShader) +{ + if (!fragShader) + return 0; + + GLuint program = glCreateProgram(); + + if (fragShader) + glAttachShader(program, fragShader); + + glLinkProgram(program); + + /* check link */ + { + GLint stat; + glGetProgramiv(program, GL_LINK_STATUS, &stat); + if (!stat) { + GLchar log[1000]; + GLsizei len; + glGetProgramInfoLog(program, 1000, &len, log); + fprintf(stderr, "Shader link error:\n%s\n", log); + return 0; + } + } + + return program; +} + +static OCIO_GLSLDrawState *allocateOpenGLState(void) +{ + OCIO_GLSLDrawState *state; + + /* Allocate memory for state. */ + state = (OCIO_GLSLDrawState *) MEM_callocN(sizeof(OCIO_GLSLDrawState), + "OCIO OpenGL State struct"); + + /* Call constructors on new memory. */ + new (&state->lut3dcacheid) std::string(""); + new (&state->shadercacheid) std::string(""); + + return state; +} + +/* Ensure LUT texture and array are allocated */ +static void ensureLUT3DAllocated(OCIO_GLSLDrawState *state) +{ + int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE; + + if (state->lut3d_texture_allocated) + return; + + glGenTextures(1, &state->lut3d_texture); + + state->lut3d = (float *) MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT"); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, state->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); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB, + LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, + 0, GL_RGB,GL_FLOAT, &state->lut3d); + + state->lut3d_texture_allocated = true; +} + +/** + * Setup OpenGL contexts for a transform defined by processor using GLSL + * All LUT allocating baking and shader compilation happens here. + * + * Once this function is called, callee could start drawing images + * using regular 2D texture. + * + * When all drawing is finished, finishGLSLDraw shall be called to + * restore OpenGL context to it's pre-GLSL draw state. + */ +void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) +{ + ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor; + + /* Create state if needed. */ + OCIO_GLSLDrawState *state; + if (!*state_r) + *state_r = allocateOpenGLState(); + state = *state_r; + + glGetIntegerv(GL_TEXTURE_2D, &state->last_texture); + glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit); + + ensureLUT3DAllocated(state); + + /* Step 1: Create a GPU Shader Description */ + GpuShaderDesc shaderDesc; + shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0); + shaderDesc.setFunctionName("OCIODisplay"); + shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE); + + /* Step 2: Compute the 3D LUT */ + std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc); + if (lut3dCacheID != state->lut3dcacheid) { + state->lut3dcacheid = lut3dCacheID; + ocio_processor->getGpuLut3D(state->lut3d, shaderDesc); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, state->lut3d_texture); + glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, + LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, + GL_RGB, GL_FLOAT, state->lut3d); + } + + /* Step 3: Compute the Shader */ + std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc); + if (state->program == 0 || shaderCacheID != state->shadercacheid) { + 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->program) + glDeleteProgram(state->program); + + state->program = linkShaders(state->fragShader); + } + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, state->lut3d_texture); + + glActiveTexture(GL_TEXTURE0); + + glUseProgram(state->program); + glUniform1i(glGetUniformLocation(state->program, "tex1"), 0); + glUniform1i(glGetUniformLocation(state->program, "tex2"), 1); +} + +void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state) +{ + glActiveTexture(state->last_texture_unit); + glBindTexture(GL_TEXTURE_2D, state->last_texture); + glUseProgram(0); +} + +void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state) +{ + using std::string; + + if (state->lut3d_texture_allocated) + glDeleteTextures(1, &state->lut3d_texture); + + if (state->lut3d) + MEM_freeN(state->lut3d); + + state->lut3dcacheid.~string(); + state->shadercacheid.~string(); + + MEM_freeN(state); +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 7399bfec2b5..682680e53c5 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6350,7 +6350,6 @@ static void direct_link_screen(FileData *fd, bScreen *sc) sclip->scopes.track_search = NULL; sclip->scopes.track_preview = NULL; - sclip->draw_context = NULL; sclip->scopes.ok = 0; } } diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 28727c913cb..541956136bd 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -39,6 +39,7 @@ struct Main; struct Mask; struct MovieClip; struct SpaceClip; +struct Scene; /* ** clip_editor.c ** */ @@ -81,12 +82,6 @@ void ED_space_clip_set_clip(struct bContext *C, struct bScreen *screen, struct S struct Mask *ED_space_clip_get_mask(struct SpaceClip *sc); void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask); -/* textures buffer */ -int ED_space_clip_texture_buffer_supported(struct SpaceClip *sc); -int ED_space_clip_load_movieclip_buffer(struct SpaceClip *sc, struct ImBuf *ibuf, const unsigned char *display_buffer); -void ED_space_clip_unload_movieclip_buffer(struct SpaceClip *sc); -void ED_space_clip_free_texture_buffer(struct SpaceClip *sc); - /* ** clip_ops.c ** */ void ED_operatormacros_clip(void); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 8501b53afae..89315e041de 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -519,6 +519,15 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, nsubparts_x = (img_w + (offset_x - 1)) / (offset_x); nsubparts_y = (img_h + (offset_y - 1)) / (offset_y); + if (format == GL_FLOAT) { + /* need to set internal format to higher range float */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, GL_FLOAT, NULL); + } + else { + /* switch to 8bit RGBA for byte buffer */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) { for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) { int remainder_x = img_w - subpart_x * offset_x; diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 2d3dc9127c3..cbca2f0c46e 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -248,6 +248,53 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar) ED_region_info_draw(ar, str, block, 0.6f); } +static void draw_movieclip_buffer_glsl(SpaceClip *sc, ImBuf *ibuf, int x, int y, + float zoomx, float zoomy) +{ + MovieClip *clip = ED_space_clip_get_clip(sc); + int filter = GL_LINEAR; + + glPushMatrix(); + glTranslatef(x, y, 0.0f); + glScalef(zoomx, zoomy, 1.0f); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glColor4f(1.0, 1.0, 1.0, 1.0); + + /* non-scaled proxy shouldn;t use diltering */ + if ((clip->flag & MCLIP_USE_PROXY) == 0 || + ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100)) + { + filter = GL_NEAREST; + } + + glaDrawPixelsTex(0, 0, ibuf->x, ibuf->y, GL_FLOAT, filter, ibuf->rect_float); + + glPopMatrix(); +} + +static void draw_movieclip_buffer_fallback(const bContext *C, ImBuf *ibuf, int x, int y, + int width, int height, float zoomx, float zoomy) +{ + unsigned char *display_buffer; + void *cache_handle; + + display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle); + + if (display_buffer) { + /* set zoom */ + glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y); + + glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer); + + /* reset zoom */ + glPixelZoom(1.0f, 1.0f); + } + + IMB_display_buffer_release(cache_handle); +} + static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, ImBuf *ibuf, int width, int height, float zoomx, float zoomy) { @@ -261,62 +308,32 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, glRectf(x, y, x + zoomx * width, y + zoomy * height); } else { - unsigned char *display_buffer; - void *cache_handle; - - display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle); - - if (display_buffer) { - int need_fallback = 1; - - /* checkerboard for case alpha */ - if (ibuf->planes == 32) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); - } + bool need_fallback = true; - if (ED_space_clip_texture_buffer_supported(sc)) { - if (ED_space_clip_load_movieclip_buffer(sc, ibuf, display_buffer)) { - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + /* checkerboard for case alpha */ + if (ibuf->planes == 32) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPushMatrix(); - glTranslatef(x, y, 0.0f); - glScalef(zoomx, zoomy, 1.0f); - - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); - glTexCoord2f(1.0f, 0.0f); glVertex2f(width, 0.0f); - glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height); - glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, height); - glEnd(); - - glPopMatrix(); - - ED_space_clip_unload_movieclip_buffer(sc); - - need_fallback = 0; - } - } + fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); + } - /* if texture buffers aren't efficiently supported or texture is too large to - * be binder fallback to simple draw pixels solution */ - if (need_fallback) { - /* set zoom */ - glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y); + /* GLSL display transform for byte buffers is not supported yet */ + if (ibuf->rect_float && IMB_coloemanagement_setup_glsl_draw_from_ctx(C)) { + draw_movieclip_buffer_glsl(sc, ibuf, x, y, zoomx, zoomy); - glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer); + IMB_coloemanagement_finish_glsl_draw(); - /* reset zoom */ - glPixelZoom(1.0f, 1.0f); - } + need_fallback = false; + } - if (ibuf->planes == 32) - glDisable(GL_BLEND); + /* if GLSL display failed, fallback to regular glaDrawPixelsAuto method */ + if (need_fallback) { + draw_movieclip_buffer_fallback(C, ibuf, x, y, width, height, zoomx, zoomy); } - IMB_display_buffer_release(cache_handle); + if (ibuf->planes == 32) + glDisable(GL_BLEND); } } diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index b00cc564a99..d297d0485e3 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -62,15 +62,13 @@ #include "GPU_extensions.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "ED_screen.h" #include "ED_clip.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" - #include "WM_api.h" #include "WM_types.h" @@ -580,163 +578,6 @@ void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask) } } -/* OpenGL draw context */ - -typedef struct SpaceClipDrawContext { - int support_checked, buffers_supported; - - GLuint texture; /* OGL texture ID */ - short texture_allocated; /* flag if texture was allocated by glGenTextures */ - struct ImBuf *texture_ibuf; /* image buffer for which texture was created */ - const unsigned char *display_buffer; /* display buffer for which texture was created */ - int image_width, image_height; /* image width and height for which texture was created */ - unsigned last_texture; /* ID of previously used texture, so it'll be restored after clip drawing */ - - /* fields to check if cache is still valid */ - int framenr, start_frame, frame_offset; - short render_size, render_flag; - - char colorspace[64]; -} SpaceClipDrawContext; - -int ED_space_clip_texture_buffer_supported(SpaceClip *sc) -{ - SpaceClipDrawContext *context = sc->draw_context; - - if (!context) { - context = MEM_callocN(sizeof(SpaceClipDrawContext), "SpaceClipDrawContext"); - sc->draw_context = context; - } - - if (!context->support_checked) { - context->support_checked = TRUE; - if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { - context->buffers_supported = FALSE; - } - else { - context->buffers_supported = GPU_non_power_of_two_support(); - } - } - - return context->buffers_supported; -} - -int ED_space_clip_load_movieclip_buffer(SpaceClip *sc, ImBuf *ibuf, const unsigned char *display_buffer) -{ - SpaceClipDrawContext *context = sc->draw_context; - MovieClip *clip = ED_space_clip_get_clip(sc); - int need_rebind = 0; - - context->last_texture = glaGetOneInteger(GL_TEXTURE_2D); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - /* image texture need to be rebinded if displaying another image buffer - * assuming displaying happens of footage frames only on which painting doesn't happen. - * so not changed image buffer pointer means unchanged image content */ - need_rebind |= context->texture_ibuf != ibuf; - need_rebind |= context->display_buffer != display_buffer; - need_rebind |= context->framenr != sc->user.framenr; - need_rebind |= context->render_size != sc->user.render_size; - need_rebind |= context->render_flag != sc->user.render_flag; - need_rebind |= context->start_frame != clip->start_frame; - need_rebind |= context->frame_offset != clip->frame_offset; - - if (!need_rebind) { - /* OCIO_TODO: not entirely nice, but currently it seems to be easiest way - * to deal with changing input color space settings - * pointer-based check could fail due to new buffers could be - * be allocated on on old memory - */ - need_rebind = strcmp(context->colorspace, clip->colorspace_settings.name) != 0; - } - - if (need_rebind) { - int width = ibuf->x, height = ibuf->y; - int need_recreate = 0; - - if (width > GL_MAX_TEXTURE_SIZE || height > GL_MAX_TEXTURE_SIZE) - return 0; - - /* if image resolution changed (e.g. switched to proxy display) texture need to be recreated */ - need_recreate = context->image_width != ibuf->x || context->image_height != ibuf->y; - - if (context->texture_ibuf && need_recreate) { - glDeleteTextures(1, &context->texture); - context->texture_allocated = 0; - } - - if (need_recreate || !context->texture_allocated) { - /* texture doesn't exist yet or need to be re-allocated because of changed dimensions */ - int filter = GL_LINEAR; - - /* non-scaled proxy shouldn;t use diltering */ - if ((clip->flag & MCLIP_USE_PROXY) == 0 || - ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100)) - { - filter = GL_NEAREST; - } - - glGenTextures(1, &context->texture); - glBindTexture(GL_TEXTURE_2D, context->texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - } - else { - /* if texture doesn't need to be reallocated itself, just bind it so - * loading of image will happen to a proper texture */ - glBindTexture(GL_TEXTURE_2D, context->texture); - } - - if (display_buffer) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer); - - /* store settings */ - context->texture_allocated = 1; - context->display_buffer = display_buffer; - context->texture_ibuf = ibuf; - context->image_width = ibuf->x; - context->image_height = ibuf->y; - context->framenr = sc->user.framenr; - context->render_size = sc->user.render_size; - context->render_flag = sc->user.render_flag; - context->start_frame = clip->start_frame; - context->frame_offset = clip->frame_offset; - - BLI_strncpy(context->colorspace, clip->colorspace_settings.name, sizeof(context->colorspace)); - } - else { - /* displaying exactly the same image which was loaded t oa texture, - * just bint texture in this case */ - glBindTexture(GL_TEXTURE_2D, context->texture); - } - - glEnable(GL_TEXTURE_2D); - - return TRUE; -} - -void ED_space_clip_unload_movieclip_buffer(SpaceClip *sc) -{ - SpaceClipDrawContext *context = sc->draw_context; - - glBindTexture(GL_TEXTURE_2D, context->last_texture); - glDisable(GL_TEXTURE_2D); -} - -void ED_space_clip_free_texture_buffer(SpaceClip *sc) -{ - SpaceClipDrawContext *context = sc->draw_context; - - if (context) { - glDeleteTextures(1, &context->texture); - - MEM_freeN(context); - } -} - /* ******** pre-fetching functions ******** */ typedef struct PrefetchJob { diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index ced19020034..64b643f8a58 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -327,8 +327,6 @@ static void clip_free(SpaceLink *sl) if (sc->scopes.track_search) IMB_freeImBuf(sc->scopes.track_search); - - ED_space_clip_free_texture_buffer(sc); } /* spacetype; init callback */ @@ -348,7 +346,6 @@ static SpaceLink *clip_duplicate(SpaceLink *sl) scn->scopes.track_search = NULL; scn->scopes.track_preview = NULL; scn->scopes.ok = FALSE; - scn->draw_context = NULL; return (SpaceLink *)scn; } diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index b981390582e..473bd7d0c7a 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -148,6 +148,14 @@ void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_process int channels, int predivide); void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor); +/* ** OpenGL drawing routines using GLSL for color space transform ** */ + +int IMB_coloemanagement_setup_glsl_draw(const struct ColorManagedViewSettings *view_settings, + const struct ColorManagedDisplaySettings *display_settings); + +int IMB_coloemanagement_setup_glsl_draw_from_ctx(const struct bContext *C); +void IMB_coloemanagement_finish_glsl_draw(void); + /* Roles */ enum { COLOR_ROLE_SCENE_LINEAR = 0, diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 65a3db839a9..6c33f6e3e33 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -102,6 +102,19 @@ typedef struct ColormanageProcessor { int is_data_result; } ColormanageProcessor; +static struct global_glsl_state { + /* Actual processor used for GLSL baked LUTs. */ + OCIO_ConstProcessorRcPtr *processor; + + /* Settings of processor for comparison. */ + char view[MAX_COLORSPACE_NAME]; + char display[MAX_COLORSPACE_NAME]; + float exposure, gamma; + + /* Container for GLSL state needed for OCIO module. */ + struct OCIO_GLSLDrawState *ocio_glsl_state; +} global_glsl_state; + /*********************** Color managed cache *************************/ /* Cache Implementation Notes @@ -607,6 +620,12 @@ void colormanagement_init(void) void colormanagement_exit(void) { + if (global_glsl_state.processor) + OCIO_processorRelease(global_glsl_state.processor); + + if (global_glsl_state.ocio_glsl_state) + OCIO_freeOGLState(global_glsl_state.ocio_glsl_state); + colormanage_free_config(); } @@ -2691,3 +2710,72 @@ void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor) MEM_freeN(cm_processor); } + +/* **** OpenGL drawing routines using GLSL for color space transform ***** */ + +static bool check_glsl_display_processor_changed(const ColorManagedViewSettings *view_settings, + const ColorManagedDisplaySettings *display_settings) +{ + return !(global_glsl_state.exposure == view_settings->exposure && + global_glsl_state.gamma == view_settings->gamma && + STREQ(global_glsl_state.view, view_settings->view_transform) && + STREQ(global_glsl_state.display, display_settings->display_device)); +} + +static void update_glsl_display_processor(const ColorManagedViewSettings *view_settings, + const ColorManagedDisplaySettings *display_settings) +{ + /* 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)) + { + /* Store settings of processor for further comparison. */ + strcpy(global_glsl_state.view, view_settings->view_transform); + strcpy(global_glsl_state.display, display_settings->display_device); + global_glsl_state.exposure = view_settings->exposure; + global_glsl_state.gamma = view_settings->gamma; + + /* Free old processor, if any. */ + if (global_glsl_state.processor) + OCIO_processorRelease(global_glsl_state.processor); + + /* We're using display OCIO processor, no RGB curves yet. */ + global_glsl_state.processor = + create_display_buffer_processor(global_glsl_state.view, + global_glsl_state.display, + global_glsl_state.exposure, + global_glsl_state.gamma); + } +} + +int IMB_coloemanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, + const ColorManagedDisplaySettings *display_settings) +{ + /* RGB curves mapping is not supported on GPU yet. */ + if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) + return FALSE; + + /* Make sure OCIO processor is up-to-date. */ + update_glsl_display_processor(view_settings, display_settings); + + OCIO_setupGLSLDraw(&global_glsl_state.ocio_glsl_state, global_glsl_state.processor); + + return TRUE; +} + +int IMB_coloemanagement_setup_glsl_draw_from_ctx(const bContext *C) +{ + ColorManagedViewSettings *view_settings; + ColorManagedDisplaySettings *display_settings; + + display_transform_get_from_ctx(C, &view_settings, &display_settings); + + return IMB_coloemanagement_setup_glsl_draw(view_settings, display_settings); +} + +void IMB_coloemanagement_finish_glsl_draw(void) +{ + OCIO_finishGLSLDraw(global_glsl_state.ocio_glsl_state); +} diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index e5e38d66de5..8253bb570f6 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1072,8 +1072,6 @@ typedef struct SpaceClip { /* grease pencil */ short gpencil_src, pad2; - void *draw_context; - int around, pad4; /* pivot point for transforms */ MaskSpaceInfo mask_info; |