Fixed typo in OCIO GLSL module, was using address to a pointer..
[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         bool lut3d_texture_valid;
64
65         GLuint lut3d_texture;  /* OGL texture ID for 3D LUT */
66
67         float *lut3d;  /* 3D LUT table */
68
69         /* Cache */
70         std::string lut3dcacheid;
71         std::string shadercacheid;
72
73         /* GLSL stuff */
74         GLuint fragShader;
75         GLuint program;
76
77         /* Previous OpenGL state. */
78         GLint last_texture, last_texture_unit;
79 } OCIO_GLSLDrawState;
80
81 /* Hardcoded to do alpha predivide before color space conversion */
82 static const char *g_fragShaderText = ""
83 "\n"
84 "uniform sampler2D tex1;\n"
85 "uniform sampler3D tex2;\n"
86 "uniform bool predivide;\n"
87 "\n"
88 "void main()\n"
89 "{\n"
90 "    vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
91 "    if (predivide == false || col[3] == 1.0f || col[3] == 0.0f) {\n"
92 "      gl_FragColor = OCIODisplay(col, tex2);\n"
93 "    } else {\n"
94 "      float alpha = col[3];\n"
95 "      float inv_alpha = 1.0f / alpha;\n"
96 "\n"
97 "      col[0] *= inv_alpha;\n"
98 "      col[1] *= inv_alpha;\n"
99 "      col[2] *= inv_alpha;\n"
100 "\n"
101 "      gl_FragColor = OCIODisplay(col, tex2);\n"
102 "\n"
103 "      col[0] *= alpha;\n"
104 "      col[1] *= alpha;\n"
105 "      col[2] *= alpha;\n"
106 "    }\n"
107 "\n"
108 "}\n";
109
110 static GLuint compileShaderText(GLenum shaderType, const char *text)
111 {
112         GLuint shader;
113         GLint stat;
114
115         shader = glCreateShader(shaderType);
116         glShaderSource(shader, 1, (const GLchar **) &text, NULL);
117         glCompileShader(shader);
118         glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
119
120         if (!stat) {
121                 GLchar log[1000];
122                 GLsizei len;
123                 glGetShaderInfoLog(shader, 1000, &len, log);
124                 return 0;
125         }
126
127         return shader;
128 }
129
130 static GLuint linkShaders(GLuint fragShader)
131 {
132         if (!fragShader)
133                 return 0;
134
135         GLuint program = glCreateProgram();
136
137         if (fragShader)
138                 glAttachShader(program, fragShader);
139
140         glLinkProgram(program);
141
142         /* check link */
143         {
144                 GLint stat;
145                 glGetProgramiv(program, GL_LINK_STATUS, &stat);
146                 if (!stat) {
147                         GLchar log[1000];
148                         GLsizei len;
149                         glGetProgramInfoLog(program, 1000, &len, log);
150                         fprintf(stderr, "Shader link error:\n%s\n", log);
151                         return 0;
152                 }
153         }
154
155         return program;
156 }
157
158 static OCIO_GLSLDrawState *allocateOpenGLState(void)
159 {
160         OCIO_GLSLDrawState *state;
161
162         /* Allocate memory for state. */
163         state = (OCIO_GLSLDrawState *) MEM_callocN(sizeof(OCIO_GLSLDrawState),
164                                                    "OCIO OpenGL State struct");
165
166         /* Call constructors on new memory. */
167         new (&state->lut3dcacheid) std::string("");
168         new (&state->shadercacheid) std::string("");
169
170         return state;
171 }
172
173 /* Ensure LUT texture and array are allocated */
174 static bool ensureLUT3DAllocated(OCIO_GLSLDrawState *state)
175 {
176         int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE;
177
178         if (state->lut3d_texture_allocated)
179                 return state->lut3d_texture_valid;
180
181         glGenTextures(1, &state->lut3d_texture);
182
183         state->lut3d = (float *) MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT");
184
185         glActiveTexture(GL_TEXTURE1);
186         glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
187         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
188         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
189         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
190         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
191         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
192
193         /* clean glError buffer */
194         while (glGetError() != GL_NO_ERROR) {}
195
196         glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
197                      LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
198                      0, GL_RGB, GL_FLOAT, state->lut3d);
199
200         state->lut3d_texture_allocated = true;
201
202         /* GL_RGB16F_ARB could be not supported at some drivers
203          * in this case we could not use GLSL display
204          */
205         state->lut3d_texture_valid = glGetError() == GL_NO_ERROR;
206
207         return state->lut3d_texture_valid;
208 }
209
210 /**
211  * Setup OpenGL contexts for a transform defined by processor using GLSL
212  * All LUT allocating baking and shader compilation happens here.
213  *
214  * Once this function is called, callee could start drawing images
215  * using regular 2D texture.
216  *
217  * When all drawing is finished, finishGLSLDraw shall be called to
218  * restore OpenGL context to it's pre-GLSL draw state.
219  */
220 bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide)
221 {
222         ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
223
224         /* Create state if needed. */
225         OCIO_GLSLDrawState *state;
226         if (!*state_r)
227                 *state_r = allocateOpenGLState();
228         state = *state_r;
229
230         glGetIntegerv(GL_TEXTURE_2D, &state->last_texture);
231         glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit);
232
233         if (!ensureLUT3DAllocated(state)) {
234                 glActiveTexture(state->last_texture_unit);
235                 glBindTexture(GL_TEXTURE_2D, state->last_texture);
236
237                 return false;
238         }
239
240         /* Step 1: Create a GPU Shader Description */
241         GpuShaderDesc shaderDesc;
242         shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0);
243         shaderDesc.setFunctionName("OCIODisplay");
244         shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
245
246         /* Step 2: Compute the 3D LUT */
247         std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc);
248         if (lut3dCacheID != state->lut3dcacheid) {
249                 state->lut3dcacheid = lut3dCacheID;
250                 ocio_processor->getGpuLut3D(state->lut3d, shaderDesc);
251
252                 glActiveTexture(GL_TEXTURE1);
253                 glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
254                 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0,
255                                 LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
256                                 GL_RGB, GL_FLOAT, state->lut3d);
257         }
258
259         /* Step 3: Compute the Shader */
260         std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
261         if (state->program == 0 || shaderCacheID != state->shadercacheid) {
262                 state->shadercacheid = shaderCacheID;
263
264                 std::ostringstream os;
265                 os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
266                 os << g_fragShaderText;
267
268                 if (state->fragShader)
269                         glDeleteShader(state->fragShader);
270
271                 state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
272
273                 if (state->fragShader) {
274                         if (state->program)
275                                 glDeleteProgram(state->program);
276
277                         state->program = linkShaders(state->fragShader);
278                 }
279         }
280
281         if (state->program) {
282                 glActiveTexture(GL_TEXTURE1);
283                 glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
284
285                 glActiveTexture(GL_TEXTURE0);
286
287                 glUseProgram(state->program);
288                 glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
289                 glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
290                 glUniform1i(glGetUniformLocation(state->program, "predivide"), predivide);
291
292                 return true;
293         }
294         else {
295                 glActiveTexture(state->last_texture_unit);
296                 glBindTexture(GL_TEXTURE_2D, state->last_texture);
297
298                 return false;
299         }
300 }
301
302 void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
303 {
304         glActiveTexture(state->last_texture_unit);
305         glBindTexture(GL_TEXTURE_2D, state->last_texture);
306         glUseProgram(0);
307 }
308
309 void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
310 {
311         using std::string;
312
313         if (state->lut3d_texture_allocated)
314                 glDeleteTextures(1, &state->lut3d_texture);
315
316         if (state->lut3d)
317                 MEM_freeN(state->lut3d);
318
319         if (state->program)
320                 glDeleteProgram(state->program);
321
322         if (state->fragShader)
323                 glDeleteShader(state->fragShader);
324
325         state->lut3dcacheid.~string();
326         state->shadercacheid.~string();
327
328         MEM_freeN(state);
329 }