Print error log to the console if OCIO shader compilation failed
[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                 fprintf(stderr, "Shader compile error:\n%s\n", log);
125                 return 0;
126         }
127
128         return shader;
129 }
130
131 static GLuint linkShaders(GLuint fragShader)
132 {
133         if (!fragShader)
134                 return 0;
135
136         GLuint program = glCreateProgram();
137
138         if (fragShader)
139                 glAttachShader(program, fragShader);
140
141         glLinkProgram(program);
142
143         /* check link */
144         {
145                 GLint stat;
146                 glGetProgramiv(program, GL_LINK_STATUS, &stat);
147                 if (!stat) {
148                         GLchar log[1000];
149                         GLsizei len;
150                         glGetProgramInfoLog(program, 1000, &len, log);
151                         fprintf(stderr, "Shader link error:\n%s\n", log);
152                         return 0;
153                 }
154         }
155
156         return program;
157 }
158
159 static OCIO_GLSLDrawState *allocateOpenGLState(void)
160 {
161         OCIO_GLSLDrawState *state;
162
163         /* Allocate memory for state. */
164         state = (OCIO_GLSLDrawState *) MEM_callocN(sizeof(OCIO_GLSLDrawState),
165                                                    "OCIO OpenGL State struct");
166
167         /* Call constructors on new memory. */
168         new (&state->lut3dcacheid) std::string("");
169         new (&state->shadercacheid) std::string("");
170
171         return state;
172 }
173
174 /* Ensure LUT texture and array are allocated */
175 static bool ensureLUT3DAllocated(OCIO_GLSLDrawState *state)
176 {
177         int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE;
178
179         if (state->lut3d_texture_allocated)
180                 return state->lut3d_texture_valid;
181
182         glGenTextures(1, &state->lut3d_texture);
183
184         state->lut3d = (float *) MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT");
185
186         glActiveTexture(GL_TEXTURE1);
187         glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
188         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
189         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
190         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
191         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
192         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
193
194         /* clean glError buffer */
195         while (glGetError() != GL_NO_ERROR) {}
196
197         glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
198                      LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
199                      0, GL_RGB, GL_FLOAT, state->lut3d);
200
201         state->lut3d_texture_allocated = true;
202
203         /* GL_RGB16F_ARB could be not supported at some drivers
204          * in this case we could not use GLSL display
205          */
206         state->lut3d_texture_valid = glGetError() == GL_NO_ERROR;
207
208         return state->lut3d_texture_valid;
209 }
210
211 /**
212  * Setup OpenGL contexts for a transform defined by processor using GLSL
213  * All LUT allocating baking and shader compilation happens here.
214  *
215  * Once this function is called, callee could start drawing images
216  * using regular 2D texture.
217  *
218  * When all drawing is finished, finishGLSLDraw shall be called to
219  * restore OpenGL context to it's pre-GLSL draw state.
220  */
221 bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide)
222 {
223         ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
224
225         /* Create state if needed. */
226         OCIO_GLSLDrawState *state;
227         if (!*state_r)
228                 *state_r = allocateOpenGLState();
229         state = *state_r;
230
231         glGetIntegerv(GL_TEXTURE_2D, &state->last_texture);
232         glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit);
233
234         if (!ensureLUT3DAllocated(state)) {
235                 glActiveTexture(state->last_texture_unit);
236                 glBindTexture(GL_TEXTURE_2D, state->last_texture);
237
238                 return false;
239         }
240
241         /* Step 1: Create a GPU Shader Description */
242         GpuShaderDesc shaderDesc;
243         shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0);
244         shaderDesc.setFunctionName("OCIODisplay");
245         shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
246
247         /* Step 2: Compute the 3D LUT */
248         std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc);
249         if (lut3dCacheID != state->lut3dcacheid) {
250                 state->lut3dcacheid = lut3dCacheID;
251                 ocio_processor->getGpuLut3D(state->lut3d, shaderDesc);
252
253                 glActiveTexture(GL_TEXTURE1);
254                 glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
255                 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0,
256                                 LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
257                                 GL_RGB, GL_FLOAT, state->lut3d);
258         }
259
260         /* Step 3: Compute the Shader */
261         std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
262         if (state->program == 0 || shaderCacheID != state->shadercacheid) {
263                 state->shadercacheid = shaderCacheID;
264
265                 std::ostringstream os;
266                 os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
267                 os << g_fragShaderText;
268
269                 if (state->fragShader)
270                         glDeleteShader(state->fragShader);
271
272                 state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
273
274                 if (state->fragShader) {
275                         if (state->program)
276                                 glDeleteProgram(state->program);
277
278                         state->program = linkShaders(state->fragShader);
279                 }
280         }
281
282         if (state->program) {
283                 glActiveTexture(GL_TEXTURE1);
284                 glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
285
286                 glActiveTexture(GL_TEXTURE0);
287
288                 glUseProgram(state->program);
289                 glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
290                 glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
291                 glUniform1i(glGetUniformLocation(state->program, "predivide"), predivide);
292
293                 return true;
294         }
295         else {
296                 glActiveTexture(state->last_texture_unit);
297                 glBindTexture(GL_TEXTURE_2D, state->last_texture);
298
299                 return false;
300         }
301 }
302
303 void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
304 {
305         glActiveTexture(state->last_texture_unit);
306         glBindTexture(GL_TEXTURE_2D, state->last_texture);
307         glUseProgram(0);
308 }
309
310 void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
311 {
312         using std::string;
313
314         if (state->lut3d_texture_allocated)
315                 glDeleteTextures(1, &state->lut3d_texture);
316
317         if (state->lut3d)
318                 MEM_freeN(state->lut3d);
319
320         if (state->program)
321                 glDeleteProgram(state->program);
322
323         if (state->fragShader)
324                 glDeleteShader(state->fragShader);
325
326         state->lut3dcacheid.~string();
327         state->shadercacheid.~string();
328
329         MEM_freeN(state);
330 }