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 #ifdef _MSC_VER
38 #  pragma warning(push)
39 #  pragma warning(disable : 4251 4275)
40 #endif
41 #include <OpenColorIO/OpenColorIO.h>
42 #ifdef _MSC_VER
43 #  pragma warning(pop)
44 #endif
45 
46 #include "GPU_immediate.h"
47 #include "GPU_shader.h"
48 #include "GPU_uniform_buffer.h"
49 
50 using namespace OCIO_NAMESPACE;
51 
52 #include "MEM_guardedalloc.h"
53 
54 #include "ocio_impl.h"
55 
56 static const int LUT3D_EDGE_SIZE = 64;
57 static const int LUT3D_TEXTURE_SIZE = sizeof(float) * 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE *
58                                       LUT3D_EDGE_SIZE;
59 static const int SHADER_CACHE_SIZE = 4;
60 
61 #define UBO_BIND_LOC 0
62 
63 extern "C" char datatoc_gpu_shader_display_transform_glsl[];
64 extern "C" char datatoc_gpu_shader_display_transform_vertex_glsl[];
65 
66 /* **** OpenGL drawing routines using GLSL for color space transform ***** */
67 
68 /* Curve mapping parameters
69  *
70  * See documentation for OCIO_CurveMappingSettings to get fields descriptions.
71  * (this ones pretty much copies stuff from C structure.)
72  */
73 struct OCIO_GLSLCurveMappingParameters {
74   float curve_mapping_mintable[4];
75   float curve_mapping_range[4];
76   float curve_mapping_ext_in_x[4];
77   float curve_mapping_ext_in_y[4];
78   float curve_mapping_ext_out_x[4];
79   float curve_mapping_ext_out_y[4];
80   float curve_mapping_first_x[4];
81   float curve_mapping_first_y[4];
82   float curve_mapping_last_x[4];
83   float curve_mapping_last_y[4];
84   float curve_mapping_black[4];
85   float curve_mapping_bwmul[4];
86   int curve_mapping_lut_size;
87   int curve_mapping_use_extend_extrapolate;
88   int _pad[2];
89   /** WARNING: Needs to be 16byte aligned. Used as UBO data. */
90 };
91 
92 struct OCIO_GLSLShader {
93   /** Cache IDs */
94   std::string cacheId;
95 
96   struct GPUShader *shader;
97   /** Uniform locations. */
98   int dither_loc;
99   int overlay_loc;
100   int predivide_loc;
101   int curve_mapping_loc;
102   int ubo_bind;
103   /** Error checking. */
104   bool valid;
105 };
106 
107 struct OCIO_GLSLLut3d {
108   /** Cache IDs */
109   std::string cacheId;
110   /** OpenGL Texture handles. NULL if not allocated. */
111   GPUTexture *texture;
112   GPUTexture *texture_display;
113   GPUTexture *texture_dummy;
114   /** Error checking. */
115   bool valid;
116 };
117 
118 struct OCIO_GLSLCurveMappping {
119   /** Cache IDs */
120   size_t cacheId;
121   /** GPU Uniform Buffer handle. 0 if not allocated. */
122   GPUUniformBuf *buffer;
123   /** OpenGL Texture handles. 0 if not allocated. */
124   GPUTexture *texture;
125   /** Error checking. */
126   bool valid;
127 };
128 
129 struct OCIO_GLSLCacheHandle {
130   size_t cache_id;
131   void *data;
132 };
133 
134 struct OCIO_GLSLDrawState {
135   /* Shader Cache */
136   OCIO_GLSLCacheHandle shader_cache[SHADER_CACHE_SIZE];
137   OCIO_GLSLCacheHandle lut3d_cache[SHADER_CACHE_SIZE];
138   OCIO_GLSLCacheHandle curvemap_cache[SHADER_CACHE_SIZE];
139 };
140 
allocateOpenGLState(void)141 static OCIO_GLSLDrawState *allocateOpenGLState(void)
142 {
143   return (OCIO_GLSLDrawState *)MEM_callocN(sizeof(OCIO_GLSLDrawState), "OCIO OpenGL State struct");
144 }
145 
146 /* -------------------------------------------------------------------- */
147 /** \name Shader
148  * \{ */
149 
updateGLSLShader(OCIO_GLSLShader * shader,ConstProcessorRcPtr * processor_scene_to_ui,ConstProcessorRcPtr * processpr_ui_to_display,GpuShaderDesc * shader_desc,const std::string & cache_id)150 static void updateGLSLShader(OCIO_GLSLShader *shader,
151                              ConstProcessorRcPtr *processor_scene_to_ui,
152                              ConstProcessorRcPtr *processpr_ui_to_display,
153                              GpuShaderDesc *shader_desc,
154                              const std::string &cache_id)
155 {
156   if (shader->cacheId == cache_id) {
157     return;
158   }
159 
160   /* Delete any previous shader. */
161   if (shader->shader) {
162     GPU_shader_free(shader->shader);
163   }
164 
165   std::ostringstream os;
166   {
167     /* Fragment shader */
168 
169     /* Work around OpenColorIO not supporting latest GLSL yet. */
170     os << "#define texture2D texture\n";
171     os << "#define texture3D texture\n";
172 
173     shader_desc->setFunctionName("OCIO_to_display_linear_with_look");
174     os << (*processor_scene_to_ui)->getGpuShaderText(*shader_desc) << "\n";
175 
176     shader_desc->setFunctionName("OCIO_to_display_encoded");
177     os << (*processpr_ui_to_display)->getGpuShaderText(*shader_desc) << "\n";
178 
179     os << datatoc_gpu_shader_display_transform_glsl;
180   }
181 
182   shader->shader = GPU_shader_create(datatoc_gpu_shader_display_transform_vertex_glsl,
183                                      os.str().c_str(),
184                                      NULL,
185                                      NULL,
186                                      NULL,
187                                      "OCIOShader");
188 
189   if (shader->shader) {
190     shader->dither_loc = GPU_shader_get_uniform(shader->shader, "dither");
191     shader->overlay_loc = GPU_shader_get_uniform(shader->shader, "overlay");
192     shader->predivide_loc = GPU_shader_get_uniform(shader->shader, "predivide");
193     shader->curve_mapping_loc = GPU_shader_get_uniform(shader->shader, "curve_mapping");
194     shader->ubo_bind = GPU_shader_get_uniform_block_binding(shader->shader,
195                                                             "OCIO_GLSLCurveMappingParameters");
196 
197     GPU_shader_bind(shader->shader);
198 
199     /* Set texture bind point uniform once. This is saved by the shader. */
200     GPUShader *sh = shader->shader;
201     GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "image_texture"), 0);
202     GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "overlay_texture"), 1);
203     GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "lut3d_texture"), 2);
204     GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "lut3d_display_texture"), 3);
205     GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "curve_mapping_texture"), 4);
206   }
207 
208   shader->cacheId = cache_id;
209   shader->valid = (shader->shader != NULL);
210 }
211 
ensureGLSLShader(OCIO_GLSLShader ** shader_ptr,ConstProcessorRcPtr * processor_scene_to_ui,ConstProcessorRcPtr * processpr_ui_to_display,GpuShaderDesc * shader_desc,const std::string & cache_id)212 static void ensureGLSLShader(OCIO_GLSLShader **shader_ptr,
213                              ConstProcessorRcPtr *processor_scene_to_ui,
214                              ConstProcessorRcPtr *processpr_ui_to_display,
215                              GpuShaderDesc *shader_desc,
216                              const std::string &cache_id)
217 {
218   if (*shader_ptr != NULL) {
219     return;
220   }
221 
222   OCIO_GLSLShader *shader = OBJECT_GUARDED_NEW(OCIO_GLSLShader);
223 
224   updateGLSLShader(shader, processor_scene_to_ui, processpr_ui_to_display, shader_desc, cache_id);
225 
226   *shader_ptr = shader;
227 }
228 
freeGLSLShader(OCIO_GLSLShader * shader)229 static void freeGLSLShader(OCIO_GLSLShader *shader)
230 {
231   if (shader->shader) {
232     GPU_shader_free(shader->shader);
233   }
234 
235   OBJECT_GUARDED_DELETE(shader, OCIO_GLSLShader);
236 }
237 
238 /** \} */
239 
240 /* -------------------------------------------------------------------- */
241 /** \name Lut3D
242  * \{ */
243 
updateGLSLLut3d(OCIO_GLSLLut3d * lut3d,ConstProcessorRcPtr * processor_scene_to_ui,ConstProcessorRcPtr * processpr_ui_to_display,GpuShaderDesc * shader_desc,const std::string & cache_id)244 static void updateGLSLLut3d(OCIO_GLSLLut3d *lut3d,
245                             ConstProcessorRcPtr *processor_scene_to_ui,
246                             ConstProcessorRcPtr *processpr_ui_to_display,
247                             GpuShaderDesc *shader_desc,
248                             const std::string &cache_id)
249 {
250   if (lut3d->cacheId == cache_id)
251     return;
252 
253   float *lut_data = (float *)MEM_mallocN(LUT3D_TEXTURE_SIZE, __func__);
254 
255   ConstProcessorRcPtr *ocio_processors[2] = {processor_scene_to_ui, processpr_ui_to_display};
256 
257   for (int i = 0; i < 2; i++) {
258     ConstProcessorRcPtr *processor = ocio_processors[i];
259     GPUTexture *texture = (&lut3d->texture)[i];
260 
261     (*processor)->getGpuLut3D(lut_data, *shader_desc);
262 
263     int offset[3] = {0, 0, 0};
264     int extent[3] = {LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE};
265     GPU_texture_update_sub(texture, GPU_DATA_FLOAT, lut_data, UNPACK3(offset), UNPACK3(extent));
266   }
267 
268   MEM_freeN(lut_data);
269 
270   lut3d->cacheId = cache_id;
271 }
272 
ensureGLSLLut3d(OCIO_GLSLLut3d ** lut3d_ptr,ConstProcessorRcPtr * processor_scene_to_ui,ConstProcessorRcPtr * processpr_ui_to_display,GpuShaderDesc * shaderDesc,const std::string & cache_id)273 static void ensureGLSLLut3d(OCIO_GLSLLut3d **lut3d_ptr,
274                             ConstProcessorRcPtr *processor_scene_to_ui,
275                             ConstProcessorRcPtr *processpr_ui_to_display,
276                             GpuShaderDesc *shaderDesc,
277                             const std::string &cache_id)
278 {
279   if (*lut3d_ptr != NULL) {
280     return;
281   }
282 
283   OCIO_GLSLLut3d *lut3d = OBJECT_GUARDED_NEW(OCIO_GLSLLut3d);
284 
285   int extent[3] = {LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE};
286 
287   lut3d->texture = GPU_texture_create_3d(
288       "OCIOLut", UNPACK3(extent), 1, GPU_RGB16F, GPU_DATA_FLOAT, NULL);
289   GPU_texture_filter_mode(lut3d->texture, true);
290   GPU_texture_wrap_mode(lut3d->texture, false, true);
291 
292   lut3d->texture_display = GPU_texture_create_3d(
293       "OCIOLutDisplay", UNPACK3(extent), 1, GPU_RGB16F, GPU_DATA_FLOAT, NULL);
294   GPU_texture_filter_mode(lut3d->texture_display, true);
295   GPU_texture_wrap_mode(lut3d->texture_display, false, true);
296 
297   lut3d->texture_dummy = GPU_texture_create_error(2, false);
298 
299   updateGLSLLut3d(lut3d, processor_scene_to_ui, processpr_ui_to_display, shaderDesc, cache_id);
300 
301   lut3d->valid = (lut3d->texture && lut3d->texture_display);
302 
303   *lut3d_ptr = lut3d;
304 }
305 
freeGLSLLut3d(OCIO_GLSLLut3d * lut3d)306 static void freeGLSLLut3d(OCIO_GLSLLut3d *lut3d)
307 {
308   GPU_texture_free(lut3d->texture);
309   GPU_texture_free(lut3d->texture_display);
310   GPU_texture_free(lut3d->texture_dummy);
311 
312   OBJECT_GUARDED_DELETE(lut3d, OCIO_GLSLLut3d);
313 }
314 
315 /** \} */
316 
317 /* -------------------------------------------------------------------- */
318 /** \name Curve Mapping
319  * \{ */
allocateCurveMappingTexture(OCIO_GLSLCurveMappping * curvemap,OCIO_CurveMappingSettings * curve_mapping_settings)320 static void allocateCurveMappingTexture(OCIO_GLSLCurveMappping *curvemap,
321                                         OCIO_CurveMappingSettings *curve_mapping_settings)
322 {
323   int lut_size = curve_mapping_settings ? curve_mapping_settings->lut_size : 1;
324   /* Do not initialize. Only if used. */
325   curvemap->texture = GPU_texture_create_1d("OCIOCurveMap", lut_size, 1, GPU_RGBA16F, NULL);
326   GPU_texture_filter_mode(curvemap->texture, false);
327   GPU_texture_wrap_mode(curvemap->texture, false, true);
328 }
329 
330 /* curve_mapping_settings can be null. In this case we alloc a dummy curvemap. */
ensureGLSLCurveMapping(OCIO_GLSLCurveMappping ** curvemap_ptr,OCIO_CurveMappingSettings * curve_mapping_settings)331 static void ensureGLSLCurveMapping(OCIO_GLSLCurveMappping **curvemap_ptr,
332                                    OCIO_CurveMappingSettings *curve_mapping_settings)
333 {
334   if (*curvemap_ptr != NULL) {
335     return;
336   }
337 
338   OCIO_GLSLCurveMappping *curvemap = OBJECT_GUARDED_NEW(OCIO_GLSLCurveMappping);
339 
340   /* Texture. */
341   allocateCurveMappingTexture(curvemap, curve_mapping_settings);
342 
343   /* Uniform buffer object. */
344   curvemap->buffer = GPU_uniformbuf_create(sizeof(OCIO_GLSLCurveMappingParameters));
345 
346   curvemap->valid = (curvemap->texture != 0);
347   curvemap->cacheId = 0;
348 
349   *curvemap_ptr = curvemap;
350 }
351 
freeGLSLCurveMapping(OCIO_GLSLCurveMappping * curvemap)352 static void freeGLSLCurveMapping(OCIO_GLSLCurveMappping *curvemap)
353 {
354   GPU_texture_free(curvemap->texture);
355   GPU_uniformbuf_free(curvemap->buffer);
356 
357   OBJECT_GUARDED_DELETE(curvemap, OCIO_GLSLCurveMappping);
358 }
359 
updateGLSLCurveMapping(OCIO_GLSLCurveMappping * curvemap,OCIO_CurveMappingSettings * curve_mapping_settings,size_t cacheId)360 static void updateGLSLCurveMapping(OCIO_GLSLCurveMappping *curvemap,
361                                    OCIO_CurveMappingSettings *curve_mapping_settings,
362                                    size_t cacheId)
363 {
364   /* No need to continue if curvemapping is not used. Just use whatever is in this cache. */
365   if (curve_mapping_settings == NULL)
366     return;
367 
368   if (curvemap->cacheId == cacheId)
369     return;
370 
371   if (curvemap->cacheId == 0) {
372     /* This cache was previously used as dummy. Recreate the texture. */
373     GPU_texture_free(curvemap->texture);
374     allocateCurveMappingTexture(curvemap, curve_mapping_settings);
375   }
376 
377   /* Update texture. */
378   int offset[3] = {0, 0, 0};
379   int extent[3] = {curve_mapping_settings->lut_size, 0, 0};
380   const float *pixels = curve_mapping_settings->lut;
381   GPU_texture_update_sub(
382       curvemap->texture, GPU_DATA_FLOAT, pixels, UNPACK3(offset), UNPACK3(extent));
383 
384   /* Update uniforms. */
385   OCIO_GLSLCurveMappingParameters data;
386   for (int i = 0; i < 4; i++) {
387     data.curve_mapping_range[i] = curve_mapping_settings->range[i];
388     data.curve_mapping_mintable[i] = curve_mapping_settings->mintable[i];
389     data.curve_mapping_ext_in_x[i] = curve_mapping_settings->ext_in_x[i];
390     data.curve_mapping_ext_in_y[i] = curve_mapping_settings->ext_in_y[i];
391     data.curve_mapping_ext_out_x[i] = curve_mapping_settings->ext_out_x[i];
392     data.curve_mapping_ext_out_y[i] = curve_mapping_settings->ext_out_y[i];
393     data.curve_mapping_first_x[i] = curve_mapping_settings->first_x[i];
394     data.curve_mapping_first_y[i] = curve_mapping_settings->first_y[i];
395     data.curve_mapping_last_x[i] = curve_mapping_settings->last_x[i];
396     data.curve_mapping_last_y[i] = curve_mapping_settings->last_y[i];
397   }
398   for (int i = 0; i < 3; i++) {
399     data.curve_mapping_black[i] = curve_mapping_settings->black[i];
400     data.curve_mapping_bwmul[i] = curve_mapping_settings->bwmul[i];
401   }
402   data.curve_mapping_lut_size = curve_mapping_settings->lut_size;
403   data.curve_mapping_use_extend_extrapolate = curve_mapping_settings->use_extend_extrapolate;
404 
405   GPU_uniformbuf_update(curvemap->buffer, &data);
406 
407   curvemap->cacheId = cacheId;
408 }
409 
410 /** \} */
411 
412 /* -------------------------------------------------------------------- */
413 /** \name LRU cache
414  * \{ */
415 
hash_string(const char * str)416 static size_t hash_string(const char *str)
417 {
418   size_t i = 0, c;
419   while ((c = *str++)) {
420     i = i * 37 + c;
421   }
422   return i;
423 }
424 
cacheSearch(OCIO_GLSLCacheHandle cache[SHADER_CACHE_SIZE],size_t cache_id)425 static OCIO_GLSLCacheHandle *cacheSearch(OCIO_GLSLCacheHandle cache[SHADER_CACHE_SIZE],
426                                          size_t cache_id)
427 {
428   OCIO_GLSLCacheHandle *cached_item = &cache[0];
429   for (int i = 0; i < SHADER_CACHE_SIZE; i++, cached_item++) {
430     if (cached_item->data == NULL) {
431       continue;
432     }
433     else if (cached_item->cache_id == cache_id) {
434       /* LRU cache, so move to front. */
435       OCIO_GLSLCacheHandle found_item = *cached_item;
436       for (int j = i; j > 0; j--) {
437         cache[j] = cache[j - 1];
438       }
439       cache[0] = found_item;
440       return &cache[0];
441     }
442   }
443   /* LRU cache, shift other items back so we can insert at the front. */
444   OCIO_GLSLCacheHandle last_item = cache[SHADER_CACHE_SIZE - 1];
445   for (int j = SHADER_CACHE_SIZE - 1; j > 0; j--) {
446     cache[j] = cache[j - 1];
447   }
448   /* Copy last to front and let the caller initialize it. */
449   cache[0] = last_item;
450   return &cache[0];
451 }
452 
453 /** \} */
454 
455 /* -------------------------------------------------------------------- */
456 /** \name OCIO GLSL Implementation
457  * \{ */
458 
459 /* Detect if we can support GLSL drawing */
supportGLSLDraw()460 bool OCIOImpl::supportGLSLDraw()
461 {
462   /* Minimum supported version 3.3 does meet all requirements. */
463   return true;
464 }
465 
466 /**
467  * Setup OpenGL contexts for a transform defined by processor using GLSL
468  * All LUT allocating baking and shader compilation happens here.
469  *
470  * Once this function is called, callee could start drawing images
471  * using regular 2D texture.
472  *
473  * When all drawing is finished, finishGLSLDraw shall be called to
474  * restore OpenGL context to its pre-GLSL draw state.
475  */
setupGLSLDraw(OCIO_GLSLDrawState ** state_r,OCIO_ConstProcessorRcPtr * ocio_processor_scene_to_ui,OCIO_ConstProcessorRcPtr * ocio_processor_ui_to_display,OCIO_CurveMappingSettings * curve_mapping_settings,float dither,bool use_predivide,bool use_overlay)476 bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r,
477                              OCIO_ConstProcessorRcPtr *ocio_processor_scene_to_ui,
478                              OCIO_ConstProcessorRcPtr *ocio_processor_ui_to_display,
479                              OCIO_CurveMappingSettings *curve_mapping_settings,
480                              float dither,
481                              bool use_predivide,
482                              bool use_overlay)
483 {
484   ConstProcessorRcPtr processor_scene_to_ui = *(ConstProcessorRcPtr *)ocio_processor_scene_to_ui;
485   ConstProcessorRcPtr processpr_ui_to_display = *(
486       ConstProcessorRcPtr *)ocio_processor_ui_to_display;
487   bool use_curve_mapping = curve_mapping_settings != NULL;
488 
489   if (!processor_scene_to_ui || !processor_scene_to_ui) {
490     return false;
491   }
492 
493   /* Create state if needed. */
494   OCIO_GLSLDrawState *state;
495   if (!*state_r)
496     *state_r = allocateOpenGLState();
497   state = *state_r;
498 
499   /* Compute cache IDs. */
500   GpuShaderDesc shaderDesc;
501   shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_3);
502   shaderDesc.setFunctionName("OCIODisplay");
503   shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
504 
505   const char *shader_cache_str = processor_scene_to_ui->getGpuShaderTextCacheID(shaderDesc);
506   const char *lut3d_cache_str = processor_scene_to_ui->getGpuLut3DCacheID(shaderDesc);
507   /* Used for comparison. */
508   std::string shaderCacheID = shader_cache_str;
509   std::string lut3dCacheID = lut3d_cache_str;
510 
511   size_t shader_cache_id = hash_string(shader_cache_str);
512   size_t lut3d_cache_id = hash_string(lut3d_cache_str);
513   size_t curvemap_cache_id = curve_mapping_settings ? curve_mapping_settings->cache_id : 0;
514 
515   OCIO_GLSLCacheHandle *shader_handle = cacheSearch(state->shader_cache, shader_cache_id);
516   OCIO_GLSLCacheHandle *lut3d_handle = cacheSearch(state->lut3d_cache, lut3d_cache_id);
517   /* We cannot keep more than one cache for curvemap because their cache id is a pointer.
518    * The pointer cannot be the same for one update but can be the same after a second update. */
519   OCIO_GLSLCacheHandle *curvemap_handle = &state->curvemap_cache[0];
520 
521   OCIO_GLSLShader **shader_ptr = (OCIO_GLSLShader **)&shader_handle->data;
522   OCIO_GLSLLut3d **lut3d_ptr = (OCIO_GLSLLut3d **)&lut3d_handle->data;
523   OCIO_GLSLCurveMappping **curvemap_ptr = (OCIO_GLSLCurveMappping **)&curvemap_handle->data;
524 
525   ensureGLSLShader(
526       shader_ptr, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, shaderCacheID);
527   ensureGLSLLut3d(
528       lut3d_ptr, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, shaderCacheID);
529   ensureGLSLCurveMapping(curvemap_ptr, curve_mapping_settings);
530 
531   OCIO_GLSLShader *shader = (OCIO_GLSLShader *)shader_handle->data;
532   OCIO_GLSLLut3d *shader_lut = (OCIO_GLSLLut3d *)lut3d_handle->data;
533   OCIO_GLSLCurveMappping *shader_curvemap = (OCIO_GLSLCurveMappping *)curvemap_handle->data;
534 
535   updateGLSLShader(
536       shader, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, shaderCacheID);
537   updateGLSLLut3d(
538       shader_lut, &processor_scene_to_ui, &processpr_ui_to_display, &shaderDesc, lut3dCacheID);
539   updateGLSLCurveMapping(shader_curvemap, curve_mapping_settings, curvemap_cache_id);
540 
541   /* Update handles cache keys. */
542   shader_handle->cache_id = shader_cache_id;
543   lut3d_handle->cache_id = lut3d_cache_id;
544   curvemap_handle->cache_id = curvemap_cache_id;
545 
546   if (shader->valid && shader_lut->valid && shader_curvemap->valid) {
547     /* Bind textures to sampler units. Texture 0 is set by caller.
548      * Uniforms have already been set for texture bind points.*/
549 
550     if (!use_overlay) {
551       /* Avoid missing binds. */
552       GPU_texture_bind(shader_lut->texture_dummy, 1);
553     }
554     GPU_texture_bind(shader_lut->texture, 2);
555     GPU_texture_bind(shader_lut->texture_display, 3);
556     GPU_texture_bind(shader_curvemap->texture, 4);
557 
558     /* Bind UBO. */
559     GPU_uniformbuf_bind(shader_curvemap->buffer, shader->ubo_bind);
560 
561     /* TODO(fclem): remove remains of IMM. */
562     immBindShader(shader->shader);
563 
564     /* Bind Shader and set uniforms. */
565     // GPU_shader_bind(shader->shader);
566     GPU_shader_uniform_float(shader->shader, shader->dither_loc, dither);
567     GPU_shader_uniform_int(shader->shader, shader->overlay_loc, use_overlay);
568     GPU_shader_uniform_int(shader->shader, shader->predivide_loc, use_predivide);
569     GPU_shader_uniform_int(shader->shader, shader->curve_mapping_loc, use_curve_mapping);
570 
571     return true;
572   }
573 
574   return false;
575 }
576 
finishGLSLDraw(OCIO_GLSLDrawState *)577 void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState * /*state*/)
578 {
579   immUnbindProgram();
580 }
581 
freeGLState(OCIO_GLSLDrawState * state)582 void OCIOImpl::freeGLState(OCIO_GLSLDrawState *state)
583 {
584   for (int i = 0; i < SHADER_CACHE_SIZE; i++) {
585     if (state->shader_cache[i].data) {
586       freeGLSLShader((OCIO_GLSLShader *)state->shader_cache[i].data);
587     }
588     if (state->lut3d_cache[i].data) {
589       freeGLSLLut3d((OCIO_GLSLLut3d *)state->lut3d_cache[i].data);
590     }
591     if (state->curvemap_cache[i].data) {
592       freeGLSLCurveMapping((OCIO_GLSLCurveMappping *)state->curvemap_cache[i].data);
593     }
594   }
595 
596   MEM_freeN(state);
597 }
598 
599 /** \} */
600