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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2013-03-29 20:02:27 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2013-03-29 20:02:27 +0400
commit2dff7c01ada2a645d39c2acdc83a10e4a295b35b (patch)
treeb68b29a7488b500b8beca2961685badfaf83952f /intern/opencolorio
parent44a43afd0e858a8a3d563ff0a1a7b6b8043bd8f3 (diff)
Implement GPU-side display transform for clip editor
Implemented using GLSL API from OpenColorIO library and some general functions were added to it's c-api: - OCIO_setupGLSLDraw prepares OpenGL context for GPU-based transformation for a giver processor. This function compiles and links shader, sets up it's argument. After this transformation would be applied on an image displaying as a 2D texture. So, glaDrawPixelsTex called after OCIO_setupGLSLDraw will do a proper color space transform. - OCIO_finishGLSLDraw restores OpenGL context after all color-managed display is over. - OCIO_freeOGLState frees allocated state structure used for cacheing some GLSL-related stuff. There're some utility functions in IMB_colormanagent which are basically proxies to lower level OCIO functions but which could be used from any place in blender. Chacheing of movie clip frame on GPU is also removed now, and either glaDrawPixelsTex or glaDrawPixelsAuto are used for display now. This is so no code duplication happens now and no large textures are lurking around in GPU memory. Known issues: - Texture buffer and GLSL are no longer checking for video card capabilities, possibly could lead to some artifacts on crappy drivers/cards. - Only float buffers are displaying using GLSL, byte buffers will still use fallback display method. This is to be addressed later. - If RGB curves are used as a part of display transform, GLSL display will also be disabled. This is also thing to be solved later. Additional changes: - glaDrawPixelsTexScaled will now use RGBA16F as an internal format of storing textures when it's used to draw float buffer. This is needed so LUT are applied without precision loss.
Diffstat (limited to 'intern/opencolorio')
-rw-r--r--intern/opencolorio/CMakeLists.txt1
-rw-r--r--intern/opencolorio/SConscript1
-rw-r--r--intern/opencolorio/fallback_impl.cc12
-rw-r--r--intern/opencolorio/ocio_capi.cc15
-rw-r--r--intern/opencolorio/ocio_capi.h6
-rw-r--r--intern/opencolorio/ocio_impl.cc235
-rw-r--r--intern/opencolorio/ocio_impl.h12
-rw-r--r--intern/opencolorio/ocio_impl_glsl.cc274
8 files changed, 556 insertions, 0 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);
+}