ClangFormat: apply to source, most of intern
[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
33 #include <limits>
34 #include <sstream>
35 #include <string.h>
36
37 #include "glew-mx.h"
38
39 #ifdef _MSC_VER
40 #  pragma warning(push)
41 #  pragma warning(disable : 4251 4275)
42 #endif
43 #include <OpenColorIO/OpenColorIO.h>
44 #ifdef _MSC_VER
45 #  pragma warning(pop)
46 #endif
47
48 extern "C" {
49 #include "GPU_immediate.h"
50 }
51
52 using namespace OCIO_NAMESPACE;
53
54 #include "MEM_guardedalloc.h"
55
56 #include "ocio_impl.h"
57
58 static const int LUT3D_EDGE_SIZE = 64;
59 static const int SHADER_CACHE_SIZE = 4;
60
61 extern "C" char datatoc_gpu_shader_display_transform_glsl[];
62 extern "C" char datatoc_gpu_shader_display_transform_vertex_glsl[];
63
64 /* **** OpenGL drawing routines using GLSL for color space transform ***** */
65
66 typedef struct OCIO_GLSLShader {
67   /* Cache ID */
68   std::string lut3dCacheID;
69   std::string shaderCacheID;
70
71   /* LUT */
72   bool lut3d_texture_allocated; /* boolean flag indicating whether
73                                   * lut texture is allocated
74                                   */
75   bool lut3d_texture_valid;
76
77   GLuint lut3d_texture; /* OGL texture ID for 3D LUT */
78
79   float *lut3d; /* 3D LUT table */
80
81   /* Dither */
82   bool use_dither;
83
84   /* Curve Mapping */
85   bool use_curve_mapping;
86   bool curve_mapping_texture_allocated;
87   bool curve_mapping_texture_valid;
88   GLuint curve_mapping_texture;
89   size_t curve_mapping_cache_id;
90
91   /* Alpha Predivide */
92   bool use_predivide;
93
94   /* GLSL stuff */
95   GLuint ocio_shader;
96   GLuint vert_shader;
97   GLuint program;
98   GPUShaderInterface *shader_interface;
99 } GLSLDrawState;
100
101 typedef struct OCIO_GLSLDrawState {
102   /* Shader Cache */
103   OCIO_GLSLShader *shader_cache[SHADER_CACHE_SIZE];
104
105   /* Previous OpenGL state. */
106   GLint last_texture, last_texture_unit;
107 } OCIO_GLSLDrawState;
108
109 static GLuint compileShaderText(GLenum shaderType, const char *text)
110 {
111   GLuint shader;
112   GLint stat;
113
114   shader = glCreateShader(shaderType);
115   glShaderSource(shader, 1, (const GLchar **)&text, NULL);
116   glCompileShader(shader);
117   glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
118
119   if (!stat) {
120     GLchar log[1000];
121     GLsizei len;
122     glGetShaderInfoLog(shader, 1000, &len, log);
123     fprintf(stderr, "Shader compile error:\n%s\n", log);
124     return 0;
125   }
126
127   return shader;
128 }
129
130 static GLuint linkShaders(GLuint ocio_shader, GLuint vert_shader)
131 {
132   if (!ocio_shader || !vert_shader)
133     return 0;
134
135   GLuint program = glCreateProgram();
136
137   glAttachShader(program, ocio_shader);
138   glAttachShader(program, vert_shader);
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   return (OCIO_GLSLDrawState *)MEM_callocN(sizeof(OCIO_GLSLDrawState), "OCIO OpenGL State struct");
161 }
162
163 /* Ensure LUT texture and array are allocated */
164 static bool ensureLUT3DAllocated(OCIO_GLSLShader *shader)
165 {
166   int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE;
167
168   if (shader->lut3d_texture_allocated)
169     return shader->lut3d_texture_valid;
170
171   glGenTextures(1, &shader->lut3d_texture);
172
173   shader->lut3d = (float *)MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT");
174
175   glActiveTexture(GL_TEXTURE1);
176   glBindTexture(GL_TEXTURE_3D, shader->lut3d_texture);
177   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
178   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
179   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
180   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
181   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
182
183   /* clean glError buffer */
184   while (glGetError() != GL_NO_ERROR) {
185   }
186
187   glTexImage3D(GL_TEXTURE_3D,
188                0,
189                GL_RGB16F_ARB,
190                LUT3D_EDGE_SIZE,
191                LUT3D_EDGE_SIZE,
192                LUT3D_EDGE_SIZE,
193                0,
194                GL_RGB,
195                GL_FLOAT,
196                shader->lut3d);
197
198   shader->lut3d_texture_allocated = true;
199
200   /* GL_RGB16F_ARB could be not supported at some drivers
201    * in this case we could not use GLSL display
202    */
203   shader->lut3d_texture_valid = glGetError() == GL_NO_ERROR;
204
205   return shader->lut3d_texture_valid;
206 }
207
208 static bool ensureCurveMappingAllocated(OCIO_GLSLShader *shader,
209                                         OCIO_CurveMappingSettings *curve_mapping_settings)
210 {
211   if (shader->curve_mapping_texture_allocated)
212     return shader->curve_mapping_texture_valid;
213
214   glGenTextures(1, &shader->curve_mapping_texture);
215
216   glActiveTexture(GL_TEXTURE2);
217   glBindTexture(GL_TEXTURE_1D, shader->curve_mapping_texture);
218   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
219   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
220   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
221   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
222   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
223
224   /* clean glError buffer */
225   while (glGetError() != GL_NO_ERROR) {
226   }
227
228   glTexImage1D(GL_TEXTURE_1D,
229                0,
230                GL_RGBA16F,
231                curve_mapping_settings->lut_size,
232                0,
233                GL_RGBA,
234                GL_FLOAT,
235                curve_mapping_settings->lut);
236
237   shader->curve_mapping_texture_allocated = true;
238
239   /* GL_RGB16F_ARB could be not supported at some drivers
240    * in this case we could not use GLSL display
241    */
242   shader->curve_mapping_texture_valid = glGetError() == GL_NO_ERROR;
243
244   return shader->curve_mapping_texture_valid;
245 }
246
247 static void freeGLSLShader(OCIO_GLSLShader *shader)
248 {
249   if (shader->curve_mapping_texture_allocated) {
250     glDeleteTextures(1, &shader->curve_mapping_texture);
251   }
252
253   if (shader->lut3d_texture_allocated) {
254     glDeleteTextures(1, &shader->lut3d_texture);
255   }
256
257   if (shader->lut3d) {
258     MEM_freeN(shader->lut3d);
259   }
260
261   if (shader->program) {
262     glDeleteProgram(shader->program);
263   }
264
265   if (shader->shader_interface) {
266     GPU_shaderinterface_discard(shader->shader_interface);
267   }
268
269   if (shader->ocio_shader) {
270     glDeleteShader(shader->ocio_shader);
271   }
272
273   using std::string;
274   shader->lut3dCacheID.~string();
275   shader->shaderCacheID.~string();
276
277   MEM_freeN(shader);
278 }
279
280 /* Detect if we can support GLSL drawing */
281 bool OCIOImpl::supportGLSLDraw()
282 {
283   /* uses GL_RGB16F_ARB */
284   return GLEW_VERSION_3_0 || GLEW_ARB_texture_float;
285 }
286
287 /**
288  * Setup OpenGL contexts for a transform defined by processor using GLSL
289  * All LUT allocating baking and shader compilation happens here.
290  *
291  * Once this function is called, callee could start drawing images
292  * using regular 2D texture.
293  *
294  * When all drawing is finished, finishGLSLDraw shall be called to
295  * restore OpenGL context to it's pre-GLSL draw state.
296  */
297 bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r,
298                              OCIO_ConstProcessorRcPtr *processor,
299                              OCIO_CurveMappingSettings *curve_mapping_settings,
300                              float dither,
301                              bool use_predivide)
302 {
303   ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *)processor;
304   bool use_curve_mapping = curve_mapping_settings != NULL;
305   bool use_dither = dither > std::numeric_limits<float>::epsilon();
306
307   /* Create state if needed. */
308   OCIO_GLSLDrawState *state;
309   if (!*state_r)
310     *state_r = allocateOpenGLState();
311   state = *state_r;
312
313   glGetIntegerv(GL_TEXTURE_BINDING_2D, &state->last_texture);
314   glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit);
315
316   /* Compute cache IDs. */
317   GpuShaderDesc shaderDesc;
318   shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_3);
319   shaderDesc.setFunctionName("OCIODisplay");
320   shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
321
322   std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc);
323   std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
324
325   /* Find matching cached shader. */
326   OCIO_GLSLShader *shader = NULL;
327   for (int i = 0; i < SHADER_CACHE_SIZE; i++) {
328     OCIO_GLSLShader *cached_shader = state->shader_cache[i];
329     if (cached_shader == NULL) {
330       continue;
331     }
332
333     if (cached_shader->lut3dCacheID == lut3dCacheID &&
334         cached_shader->shaderCacheID == shaderCacheID &&
335         cached_shader->use_predivide == use_predivide &&
336         cached_shader->use_curve_mapping == use_curve_mapping &&
337         cached_shader->use_dither == use_dither) {
338       /* LRU cache, so move to front. */
339       for (int j = i; j > 0; j--) {
340         state->shader_cache[j] = state->shader_cache[j - 1];
341       }
342       state->shader_cache[0] = cached_shader;
343
344       shader = cached_shader;
345       break;
346     }
347   }
348
349   if (shader == NULL) {
350     /* LRU cache, shift other items back so we can insert at the front. */
351     OCIO_GLSLShader *last_shader = state->shader_cache[SHADER_CACHE_SIZE - 1];
352     if (last_shader) {
353       freeGLSLShader(last_shader);
354     }
355     for (int j = SHADER_CACHE_SIZE - 1; j > 0; j--) {
356       state->shader_cache[j] = state->shader_cache[j - 1];
357     }
358
359     /* Allocate memory for shader. */
360     shader = (OCIO_GLSLShader *)MEM_callocN(sizeof(OCIO_GLSLShader), "OCIO GLSL Shader");
361     state->shader_cache[0] = shader;
362
363     new (&shader->lut3dCacheID) std::string();
364     new (&shader->shaderCacheID) std::string();
365
366     shader->lut3dCacheID = lut3dCacheID;
367     shader->shaderCacheID = shaderCacheID;
368     shader->use_curve_mapping = use_curve_mapping;
369     shader->use_dither = use_dither;
370     shader->use_predivide = use_predivide;
371
372     bool valid = true;
373
374     /* Compute 3D LUT. */
375     if (valid && ensureLUT3DAllocated(shader)) {
376       ocio_processor->getGpuLut3D(shader->lut3d, shaderDesc);
377
378       glActiveTexture(GL_TEXTURE1);
379       glBindTexture(GL_TEXTURE_3D, shader->lut3d_texture);
380       glTexSubImage3D(GL_TEXTURE_3D,
381                       0,
382                       0,
383                       0,
384                       0,
385                       LUT3D_EDGE_SIZE,
386                       LUT3D_EDGE_SIZE,
387                       LUT3D_EDGE_SIZE,
388                       GL_RGB,
389                       GL_FLOAT,
390                       shader->lut3d);
391     }
392     else {
393       valid = false;
394     }
395
396     /* Allocate curve mapping texture. */
397     if (valid && use_curve_mapping) {
398       if (!ensureCurveMappingAllocated(shader, curve_mapping_settings)) {
399         valid = false;
400       }
401     }
402
403     if (valid) {
404       /* Vertex shader */
405       std::ostringstream osv;
406
407       osv << "#version 330\n";
408       osv << datatoc_gpu_shader_display_transform_vertex_glsl;
409
410       shader->vert_shader = compileShaderText(GL_VERTEX_SHADER, osv.str().c_str());
411
412       /* Fragment shader */
413       std::ostringstream os;
414
415       os << "#version 330\n";
416
417       /* Work around OpenColorIO not supporting latest GLSL yet. */
418       os << "#define texture2D texture\n";
419       os << "#define texture3D texture\n";
420
421       if (use_predivide) {
422         os << "#define USE_PREDIVIDE\n";
423       }
424
425       if (use_dither) {
426         os << "#define USE_DITHER\n";
427       }
428
429       if (use_curve_mapping) {
430         os << "#define USE_CURVE_MAPPING\n";
431       }
432
433       os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
434       os << datatoc_gpu_shader_display_transform_glsl;
435
436       shader->ocio_shader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
437
438       /* Program */
439       if (shader->ocio_shader && shader->vert_shader) {
440         shader->program = linkShaders(shader->ocio_shader, shader->vert_shader);
441       }
442
443       if (shader->program) {
444         if (shader->shader_interface) {
445           GPU_shaderinterface_discard(shader->shader_interface);
446         }
447         shader->shader_interface = GPU_shaderinterface_create(shader->program);
448       }
449     }
450   }
451
452   /* Update curve mapping texture. */
453   if (use_curve_mapping && shader->curve_mapping_texture_allocated) {
454     if (shader->curve_mapping_cache_id != curve_mapping_settings->cache_id) {
455       glActiveTexture(GL_TEXTURE2);
456       glBindTexture(GL_TEXTURE_1D, shader->curve_mapping_texture);
457       glTexSubImage1D(GL_TEXTURE_1D,
458                       0,
459                       0,
460                       curve_mapping_settings->lut_size,
461                       GL_RGBA,
462                       GL_FLOAT,
463                       curve_mapping_settings->lut);
464     }
465   }
466
467   /* Bind Shader. */
468   if (shader->program) {
469     glActiveTexture(GL_TEXTURE1);
470     glBindTexture(GL_TEXTURE_3D, shader->lut3d_texture);
471
472     if (use_curve_mapping) {
473       glActiveTexture(GL_TEXTURE2);
474       glBindTexture(GL_TEXTURE_1D, shader->curve_mapping_texture);
475     }
476
477     glActiveTexture(GL_TEXTURE0);
478
479     /* IMM needs vertex format even if we don't draw with it.
480      *
481      * NOTE: The only reason why it's here is because of Cycles viewport.
482      * All other areas are managing their own vertex formats.
483      * Doing it here is probably harmless, but kind of stupid.
484      *
485      * TODO(sergey): Look into some nicer solution.
486      */
487     GPUVertFormat *format = immVertexFormat();
488     GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
489     GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
490     immBindProgram(shader->program, shader->shader_interface);
491
492     immUniform1i("image_texture", 0);
493     immUniform1i("lut3d_texture", 1);
494
495     if (use_dither) {
496       immUniform1f("dither", dither);
497     }
498
499     if (use_curve_mapping) {
500       immUniform1i("curve_mapping_texture", 2);
501       immUniform1i("curve_mapping_lut_size", curve_mapping_settings->lut_size);
502       immUniform4iv("use_curve_mapping_extend_extrapolate",
503                     curve_mapping_settings->use_extend_extrapolate);
504       immUniform4fv("curve_mapping_mintable", curve_mapping_settings->mintable);
505       immUniform4fv("curve_mapping_range", curve_mapping_settings->range);
506       immUniform4fv("curve_mapping_ext_in_x", curve_mapping_settings->ext_in_x);
507       immUniform4fv("curve_mapping_ext_in_y", curve_mapping_settings->ext_in_y);
508       immUniform4fv("curve_mapping_ext_out_x", curve_mapping_settings->ext_out_x);
509       immUniform4fv("curve_mapping_ext_out_y", curve_mapping_settings->ext_out_y);
510       immUniform4fv("curve_mapping_first_x", curve_mapping_settings->first_x);
511       immUniform4fv("curve_mapping_first_y", curve_mapping_settings->first_y);
512       immUniform4fv("curve_mapping_last_x", curve_mapping_settings->last_x);
513       immUniform4fv("curve_mapping_last_y", curve_mapping_settings->last_y);
514       immUniform3fv("curve_mapping_black", curve_mapping_settings->black);
515       immUniform3fv("curve_mapping_bwmul", curve_mapping_settings->bwmul);
516     }
517
518     return true;
519   }
520   else {
521     glActiveTexture(state->last_texture_unit);
522     glBindTexture(GL_TEXTURE_2D, state->last_texture);
523
524     return false;
525   }
526 }
527
528 void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
529 {
530   glActiveTexture(state->last_texture_unit);
531   glBindTexture(GL_TEXTURE_2D, state->last_texture);
532   immUnbindProgram();
533 }
534
535 void OCIOImpl::freeGLState(OCIO_GLSLDrawState *state)
536 {
537   for (int i = 0; i < SHADER_CACHE_SIZE; i++) {
538     if (state->shader_cache[i]) {
539       freeGLSLShader(state->shader_cache[i]);
540     }
541   }
542
543   MEM_freeN(state);
544 }