Fix T91461: Pose Library name filter not working
[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 <list>
35 #include <sstream>
36 #include <string.h>
37 #include <vector>
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 #include "GPU_immediate.h"
49 #include "GPU_shader.h"
50 #include "GPU_uniform_buffer.h"
51
52 using namespace OCIO_NAMESPACE;
53
54 #include "MEM_guardedalloc.h"
55
56 #include "ocio_impl.h"
57
58 extern "C" char datatoc_gpu_shader_display_transform_glsl[];
59 extern "C" char datatoc_gpu_shader_display_transform_vertex_glsl[];
60
61 /* **** OpenGL drawing routines using GLSL for color space transform ***** */
62
63 enum OCIO_GPUTextureSlots {
64   TEXTURE_SLOT_IMAGE = 0,
65   TEXTURE_SLOT_OVERLAY = 1,
66   TEXTURE_SLOT_CURVE_MAPPING = 2,
67   TEXTURE_SLOT_LUTS_OFFSET = 3,
68 };
69
70 /* Curve mapping parameters
71  *
72  * See documentation for OCIO_CurveMappingSettings to get fields descriptions.
73  * (this ones pretty much copies stuff from C structure.)
74  */
75 struct OCIO_GPUCurveMappingParameters {
76   float curve_mapping_mintable[4];
77   float curve_mapping_range[4];
78   float curve_mapping_ext_in_x[4];
79   float curve_mapping_ext_in_y[4];
80   float curve_mapping_ext_out_x[4];
81   float curve_mapping_ext_out_y[4];
82   float curve_mapping_first_x[4];
83   float curve_mapping_first_y[4];
84   float curve_mapping_last_x[4];
85   float curve_mapping_last_y[4];
86   float curve_mapping_black[4];
87   float curve_mapping_bwmul[4];
88   int curve_mapping_lut_size;
89   int curve_mapping_use_extend_extrapolate;
90   int _pad[2];
91   /** WARNING: Needs to be 16byte aligned. Used as UBO data. */
92 };
93
94 struct OCIO_GPUShader {
95   /* GPU shader. */
96   struct GPUShader *shader = nullptr;
97
98   /** Uniform locations. */
99   int scale_loc = 0;
100   int exponent_loc = 0;
101   int dither_loc = 0;
102   int overlay_loc = 0;
103   int predivide_loc = 0;
104   int ubo_bind = 0;
105
106   /* Destructor. */
107   ~OCIO_GPUShader()
108   {
109     if (shader) {
110       GPU_shader_free(shader);
111     }
112   }
113 };
114
115 struct OCIO_GPULutTexture {
116   GPUTexture *texture = nullptr;
117   std::string sampler_name;
118 };
119
120 struct OCIO_GPUUniform {
121   GpuShaderDesc::UniformData data;
122   std::string name;
123 };
124
125 struct OCIO_GPUTextures {
126   /** LUT Textures */
127   std::vector<OCIO_GPULutTexture> luts;
128
129   /* Dummy in case of no overlay. */
130   GPUTexture *dummy = nullptr;
131
132   /* Uniforms */
133   std::vector<OCIO_GPUUniform> uniforms;
134
135   /* Destructor. */
136   ~OCIO_GPUTextures()
137   {
138     for (OCIO_GPULutTexture &lut : luts) {
139       GPU_texture_free(lut.texture);
140     }
141     if (dummy) {
142       GPU_texture_free(dummy);
143     }
144   }
145 };
146
147 struct OCIO_GPUCurveMappping {
148   /** GPU Uniform Buffer handle. 0 if not allocated. */
149   GPUUniformBuf *buffer = nullptr;
150   /** OpenGL Texture handles. 0 if not allocated. */
151   GPUTexture *texture = nullptr;
152   /* To detect when to update the uniforms and textures. */
153   size_t cache_id = 0;
154
155   /* Destructor. */
156   ~OCIO_GPUCurveMappping()
157   {
158     if (texture) {
159       GPU_texture_free(texture);
160     }
161     if (buffer) {
162       GPU_uniformbuf_free(buffer);
163     }
164   }
165 };
166
167 struct OCIO_GPUDisplayShader {
168   OCIO_GPUShader shader;
169   OCIO_GPUTextures textures;
170   OCIO_GPUCurveMappping curvemap;
171
172   /* Cache variables. */
173   std::string input;
174   std::string view;
175   std::string display;
176   std::string look;
177   bool use_curve_mapping = false;
178
179   /** Error checking. */
180   bool valid = false;
181 };
182
183 static const int SHADER_CACHE_MAX_SIZE = 4;
184 std::list<OCIO_GPUDisplayShader> SHADER_CACHE;
185
186 /* -------------------------------------------------------------------- */
187 /** \name Shader
188  * \{ */
189
190 static bool createGPUShader(OCIO_GPUShader &shader,
191                             OCIO_GPUTextures &textures,
192                             const GpuShaderDescRcPtr &shaderdesc_to_scene_linear,
193                             const GpuShaderDescRcPtr &shaderdesc_to_display,
194                             const bool use_curve_mapping)
195 {
196   std::ostringstream os;
197   {
198     /* Fragment shader */
199
200     /* Work around OpenColorIO not supporting latest GLSL yet. */
201     os << "#define texture2D texture\n";
202     os << "#define texture3D texture\n";
203
204     if (use_curve_mapping) {
205       os << "#define USE_CURVE_MAPPING\n";
206     }
207
208     os << shaderdesc_to_scene_linear->getShaderText() << "\n";
209     os << shaderdesc_to_display->getShaderText() << "\n";
210
211     os << datatoc_gpu_shader_display_transform_glsl;
212   }
213
214   shader.shader = GPU_shader_create(datatoc_gpu_shader_display_transform_vertex_glsl,
215                                     os.str().c_str(),
216                                     nullptr,
217                                     nullptr,
218                                     nullptr,
219                                     "OCIOShader");
220
221   if (shader.shader == nullptr) {
222     return false;
223   }
224
225   shader.scale_loc = GPU_shader_get_uniform(shader.shader, "scale");
226   shader.exponent_loc = GPU_shader_get_uniform(shader.shader, "exponent");
227   shader.dither_loc = GPU_shader_get_uniform(shader.shader, "dither");
228   shader.overlay_loc = GPU_shader_get_uniform(shader.shader, "overlay");
229   shader.predivide_loc = GPU_shader_get_uniform(shader.shader, "predivide");
230   shader.ubo_bind = GPU_shader_get_uniform_block_binding(shader.shader,
231                                                          "OCIO_GPUCurveMappingParameters");
232
233   GPU_shader_bind(shader.shader);
234
235   /* Set texture bind point uniform once. This is saved by the shader. */
236   GPUShader *sh = shader.shader;
237   GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "image_texture"), TEXTURE_SLOT_IMAGE);
238   GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "overlay_texture"), TEXTURE_SLOT_OVERLAY);
239
240   if (use_curve_mapping) {
241     GPU_shader_uniform_int(
242         sh, GPU_shader_get_uniform(sh, "curve_mapping_texture"), TEXTURE_SLOT_CURVE_MAPPING);
243   }
244
245   /* Set LUT textures. */
246   for (int i = 0; i < textures.luts.size(); i++) {
247     GPU_shader_uniform_int(sh,
248                            GPU_shader_get_uniform(sh, textures.luts[i].sampler_name.c_str()),
249                            TEXTURE_SLOT_LUTS_OFFSET + i);
250   }
251
252   /* Set uniforms. */
253   for (OCIO_GPUUniform &uniform : textures.uniforms) {
254     const GpuShaderDesc::UniformData &data = uniform.data;
255     const char *name = uniform.name.c_str();
256
257     if (data.m_getDouble) {
258       GPU_shader_uniform_1f(sh, name, (float)data.m_getDouble());
259     }
260     else if (data.m_getBool) {
261       GPU_shader_uniform_1f(sh, name, (float)(data.m_getBool() ? 1.0f : 0.0f));
262     }
263     else if (data.m_getFloat3) {
264       GPU_shader_uniform_3f(sh,
265                             name,
266                             (float)data.m_getFloat3()[0],
267                             (float)data.m_getFloat3()[1],
268                             (float)data.m_getFloat3()[2]);
269     }
270     else if (data.m_vectorFloat.m_getSize && data.m_vectorFloat.m_getVector) {
271       GPU_shader_uniform_vector(sh,
272                                 GPU_shader_get_uniform(sh, name),
273                                 (int)data.m_vectorFloat.m_getSize(),
274                                 1,
275                                 (float *)data.m_vectorFloat.m_getVector());
276     }
277     else if (data.m_vectorInt.m_getSize && data.m_vectorInt.m_getVector) {
278       GPU_shader_uniform_vector_int(sh,
279                                     GPU_shader_get_uniform(sh, name),
280                                     (int)data.m_vectorInt.m_getSize(),
281                                     1,
282                                     (int *)data.m_vectorInt.m_getVector());
283     }
284   }
285
286   return true;
287 }
288
289 /** \} */
290
291 /* -------------------------------------------------------------------- */
292 /** \name Textures
293  * \{ */
294
295 static bool addGPUUniform(OCIO_GPUTextures &textures,
296                           const GpuShaderDescRcPtr &shader_desc,
297                           int index)
298 {
299   OCIO_GPUUniform uniform;
300   uniform.name = shader_desc->getUniform(index, uniform.data);
301   if (uniform.data.m_type == UNIFORM_UNKNOWN) {
302     return false;
303   }
304
305   textures.uniforms.push_back(uniform);
306   return true;
307 }
308
309 static bool addGPULut2D(OCIO_GPUTextures &textures,
310                         const GpuShaderDescRcPtr &shader_desc,
311                         int index)
312 {
313   const char *texture_name = nullptr;
314   const char *sampler_name = nullptr;
315   unsigned int width = 0;
316   unsigned int height = 0;
317   GpuShaderCreator::TextureType channel = GpuShaderCreator::TEXTURE_RGB_CHANNEL;
318   Interpolation interpolation = INTERP_LINEAR;
319   shader_desc->getTexture(
320       index, texture_name, sampler_name, width, height, channel, interpolation);
321
322   const float *values;
323   shader_desc->getTextureValues(index, values);
324   if (texture_name == nullptr || sampler_name == nullptr || width == 0 || height == 0 ||
325       values == nullptr) {
326     return false;
327   }
328
329   eGPUTextureFormat format = (channel == GpuShaderCreator::TEXTURE_RGB_CHANNEL) ? GPU_RGB16F :
330                                                                                   GPU_R16F;
331
332   OCIO_GPULutTexture lut;
333   lut.texture = GPU_texture_create_2d(texture_name, width, height, 0, format, values);
334   if (lut.texture == nullptr) {
335     return false;
336   }
337
338   GPU_texture_filter_mode(lut.texture, interpolation != INTERP_NEAREST);
339   GPU_texture_wrap_mode(lut.texture, false, true);
340
341   lut.sampler_name = sampler_name;
342
343   textures.luts.push_back(lut);
344   return true;
345 }
346
347 static bool addGPULut3D(OCIO_GPUTextures &textures,
348                         const GpuShaderDescRcPtr &shader_desc,
349                         int index)
350 {
351   const char *texture_name = nullptr;
352   const char *sampler_name = nullptr;
353   unsigned int edgelen = 0;
354   Interpolation interpolation = INTERP_LINEAR;
355   shader_desc->get3DTexture(index, texture_name, sampler_name, edgelen, interpolation);
356
357   const float *values;
358   shader_desc->get3DTextureValues(index, values);
359   if (texture_name == nullptr || sampler_name == nullptr || edgelen == 0 || values == nullptr) {
360     return false;
361   }
362
363   OCIO_GPULutTexture lut;
364   lut.texture = GPU_texture_create_3d(
365       texture_name, edgelen, edgelen, edgelen, 0, GPU_RGB16F, GPU_DATA_FLOAT, values);
366   if (lut.texture == nullptr) {
367     return false;
368   }
369
370   GPU_texture_filter_mode(lut.texture, interpolation != INTERP_NEAREST);
371   GPU_texture_wrap_mode(lut.texture, false, true);
372
373   lut.sampler_name = sampler_name;
374
375   textures.luts.push_back(lut);
376   return true;
377 }
378
379 static bool createGPUTextures(OCIO_GPUTextures &textures,
380                               const GpuShaderDescRcPtr &shaderdesc_to_scene_linear,
381                               const GpuShaderDescRcPtr &shaderdesc_to_display)
382 {
383   textures.dummy = GPU_texture_create_error(2, false);
384
385   textures.luts.clear();
386   textures.uniforms.clear();
387
388   for (int index = 0; index < shaderdesc_to_scene_linear->getNumUniforms(); index++) {
389     if (!addGPUUniform(textures, shaderdesc_to_scene_linear, index)) {
390       return false;
391     }
392   }
393   for (int index = 0; index < shaderdesc_to_scene_linear->getNumTextures(); index++) {
394     if (!addGPULut2D(textures, shaderdesc_to_scene_linear, index)) {
395       return false;
396     }
397   }
398   for (int index = 0; index < shaderdesc_to_scene_linear->getNum3DTextures(); index++) {
399     if (!addGPULut3D(textures, shaderdesc_to_scene_linear, index)) {
400       return false;
401     }
402   }
403   for (int index = 0; index < shaderdesc_to_display->getNumUniforms(); index++) {
404     if (!addGPUUniform(textures, shaderdesc_to_display, index)) {
405       return false;
406     }
407   }
408   for (int index = 0; index < shaderdesc_to_display->getNumTextures(); index++) {
409     if (!addGPULut2D(textures, shaderdesc_to_display, index)) {
410       return false;
411     }
412   }
413   for (int index = 0; index < shaderdesc_to_display->getNum3DTextures(); index++) {
414     if (!addGPULut3D(textures, shaderdesc_to_display, index)) {
415       return false;
416     }
417   }
418
419   return true;
420 }
421
422 /** \} */
423
424 /* -------------------------------------------------------------------- */
425 /** \name Curve Mapping
426  * \{ */
427
428 static bool createGPUCurveMapping(OCIO_GPUCurveMappping &curvemap,
429                                   OCIO_CurveMappingSettings *curve_mapping_settings)
430 {
431   if (curve_mapping_settings) {
432     int lut_size = curve_mapping_settings->lut_size;
433
434     curvemap.texture = GPU_texture_create_1d("OCIOCurveMap", lut_size, 1, GPU_RGBA16F, nullptr);
435     GPU_texture_filter_mode(curvemap.texture, false);
436     GPU_texture_wrap_mode(curvemap.texture, false, true);
437
438     curvemap.buffer = GPU_uniformbuf_create(sizeof(OCIO_GPUCurveMappingParameters));
439
440     if (curvemap.texture == nullptr || curvemap.buffer == nullptr) {
441       return false;
442     }
443   }
444
445   return true;
446 }
447
448 static void updateGPUCurveMapping(OCIO_GPUCurveMappping &curvemap,
449                                   OCIO_CurveMappingSettings *curve_mapping_settings)
450 {
451   /* Test if we need to update. The caller ensures the curve_mapping_settings
452    * changes when its contents changes. */
453   if (curve_mapping_settings == nullptr || curvemap.cache_id == curve_mapping_settings->cache_id) {
454     return;
455   }
456
457   curvemap.cache_id = curve_mapping_settings->cache_id;
458
459   /* Update texture. */
460   int offset[3] = {0, 0, 0};
461   int extent[3] = {curve_mapping_settings->lut_size, 0, 0};
462   const float *pixels = curve_mapping_settings->lut;
463   GPU_texture_update_sub(
464       curvemap.texture, GPU_DATA_FLOAT, pixels, UNPACK3(offset), UNPACK3(extent));
465
466   /* Update uniforms. */
467   OCIO_GPUCurveMappingParameters data;
468   for (int i = 0; i < 4; i++) {
469     data.curve_mapping_range[i] = curve_mapping_settings->range[i];
470     data.curve_mapping_mintable[i] = curve_mapping_settings->mintable[i];
471     data.curve_mapping_ext_in_x[i] = curve_mapping_settings->ext_in_x[i];
472     data.curve_mapping_ext_in_y[i] = curve_mapping_settings->ext_in_y[i];
473     data.curve_mapping_ext_out_x[i] = curve_mapping_settings->ext_out_x[i];
474     data.curve_mapping_ext_out_y[i] = curve_mapping_settings->ext_out_y[i];
475     data.curve_mapping_first_x[i] = curve_mapping_settings->first_x[i];
476     data.curve_mapping_first_y[i] = curve_mapping_settings->first_y[i];
477     data.curve_mapping_last_x[i] = curve_mapping_settings->last_x[i];
478     data.curve_mapping_last_y[i] = curve_mapping_settings->last_y[i];
479   }
480   for (int i = 0; i < 3; i++) {
481     data.curve_mapping_black[i] = curve_mapping_settings->black[i];
482     data.curve_mapping_bwmul[i] = curve_mapping_settings->bwmul[i];
483   }
484   data.curve_mapping_lut_size = curve_mapping_settings->lut_size;
485   data.curve_mapping_use_extend_extrapolate = curve_mapping_settings->use_extend_extrapolate;
486
487   GPU_uniformbuf_update(curvemap.buffer, &data);
488 }
489
490 /** \} */
491
492 /* -------------------------------------------------------------------- */
493 /** \name OCIO GPU Shader Implementation
494  * \{ */
495
496 bool OCIOImpl::supportGPUShader()
497 {
498   /* Minimum supported version 3.3 does meet all requirements. */
499   return true;
500 }
501
502 static OCIO_GPUDisplayShader &getGPUDisplayShader(
503     OCIO_ConstConfigRcPtr *config,
504     const char *input,
505     const char *view,
506     const char *display,
507     const char *look,
508     OCIO_CurveMappingSettings *curve_mapping_settings)
509 {
510   /* Find existing shader in cache. */
511   const bool use_curve_mapping = (curve_mapping_settings != nullptr);
512   for (std::list<OCIO_GPUDisplayShader>::iterator it = SHADER_CACHE.begin();
513        it != SHADER_CACHE.end();
514        it++) {
515     if (it->input == input && it->view == view && it->display == display && it->look == look &&
516         it->use_curve_mapping == use_curve_mapping) {
517       /* Move to front of the cache to mark as most recently used. */
518       if (it != SHADER_CACHE.begin()) {
519         SHADER_CACHE.splice(SHADER_CACHE.begin(), SHADER_CACHE, it);
520       }
521
522       return *it;
523     }
524   }
525
526   /* Remove least recently used element from cache. */
527   if (SHADER_CACHE.size() >= SHADER_CACHE_MAX_SIZE) {
528     SHADER_CACHE.pop_back();
529   }
530
531   /* Create GPU shader. */
532   SHADER_CACHE.emplace_front();
533   OCIO_GPUDisplayShader &display_shader = SHADER_CACHE.front();
534
535   display_shader.input = input;
536   display_shader.view = view;
537   display_shader.display = display;
538   display_shader.look = look;
539   display_shader.use_curve_mapping = use_curve_mapping;
540   display_shader.valid = false;
541
542   /* Create Processors.
543    *
544    * Scale and exponent are handled outside of OCIO shader so we can handle them
545    * as uniforms at the binding stage. OCIO would otherwise bake them into the
546    * shader code, requiring slow recompiles when interactively adjusting them.
547    *
548    * Note that OCIO does have the concept of dynamic properties, however there
549    * is no dynamic gamma and exposure is part of more expensive operations only.
550    *
551    * Since exposure must happen in scene linear, we use two processors. The input
552    * is usually scene linear already and so that conversion is often a no-op.
553    */
554   OCIO_ConstProcessorRcPtr *processor_to_scene_linear = OCIO_configGetProcessorWithNames(
555       config, input, ROLE_SCENE_LINEAR);
556   OCIO_ConstProcessorRcPtr *processor_to_display = OCIO_createDisplayProcessor(
557       config, ROLE_SCENE_LINEAR, view, display, look, 1.0f, 1.0f);
558
559   /* Create shader descriptions. */
560   if (processor_to_scene_linear && processor_to_display) {
561     GpuShaderDescRcPtr shaderdesc_to_scene_linear = GpuShaderDesc::CreateShaderDesc();
562     shaderdesc_to_scene_linear->setLanguage(GPU_LANGUAGE_GLSL_1_3);
563     shaderdesc_to_scene_linear->setFunctionName("OCIO_to_scene_linear");
564     shaderdesc_to_scene_linear->setResourcePrefix("to_scene");
565     (*(ConstProcessorRcPtr *)processor_to_scene_linear)
566         ->getDefaultGPUProcessor()
567         ->extractGpuShaderInfo(shaderdesc_to_scene_linear);
568     shaderdesc_to_scene_linear->finalize();
569
570     GpuShaderDescRcPtr shaderdesc_to_display = GpuShaderDesc::CreateShaderDesc();
571     shaderdesc_to_display->setLanguage(GPU_LANGUAGE_GLSL_1_3);
572     shaderdesc_to_display->setFunctionName("OCIO_to_display");
573     shaderdesc_to_scene_linear->setResourcePrefix("to_display");
574     (*(ConstProcessorRcPtr *)processor_to_display)
575         ->getDefaultGPUProcessor()
576         ->extractGpuShaderInfo(shaderdesc_to_display);
577     shaderdesc_to_display->finalize();
578
579     /* Create GPU shader and textures. */
580     if (createGPUTextures(
581             display_shader.textures, shaderdesc_to_scene_linear, shaderdesc_to_display) &&
582         createGPUCurveMapping(display_shader.curvemap, curve_mapping_settings) &&
583         createGPUShader(display_shader.shader,
584                         display_shader.textures,
585                         shaderdesc_to_scene_linear,
586                         shaderdesc_to_display,
587                         use_curve_mapping)) {
588       display_shader.valid = true;
589     }
590   }
591
592   /* Free processors. */
593   if (processor_to_scene_linear) {
594     OCIO_processorRelease(processor_to_scene_linear);
595   }
596   if (processor_to_display) {
597     OCIO_processorRelease(processor_to_display);
598   }
599
600   return display_shader;
601 }
602
603 /**
604  * Setup GPU contexts for a transform defined by processor using GLSL.
605  * All LUT allocating baking and shader compilation happens here.
606  *
607  * Once this function is called, callee could start drawing images
608  * using regular 2D texture.
609  *
610  * When all drawing is finished, gpuDisplayShaderUnbind must be called to
611  * restore GPU context to its previous state.
612  */
613 bool OCIOImpl::gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
614                                     const char *input,
615                                     const char *view,
616                                     const char *display,
617                                     const char *look,
618                                     OCIO_CurveMappingSettings *curve_mapping_settings,
619                                     const float scale,
620                                     const float exponent,
621                                     const float dither,
622                                     const bool use_predivide,
623                                     const bool use_overlay)
624 {
625   /* Get GPU shader from cache or create new one. */
626   OCIO_GPUDisplayShader &display_shader = getGPUDisplayShader(
627       config, input, view, display, look, curve_mapping_settings);
628   if (!display_shader.valid) {
629     return false;
630   }
631
632   /* Verify the shader is valid. */
633   OCIO_GPUTextures &textures = display_shader.textures;
634   OCIO_GPUShader &shader = display_shader.shader;
635   OCIO_GPUCurveMappping &curvemap = display_shader.curvemap;
636
637   /* Update and bind curve mapping data. */
638   if (curve_mapping_settings) {
639     updateGPUCurveMapping(curvemap, curve_mapping_settings);
640     GPU_uniformbuf_bind(curvemap.buffer, shader.ubo_bind);
641     GPU_texture_bind(curvemap.texture, TEXTURE_SLOT_CURVE_MAPPING);
642   }
643
644   /* Bind textures to sampler units. Texture 0 is set by caller.
645    * Uniforms have already been set for texture bind points.*/
646   if (!use_overlay) {
647     /* Avoid missing binds. */
648     GPU_texture_bind(textures.dummy, TEXTURE_SLOT_OVERLAY);
649   }
650   for (int i = 0; i < textures.luts.size(); i++) {
651     GPU_texture_bind(textures.luts[i].texture, TEXTURE_SLOT_LUTS_OFFSET + i);
652   }
653
654   /* TODO(fclem): remove remains of IMM. */
655   immBindShader(shader.shader);
656
657   /* Bind Shader and set uniforms. */
658   // GPU_shader_bind(shader.shader);
659   GPU_shader_uniform_float(shader.shader, shader.scale_loc, scale);
660   GPU_shader_uniform_float(shader.shader, shader.exponent_loc, exponent);
661   GPU_shader_uniform_float(shader.shader, shader.dither_loc, dither);
662   GPU_shader_uniform_int(shader.shader, shader.overlay_loc, use_overlay);
663   GPU_shader_uniform_int(shader.shader, shader.predivide_loc, use_predivide);
664
665   return true;
666 }
667
668 void OCIOImpl::gpuDisplayShaderUnbind()
669 {
670   immUnbindProgram();
671 }
672
673 void OCIOImpl::gpuCacheFree()
674 {
675   SHADER_CACHE.clear();
676 }
677
678 /** \} */