59845abca338fe65d534d739ff7b991b3ac10dac
[blender.git] / intern / opencolorio / ocio_impl_glsl.cc
1 /*
2  * Adapted from OpenColorIO with this license:
3  *
4  * Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
5  * All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * * Neither the name of Sony Pictures Imageworks nor the names of its
16  *   contributors may be used to endorse or promote products derived from
17  *   this software without specific prior written permission.
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Modifications Copyright 2013, Blender Foundation.
31  *
32  * Contributor(s): Sergey Sharybin
33  *
34  */
35
36 #include <sstream>
37 #include <string.h>
38
39 #ifdef __APPLE__
40 #include <OpenGL/gl.h>
41 #include <OpenGL/glu.h>
42 #else
43 #include <GL/glew.h>
44 #endif
45
46 #include <OpenColorIO/OpenColorIO.h>
47
48 using namespace OCIO_NAMESPACE;
49
50 #include "MEM_guardedalloc.h"
51
52 #include "ocio_impl.h"
53
54 static const int LUT3D_EDGE_SIZE = 32;
55
56
57 /* **** OpenGL drawing routines using GLSL for color space transform ***** */
58
59 typedef struct OCIO_GLSLDrawState {
60         bool lut3d_texture_allocated;  /* boolean flag indicating whether
61                                         * lut texture is allocated
62                                         */
63
64         GLuint lut3d_texture;  /* OGL texture ID for 3D LUT */
65
66         float *lut3d;  /* 3D LUT table */
67
68         /* Cache */
69         std::string lut3dcacheid;
70         std::string shadercacheid;
71
72         /* GLSL stuff */
73         GLuint fragShader;
74         GLuint program;
75
76         /* Previous OpenGL state. */
77         GLint last_texture, last_texture_unit;
78 } OCIO_GLSLDrawState;
79
80 static const char * g_fragShaderText = ""
81 "\n"
82 "uniform sampler2D tex1;\n"
83 "uniform sampler3D tex2;\n"
84 "\n"
85 "void main()\n"
86 "{\n"
87 "    vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
88 "    gl_FragColor = OCIODisplay(col, tex2);\n"
89 "}\n";
90
91 static GLuint compileShaderText(GLenum shaderType, const char *text)
92 {
93         GLuint shader;
94         GLint stat;
95
96         shader = glCreateShader(shaderType);
97         glShaderSource(shader, 1, (const GLchar **) &text, NULL);
98         glCompileShader(shader);
99         glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
100
101         if (!stat) {
102                 GLchar log[1000];
103                 GLsizei len;
104                 glGetShaderInfoLog(shader, 1000, &len, log);
105                 return 0;
106         }
107
108         return shader;
109 }
110
111 static GLuint linkShaders(GLuint fragShader)
112 {
113         if (!fragShader)
114                 return 0;
115
116         GLuint program = glCreateProgram();
117
118         if (fragShader)
119                 glAttachShader(program, fragShader);
120
121         glLinkProgram(program);
122
123         /* check link */
124         {
125                 GLint stat;
126                 glGetProgramiv(program, GL_LINK_STATUS, &stat);
127                 if (!stat) {
128                         GLchar log[1000];
129                         GLsizei len;
130                         glGetProgramInfoLog(program, 1000, &len, log);
131                         fprintf(stderr, "Shader link error:\n%s\n", log);
132                         return 0;
133                 }
134         }
135
136         return program;
137 }
138
139 static OCIO_GLSLDrawState *allocateOpenGLState(void)
140 {
141         OCIO_GLSLDrawState *state;
142
143         /* Allocate memory for state. */
144         state = (OCIO_GLSLDrawState *) MEM_callocN(sizeof(OCIO_GLSLDrawState),
145                                                    "OCIO OpenGL State struct");
146
147         /* Call constructors on new memory. */
148         new (&state->lut3dcacheid) std::string("");
149         new (&state->shadercacheid) std::string("");
150
151         return state;
152 }
153
154 /* Ensure LUT texture and array are allocated */
155 static void ensureLUT3DAllocated(OCIO_GLSLDrawState *state)
156 {
157         int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE;
158
159         if (state->lut3d_texture_allocated)
160                 return;
161
162         glGenTextures(1, &state->lut3d_texture);
163
164         state->lut3d = (float *) MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT");
165
166         glActiveTexture(GL_TEXTURE1);
167         glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
168         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
169         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
170         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
171         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
172         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
173         glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
174                      LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
175                      0, GL_RGB,GL_FLOAT, &state->lut3d);
176
177         state->lut3d_texture_allocated = true;
178 }
179
180 /**
181  * Setup OpenGL contexts for a transform defined by processor using GLSL
182  * All LUT allocating baking and shader compilation happens here.
183  *
184  * Once this function is called, callee could start drawing images
185  * using regular 2D texture.
186  *
187  * When all drawing is finished, finishGLSLDraw shall be called to
188  * restore OpenGL context to it's pre-GLSL draw state.
189  */
190 bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor)
191 {
192         ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
193
194         /* Create state if needed. */
195         OCIO_GLSLDrawState *state;
196         if (!*state_r)
197                 *state_r = allocateOpenGLState();
198         state = *state_r;
199
200         glGetIntegerv(GL_TEXTURE_2D, &state->last_texture);
201         glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit);
202
203         ensureLUT3DAllocated(state);
204
205         /* Step 1: Create a GPU Shader Description */
206         GpuShaderDesc shaderDesc;
207         shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0);
208         shaderDesc.setFunctionName("OCIODisplay");
209         shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
210
211         /* Step 2: Compute the 3D LUT */
212         std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc);
213         if (lut3dCacheID != state->lut3dcacheid) {
214                 state->lut3dcacheid = lut3dCacheID;
215                 ocio_processor->getGpuLut3D(state->lut3d, shaderDesc);
216
217                 glActiveTexture(GL_TEXTURE1);
218                 glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
219                 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0,
220                                 LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
221                                 GL_RGB, GL_FLOAT, state->lut3d);
222         }
223
224         /* Step 3: Compute the Shader */
225         std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
226         if (state->program == 0 || shaderCacheID != state->shadercacheid) {
227                 state->shadercacheid = shaderCacheID;
228
229                 std::ostringstream os;
230                 os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
231                 os << g_fragShaderText;
232
233                 if (state->fragShader)
234                         glDeleteShader(state->fragShader);
235
236                 state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
237
238                 if (state->fragShader) {
239                         if (state->program)
240                                 glDeleteProgram(state->program);
241
242                         state->program = linkShaders(state->fragShader);
243                 }
244         }
245
246         if (state->program) {
247                 glActiveTexture(GL_TEXTURE1);
248                 glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
249
250                 glActiveTexture(GL_TEXTURE0);
251
252                 glUseProgram(state->program);
253                 glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
254                 glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
255
256                 return true;
257         }
258         else {
259                 glActiveTexture(state->last_texture_unit);
260                 glBindTexture(GL_TEXTURE_2D, state->last_texture);
261
262                 return false;
263         }
264 }
265
266 void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
267 {
268         glActiveTexture(state->last_texture_unit);
269         glBindTexture(GL_TEXTURE_2D, state->last_texture);
270         glUseProgram(0);
271 }
272
273 void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
274 {
275         using std::string;
276
277         if (state->lut3d_texture_allocated)
278                 glDeleteTextures(1, &state->lut3d_texture);
279
280         if (state->lut3d)
281                 MEM_freeN(state->lut3d);
282
283         if (state->program)
284                 glDeleteProgram(state->program);
285
286         if (state->fragShader)
287                 glDeleteShader(state->fragShader);
288
289         state->lut3dcacheid.~string();
290         state->shadercacheid.~string();
291
292         MEM_freeN(state);
293 }