Blender V4.3
ocio_impl_glsl.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2003-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
2 * (BSD-3-Clause).
3 * SPDX-FileCopyrightText: 2013 Blender Authors (GPL-2.0-or-later).
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later AND BSD-3-Clause */
6
7#include <limits>
8#include <list>
9#include <sstream>
10#include <string.h>
11#include <vector>
12
13#ifdef _MSC_VER
14# pragma warning(push)
15# pragma warning(disable : 4251 4275)
16#endif
17#include <OpenColorIO/OpenColorIO.h>
18#ifdef _MSC_VER
19# pragma warning(pop)
20#endif
21
22#include "GPU_immediate.hh"
23#include "GPU_shader.hh"
24#include "GPU_uniform_buffer.hh"
25
27
28using namespace OCIO_NAMESPACE;
29
30#include "BLI_math_color.h"
31#include "BLI_math_color.hh"
32#include "BLI_math_matrix.hh"
33
34#include "MEM_guardedalloc.h"
35
36#include "ocio_impl.h"
37#include "ocio_shader_shared.hh"
38
40
41/* **** OpenGL drawing routines using GLSL for color space transform ***** */
42
49
55
57 /* GPU shader. */
58 struct GPUShader *shader = nullptr;
59
62 GPUUniformBuf *parameters_buffer = nullptr;
63
64 /* Destructor. */
66 {
67 if (shader) {
68 GPU_shader_free(shader);
69 }
72 }
73 }
74};
75
77 GPUTexture *texture = nullptr;
78 std::string sampler_name;
79};
80
82 GpuShaderDesc::UniformData data;
83 std::string name;
84};
85
88 std::vector<OCIO_GPULutTexture> luts;
89
90 /* Dummy in case of no overlay. */
91 GPUTexture *dummy = nullptr;
92
93 /* Uniforms */
94 std::vector<OCIO_GPUUniform> uniforms;
95 GPUUniformBuf *uniforms_buffer = nullptr;
96
97 /* Destructor. */
99 {
100 for (OCIO_GPULutTexture &lut : luts) {
101 GPU_texture_free(lut.texture);
102 }
103 if (dummy) {
105 }
106 if (uniforms_buffer) {
108 }
109 }
110};
111
114 GPUUniformBuf *buffer = nullptr;
116 GPUTexture *texture = nullptr;
117 /* To detect when to update the uniforms and textures. */
118 size_t cache_id = 0;
119
120 /* Destructor. */
122 {
123 if (texture) {
124 GPU_texture_free(texture);
125 }
126 if (buffer) {
128 }
129 }
130};
131
136
137 /* Cache variables. */
138 std::string input;
139 std::string view;
140 std::string display;
141 std::string look;
142 bool use_curve_mapping = false;
143
145 bool valid = false;
146};
147
148static const int SHADER_CACHE_MAX_SIZE = 4;
149std::list<OCIO_GPUDisplayShader> SHADER_CACHE;
150
151/* -------------------------------------------------------------------- */
155static void string_replace_all(std::string &haystack,
156 const std::string &needle,
157 const std::string &other)
158{
159 size_t i = 0, index;
160 while ((index = haystack.find(needle, i)) != std::string::npos) {
161 haystack.replace(index, needle.size(), other);
162 i = index + other.size();
163 }
164}
165
166static bool createGPUShader(OCIO_GPUShader &shader,
167 OCIO_GPUTextures &textures,
168 const GpuShaderDescRcPtr &shaderdesc_to_scene_linear,
169 const GpuShaderDescRcPtr &shaderdesc_to_display,
170 const bool use_curve_mapping)
171{
172 using namespace blender::gpu::shader;
173
174 std::string source;
175 source += shaderdesc_to_scene_linear->getShaderText();
176 source += "\n";
177 source += shaderdesc_to_display->getShaderText();
178 source += "\n";
179
180 {
181 /* Replace all uniform declarations by a comment.
182 * This avoids double declarations from the backend. */
183 size_t index = 0;
184 while (true) {
185 index = source.find("uniform ", index);
186 if (index == -1) {
187 break;
188 }
189 source.replace(index, 2, "//");
190 index += 2;
191 }
192 }
193
194 /* Comparison operator in Metal returns per-element comparison and returns a vector of booleans.
195 * Need a special syntax to see if two vec3 are matched.
196 *
197 * NOTE: The replacement is optimized for transforming code generated by
198 * GradingPrimaryTransform. A more general approach is possible, but for now prefer processing
199 * speed.
200 *
201 * NOTE: The syntax works for all backends Blender supports. */
203 source, "if ( gamma != vec3(1., 1., 1.) )", "if (! all(equal(gamma, vec3(1., 1., 1.))) )");
204
205 StageInterfaceInfo iface("OCIO_Interface", "");
206 iface.smooth(Type::VEC2, "texCoord_interp");
207
208 ShaderCreateInfo info("OCIO_Display");
209 /* Work around OpenColorIO not supporting latest GLSL yet. */
210 info.define("texture1D", "texture");
211 info.define("texture2D", "texture");
212 info.define("texture3D", "texture");
213 /* Work around unsupported in keyword in Metal GLSL emulation. */
214#ifdef __APPLE__
215 info.define("in", "");
216#endif
217 info.typedef_source("ocio_shader_shared.hh");
218 info.sampler(TEXTURE_SLOT_IMAGE, ImageType::FLOAT_2D, "image_texture");
219 info.sampler(TEXTURE_SLOT_OVERLAY, ImageType::FLOAT_2D, "overlay_texture");
220 info.uniform_buf(UNIFORMBUF_SLOT_DISPLAY, "OCIO_GPUParameters", "parameters");
221 info.push_constant(Type::MAT4, "ModelViewProjectionMatrix");
222 info.vertex_in(0, Type::VEC2, "pos");
223 info.vertex_in(1, Type::VEC2, "texCoord");
224 info.vertex_out(iface);
225 info.fragment_out(0, Type::VEC4, "fragColor");
226 info.vertex_source("gpu_shader_display_transform_vert.glsl");
227 info.fragment_source("gpu_shader_display_transform_frag.glsl");
228 info.fragment_source_generated = source;
229
230 /* #96502: Work around for incorrect OCIO GLSL code generation when using
231 * GradingPrimaryTransform. Should be reevaluated when changing to a next version of OCIO.
232 * (currently v2.1.1). */
233 info.define("inf 1e32");
234
235 if (use_curve_mapping) {
236 info.define("USE_CURVE_MAPPING");
237 info.uniform_buf(UNIFORMBUF_SLOT_CURVEMAP, "OCIO_GPUCurveMappingParameters", "curve_mapping");
238 info.sampler(TEXTURE_SLOT_CURVE_MAPPING, ImageType::FLOAT_1D, "curve_mapping_texture");
239 }
240
241 /* Set LUT textures. */
242 int slot = TEXTURE_SLOT_LUTS_OFFSET;
243 for (OCIO_GPULutTexture &texture : textures.luts) {
244 const int dimensions = GPU_texture_dimensions(texture.texture);
245 ImageType type = (dimensions == 1) ? ImageType::FLOAT_1D :
246 (dimensions == 2) ? ImageType::FLOAT_2D :
247 ImageType::FLOAT_3D;
248
249 info.sampler(slot++, type, texture.sampler_name.c_str());
250 }
251
252 /* Set LUT uniforms. */
253 if (!textures.uniforms.empty()) {
254 /* NOTE: For simplicity, we pad everything to size of vec4 avoiding sorting and alignment
255 * issues. It is unlikely that this becomes a real issue. */
256 size_t ubo_size = textures.uniforms.size() * sizeof(float) * 4;
257 void *ubo_data_buf = malloc(ubo_size);
258
259 uint32_t *ubo_data = reinterpret_cast<uint32_t *>(ubo_data_buf);
260
261 std::stringstream ss;
262 ss << "struct OCIO_GPULutParameters {\n";
263
264 int index = 0;
265 for (OCIO_GPUUniform &uniform : textures.uniforms) {
266 index += 1;
267 const GpuShaderDesc::UniformData &data = uniform.data;
268 const char *name = uniform.name.c_str();
269 char prefix = ' ';
270 int vec_len;
271 switch (data.m_type) {
272 case UNIFORM_DOUBLE: {
273 vec_len = 1;
274 float value = float(data.m_getDouble());
275 memcpy(ubo_data, &value, sizeof(float));
276 break;
277 }
278 case UNIFORM_BOOL: {
279 prefix = 'b';
280 vec_len = 1;
281 int value = int(data.m_getBool());
282 memcpy(ubo_data, &value, sizeof(int));
283 break;
284 }
285 case UNIFORM_FLOAT3:
286 vec_len = 3;
287 memcpy(ubo_data, data.m_getFloat3().data(), sizeof(float) * 3);
288 break;
289 case UNIFORM_VECTOR_FLOAT:
290 vec_len = data.m_vectorFloat.m_getSize();
291 memcpy(ubo_data, data.m_vectorFloat.m_getVector(), sizeof(float) * vec_len);
292 break;
293 case UNIFORM_VECTOR_INT:
294 prefix = 'i';
295 vec_len = data.m_vectorInt.m_getSize();
296 memcpy(ubo_data, data.m_vectorInt.m_getVector(), sizeof(int) * vec_len);
297 break;
298 default:
299 continue;
300 }
301 /* Align every member to 16bytes. */
302 ubo_data += 4;
303 /* Use a generic variable name because some GLSL compilers can interpret the preprocessor
304 * define as recursive. */
305 ss << " " << prefix << "vec4 var" << index << ";\n";
306 /* Use a define to keep the generated code working. */
307 blender::StringRef suffix = blender::StringRefNull("xyzw").substr(0, vec_len);
308 ss << "#define " << name << " lut_parameters.var" << index << "." << suffix << "\n";
309 }
310 ss << "};\n";
311 info.typedef_source_generated = ss.str();
312
313 info.uniform_buf(UNIFORMBUF_SLOT_LUTS, "OCIO_GPULutParameters", "lut_parameters");
314
316 ubo_size, ubo_data_buf, "OCIO_LutParameters");
317
318 free(ubo_data_buf);
319 }
320
321 shader.shader = GPU_shader_create_from_info(reinterpret_cast<GPUShaderCreateInfo *>(&info));
322
323 return (shader.shader != nullptr);
324}
325
328/* -------------------------------------------------------------------- */
332static bool addGPUUniform(OCIO_GPUTextures &textures,
333 const GpuShaderDescRcPtr &shader_desc,
334 int index)
335{
336 OCIO_GPUUniform uniform;
337 uniform.name = shader_desc->getUniform(index, uniform.data);
338 if (uniform.data.m_type == UNIFORM_UNKNOWN) {
339 return false;
340 }
341
342 textures.uniforms.push_back(uniform);
343 return true;
344}
345
346static bool addGPULut1D2D(OCIO_GPUTextures &textures,
347 const GpuShaderDescRcPtr &shader_desc,
348 int index)
349{
350 const char *texture_name = nullptr;
351 const char *sampler_name = nullptr;
352 unsigned int width = 0;
353 unsigned int height = 0;
354 GpuShaderCreator::TextureType channel = GpuShaderCreator::TEXTURE_RGB_CHANNEL;
355 Interpolation interpolation = INTERP_LINEAR;
356#if OCIO_VERSION_HEX >= 0x02030000
357 /* Always use 2D textures in OpenColorIO 2.3, simpler and same performance. */
358 GpuShaderDesc::TextureDimensions dimensions = GpuShaderDesc::TEXTURE_2D;
359 shader_desc->getTexture(
360 index, texture_name, sampler_name, width, height, channel, dimensions, interpolation);
361#else
362 shader_desc->getTexture(
363 index, texture_name, sampler_name, width, height, channel, interpolation);
364#endif
365
366 const float *values;
367 shader_desc->getTextureValues(index, values);
368 if (texture_name == nullptr || sampler_name == nullptr || width == 0 || height == 0 ||
369 values == nullptr)
370 {
371 return false;
372 }
373
374 eGPUTextureFormat format = (channel == GpuShaderCreator::TEXTURE_RGB_CHANNEL) ? GPU_RGB16F :
375 GPU_R16F;
376
378#if OCIO_VERSION_HEX < 0x02030000
379 /* There does not appear to be an explicit way to check if a texture is 1D or 2D.
380 * It depends on more than height. So check instead by looking at the source. */
381 std::string sampler1D_name = std::string("sampler1D ") + sampler_name;
382 if (strstr(shader_desc->getShaderText(), sampler1D_name.c_str()) != nullptr) {
384 texture_name, width, 1, format, GPU_TEXTURE_USAGE_SHADER_READ, values);
385 }
386 else
387#endif
388 {
390 texture_name, width, height, 1, format, GPU_TEXTURE_USAGE_SHADER_READ, values);
391 }
392 if (lut.texture == nullptr) {
393 return false;
394 }
395
396 GPU_texture_filter_mode(lut.texture, interpolation != INTERP_NEAREST);
398
399 lut.sampler_name = sampler_name;
400
401 textures.luts.push_back(lut);
402 return true;
403}
404
405static bool addGPULut3D(OCIO_GPUTextures &textures,
406 const GpuShaderDescRcPtr &shader_desc,
407 int index)
408{
409 const char *texture_name = nullptr;
410 const char *sampler_name = nullptr;
411 unsigned int edgelen = 0;
412 Interpolation interpolation = INTERP_LINEAR;
413 shader_desc->get3DTexture(index, texture_name, sampler_name, edgelen, interpolation);
414
415 const float *values;
416 shader_desc->get3DTextureValues(index, values);
417 if (texture_name == nullptr || sampler_name == nullptr || edgelen == 0 || values == nullptr) {
418 return false;
419 }
420
422 lut.texture = GPU_texture_create_3d(texture_name,
423 edgelen,
424 edgelen,
425 edgelen,
426 1,
429 values);
430 if (lut.texture == nullptr) {
431 return false;
432 }
433
434 GPU_texture_filter_mode(lut.texture, interpolation != INTERP_NEAREST);
436
437 lut.sampler_name = sampler_name;
438
439 textures.luts.push_back(lut);
440 return true;
441}
442
444 const GpuShaderDescRcPtr &shaderdesc_to_scene_linear,
445 const GpuShaderDescRcPtr &shaderdesc_to_display)
446{
447 textures.dummy = GPU_texture_create_error(2, false);
448
449 textures.luts.clear();
450 textures.uniforms.clear();
451
452 for (int index = 0; index < shaderdesc_to_scene_linear->getNumUniforms(); index++) {
453 if (!addGPUUniform(textures, shaderdesc_to_scene_linear, index)) {
454 return false;
455 }
456 }
457 for (int index = 0; index < shaderdesc_to_scene_linear->getNumTextures(); index++) {
458 if (!addGPULut1D2D(textures, shaderdesc_to_scene_linear, index)) {
459 return false;
460 }
461 }
462 for (int index = 0; index < shaderdesc_to_scene_linear->getNum3DTextures(); index++) {
463 if (!addGPULut3D(textures, shaderdesc_to_scene_linear, index)) {
464 return false;
465 }
466 }
467 for (int index = 0; index < shaderdesc_to_display->getNumUniforms(); index++) {
468 if (!addGPUUniform(textures, shaderdesc_to_display, index)) {
469 return false;
470 }
471 }
472 for (int index = 0; index < shaderdesc_to_display->getNumTextures(); index++) {
473 if (!addGPULut1D2D(textures, shaderdesc_to_display, index)) {
474 return false;
475 }
476 }
477 for (int index = 0; index < shaderdesc_to_display->getNum3DTextures(); index++) {
478 if (!addGPULut3D(textures, shaderdesc_to_display, index)) {
479 return false;
480 }
481 }
482
483 return true;
484}
485
488/* -------------------------------------------------------------------- */
493 OCIO_CurveMappingSettings *curve_mapping_settings)
494{
495 if (curve_mapping_settings) {
496 int lut_size = curve_mapping_settings->lut_size;
497
499 "OCIOCurveMap", lut_size, 1, GPU_RGBA16F, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
500 GPU_texture_filter_mode(curvemap.texture, false);
502
504
505 if (curvemap.texture == nullptr || curvemap.buffer == nullptr) {
506 return false;
507 }
508 }
509
510 return true;
511}
512
514 OCIO_CurveMappingSettings *curve_mapping_settings)
515{
516 /* Test if we need to update. The caller ensures the curve_mapping_settings
517 * changes when its contents changes. */
518 if (curve_mapping_settings == nullptr || curvemap.cache_id == curve_mapping_settings->cache_id) {
519 return;
520 }
521
522 curvemap.cache_id = curve_mapping_settings->cache_id;
523
524 /* Update texture. */
525 const int offset[3] = {0, 0, 0};
526 const int extent[3] = {curve_mapping_settings->lut_size, 0, 0};
527 const float *pixels = curve_mapping_settings->lut;
529 curvemap.texture, GPU_DATA_FLOAT, pixels, UNPACK3(offset), UNPACK3(extent));
530
531 /* Update uniforms. */
533 for (int i = 0; i < 4; i++) {
534 data.range[i] = curve_mapping_settings->range[i];
535 data.mintable[i] = curve_mapping_settings->mintable[i];
536 data.ext_in_x[i] = curve_mapping_settings->ext_in_x[i];
537 data.ext_in_y[i] = curve_mapping_settings->ext_in_y[i];
538 data.ext_out_x[i] = curve_mapping_settings->ext_out_x[i];
539 data.ext_out_y[i] = curve_mapping_settings->ext_out_y[i];
540 data.first_x[i] = curve_mapping_settings->first_x[i];
541 data.first_y[i] = curve_mapping_settings->first_y[i];
542 data.last_x[i] = curve_mapping_settings->last_x[i];
543 data.last_y[i] = curve_mapping_settings->last_y[i];
544 }
545 for (int i = 0; i < 3; i++) {
546 data.black[i] = curve_mapping_settings->black[i];
547 data.bwmul[i] = curve_mapping_settings->bwmul[i];
548 }
549 data.lut_size = curve_mapping_settings->lut_size;
550 data.use_extend_extrapolate = curve_mapping_settings->use_extend_extrapolate;
551
552 GPU_uniformbuf_update(curvemap.buffer, &data);
553}
554
556 float exponent,
557 float4x4 scene_linear_matrix,
558 float dither,
559 bool use_predivide,
560 bool use_overlay,
561 bool use_hdr)
562{
563 bool do_update = false;
564 if (shader.parameters_buffer == nullptr) {
565 shader.parameters_buffer = GPU_uniformbuf_create(sizeof(OCIO_GPUParameters));
566 do_update = true;
567 }
568 OCIO_GPUParameters &data = shader.parameters;
569 if (data.scene_linear_matrix != scene_linear_matrix) {
570 data.scene_linear_matrix = scene_linear_matrix;
571 do_update = true;
572 }
573 if (data.exponent != exponent) {
574 data.exponent = exponent;
575 do_update = true;
576 }
577 if (data.dither != dither) {
578 data.dither = dither;
579 do_update = true;
580 }
581 if (bool(data.use_predivide) != use_predivide) {
582 data.use_predivide = use_predivide;
583 do_update = true;
584 }
585 if (bool(data.use_overlay) != use_overlay) {
586 data.use_overlay = use_overlay;
587 do_update = true;
588 }
589 if (bool(data.use_hdr) != use_hdr) {
590 data.use_hdr = use_hdr;
591 do_update = true;
592 }
593 if (do_update) {
594 GPU_uniformbuf_update(shader.parameters_buffer, &data);
595 }
596}
597
600/* -------------------------------------------------------------------- */
604bool OCIOImpl::supportGPUShader()
605{
606 /* Minimum supported version 3.3 does meet all requirements. */
607 return true;
608}
609
611 OCIO_ConstConfigRcPtr *config,
612 const char *input,
613 const char *view,
614 const char *display,
615 const char *look,
616 OCIO_CurveMappingSettings *curve_mapping_settings)
617{
618 /* Find existing shader in cache. */
619 const bool use_curve_mapping = (curve_mapping_settings != nullptr);
620 for (std::list<OCIO_GPUDisplayShader>::iterator it = SHADER_CACHE.begin();
621 it != SHADER_CACHE.end();
622 it++)
623 {
624 if (it->input == input && it->view == view && it->display == display && it->look == look &&
625 it->use_curve_mapping == use_curve_mapping)
626 {
627 /* Move to front of the cache to mark as most recently used. */
628 if (it != SHADER_CACHE.begin()) {
629 SHADER_CACHE.splice(SHADER_CACHE.begin(), SHADER_CACHE, it);
630 }
631
632 return *it;
633 }
634 }
635
636 /* Remove least recently used element from cache. */
637 if (SHADER_CACHE.size() >= SHADER_CACHE_MAX_SIZE) {
638 SHADER_CACHE.pop_back();
639 }
640
641 /* Create GPU shader. */
642 SHADER_CACHE.emplace_front();
643 OCIO_GPUDisplayShader &display_shader = SHADER_CACHE.front();
644
645 display_shader.input = input;
646 display_shader.view = view;
647 display_shader.display = display;
648 display_shader.look = look;
649 display_shader.use_curve_mapping = use_curve_mapping;
650 display_shader.valid = false;
651
652 /* Create Processors.
653 *
654 * Scale, white balance and exponent are handled outside of OCIO shader so we
655 * can handle them as uniforms at the binding stage. OCIO would otherwise bake
656 * them into the shader code, requiring slow recompiles when interactively
657 * adjusting them.
658 *
659 * Note that OCIO does have the concept of dynamic properties, however there
660 * is no dynamic gamma and exposure is part of more expensive operations only.
661 *
662 * Since exposure and white balance must happen in scene linear, we use two
663 * processors. The input is usually scene linear already and so that conversion
664 * is often a no-op.
665 */
666 OCIO_ConstProcessorRcPtr *processor_to_scene_linear = OCIO_configGetProcessorWithNames(
667 config, input, ROLE_SCENE_LINEAR);
668 OCIO_ConstProcessorRcPtr *processor_to_display = OCIO_createDisplayProcessor(
669 config, ROLE_SCENE_LINEAR, view, display, look, 1.0f, 1.0f, 0.0f, 0.0f, false, false);
670
671 /* Create shader descriptions. */
672 if (processor_to_scene_linear && processor_to_display) {
673 GpuShaderDescRcPtr shaderdesc_to_scene_linear = GpuShaderDesc::CreateShaderDesc();
674 shaderdesc_to_scene_linear->setLanguage(GPU_LANGUAGE_GLSL_1_3);
675 shaderdesc_to_scene_linear->setFunctionName("OCIO_to_scene_linear");
676 shaderdesc_to_scene_linear->setResourcePrefix("to_scene");
677 (*(ConstProcessorRcPtr *)processor_to_scene_linear)
678 ->getDefaultGPUProcessor()
679 ->extractGpuShaderInfo(shaderdesc_to_scene_linear);
680 shaderdesc_to_scene_linear->finalize();
681
682 GpuShaderDescRcPtr shaderdesc_to_display = GpuShaderDesc::CreateShaderDesc();
683 shaderdesc_to_display->setLanguage(GPU_LANGUAGE_GLSL_1_3);
684 shaderdesc_to_display->setFunctionName("OCIO_to_display");
685 shaderdesc_to_display->setResourcePrefix("to_display");
686 (*(ConstProcessorRcPtr *)processor_to_display)
687 ->getDefaultGPUProcessor()
688 ->extractGpuShaderInfo(shaderdesc_to_display);
689 shaderdesc_to_display->finalize();
690
691 /* Create GPU shader and textures. */
693 display_shader.textures, shaderdesc_to_scene_linear, shaderdesc_to_display) &&
694 createGPUCurveMapping(display_shader.curvemap, curve_mapping_settings) &&
695 createGPUShader(display_shader.shader,
696 display_shader.textures,
697 shaderdesc_to_scene_linear,
698 shaderdesc_to_display,
699 use_curve_mapping))
700 {
701 display_shader.valid = true;
702 }
703 }
704
705 /* Free processors. */
706 if (processor_to_scene_linear) {
707 OCIO_processorRelease(processor_to_scene_linear);
708 }
709 if (processor_to_display) {
710 OCIO_processorRelease(processor_to_display);
711 }
712
713 return display_shader;
714}
715
726bool OCIOImpl::gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
727 const char *input,
728 const char *view,
729 const char *display,
730 const char *look,
731 OCIO_CurveMappingSettings *curve_mapping_settings,
732 const float scale,
733 const float exponent,
734 const float dither,
735 const float temperature,
736 const float tint,
737 const bool use_predivide,
738 const bool use_overlay,
739 const bool use_hdr,
740 const bool use_white_balance)
741{
742 /* Get GPU shader from cache or create new one. */
744 config, input, view, display, look, curve_mapping_settings);
745 if (!display_shader.valid) {
746 return false;
747 }
748
749 /* Verify the shader is valid. */
750 OCIO_GPUTextures &textures = display_shader.textures;
751 OCIO_GPUShader &shader = display_shader.shader;
752 OCIO_GPUCurveMappping &curvemap = display_shader.curvemap;
753
754 /* Update and bind curve mapping data. */
755 if (curve_mapping_settings) {
756 updateGPUCurveMapping(curvemap, curve_mapping_settings);
759 }
760
761 /* Bind textures to sampler units. Texture 0 is set by caller.
762 * Uniforms have already been set for texture bind points. */
763 if (!use_overlay) {
764 /* Avoid missing binds. */
766 }
767 for (int i = 0; i < textures.luts.size(); i++) {
768 GPU_texture_bind(textures.luts[i].texture, TEXTURE_SLOT_LUTS_OFFSET + i);
769 }
770
771 if (textures.uniforms_buffer) {
773 }
774
775 float3x3 matrix = float3x3::identity() * scale;
776 if (use_white_balance) {
777 /* Compute white point of the scene space in XYZ.*/
778 float3x3 xyz_to_scene;
779 configGetXYZtoSceneLinear(config, xyz_to_scene.ptr());
780 float3x3 scene_to_xyz = blender::math::invert(xyz_to_scene);
781 float3 target = scene_to_xyz * float3(1.0f);
782
783 /* Add operations to the matrix.
784 * Note: Since we're multiplying from the right, the operations here will be performed in
785 * reverse list order (scene-to-XYZ, then adaption, then XYZ-to-scene, then exposure). */
786 matrix *= xyz_to_scene;
788 blender::math::whitepoint_from_temp_tint(temperature, tint), target);
789 matrix *= scene_to_xyz;
790 }
792 shader, exponent, float4x4(matrix), dither, use_predivide, use_overlay, use_hdr);
793 GPU_uniformbuf_bind(shader.parameters_buffer, UNIFORMBUF_SLOT_DISPLAY);
794
795 /* TODO(fclem): remove remains of IMM. */
796 immBindShader(shader.shader);
797
798 return true;
799}
800
801void OCIOImpl::gpuDisplayShaderUnbind()
802{
804}
805
806void OCIOImpl::gpuCacheFree()
807{
808 SHADER_CACHE.clear();
809}
810
void BLI_kdtree_nd_ free(KDTree *tree)
#define UNPACK3(a)
static AppView * view
void immUnbindProgram()
void immBindShader(GPUShader *shader)
GPUShader * GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
void GPU_shader_free(GPUShader *shader)
void GPU_texture_bind(GPUTexture *texture, int unit)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
GPUTexture * GPU_texture_create_1d(const char *name, int width, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
int GPU_texture_dimensions(const GPUTexture *texture)
GPUTexture * GPU_texture_create_error(int dimension, bool array)
@ GPU_DATA_FLOAT
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_SAMPLER_EXTEND_MODE_EXTEND
void GPU_texture_update_sub(GPUTexture *texture, eGPUDataFormat data_format, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
GPUTexture * GPU_texture_create_3d(const char *name, int width, int height, int depth, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const void *data)
void GPU_texture_filter_mode(GPUTexture *texture, bool use_filter)
eGPUTextureFormat
@ GPU_RGB16F
GPUUniformBuf * GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
#define GPU_uniformbuf_create(size)
void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
void GPU_uniformbuf_free(GPUUniformBuf *ubo)
void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
Read Guarded memory(de)allocation.
struct GPUShader GPUShader
constexpr StringRef substr(int64_t start, int64_t size) const
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
format
float3 whitepoint_from_temp_tint(float temperature, float tint)
CartesianBasis invert(const CartesianBasis &basis)
float3x3 chromatic_adaption_matrix(const float3 &from_XYZ, const float3 &to_XYZ)
OCIO_ConstProcessorRcPtr * OCIO_createDisplayProcessor(OCIO_ConstConfigRcPtr *config, const char *input, const char *view, const char *display, const char *look, const float scale, const float exponent, const float temperature, const float tint, const bool use_white_balance, const bool inverse)
Definition ocio_capi.cc:253
OCIO_ConstProcessorRcPtr * OCIO_configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName)
Definition ocio_capi.cc:175
void OCIO_processorRelease(OCIO_ConstProcessorRcPtr *processor)
Definition ocio_capi.cc:182
static bool addGPULut3D(OCIO_GPUTextures &textures, const GpuShaderDescRcPtr &shader_desc, int index)
static bool createGPUCurveMapping(OCIO_GPUCurveMappping &curvemap, OCIO_CurveMappingSettings *curve_mapping_settings)
static void updateGPUDisplayParameters(OCIO_GPUShader &shader, float exponent, float4x4 scene_linear_matrix, float dither, bool use_predivide, bool use_overlay, bool use_hdr)
static bool addGPUUniform(OCIO_GPUTextures &textures, const GpuShaderDescRcPtr &shader_desc, int index)
OCIO_GPUUniformBufSlots
@ UNIFORMBUF_SLOT_CURVEMAP
@ UNIFORMBUF_SLOT_DISPLAY
@ UNIFORMBUF_SLOT_LUTS
static bool createGPUShader(OCIO_GPUShader &shader, OCIO_GPUTextures &textures, const GpuShaderDescRcPtr &shaderdesc_to_scene_linear, const GpuShaderDescRcPtr &shaderdesc_to_display, const bool use_curve_mapping)
OCIO_GPUTextureSlots
@ TEXTURE_SLOT_CURVE_MAPPING
@ TEXTURE_SLOT_OVERLAY
@ TEXTURE_SLOT_LUTS_OFFSET
@ TEXTURE_SLOT_IMAGE
static const int SHADER_CACHE_MAX_SIZE
static bool createGPUTextures(OCIO_GPUTextures &textures, const GpuShaderDescRcPtr &shaderdesc_to_scene_linear, const GpuShaderDescRcPtr &shaderdesc_to_display)
static void updateGPUCurveMapping(OCIO_GPUCurveMappping &curvemap, OCIO_CurveMappingSettings *curve_mapping_settings)
static bool addGPULut1D2D(OCIO_GPUTextures &textures, const GpuShaderDescRcPtr &shader_desc, int index)
std::list< OCIO_GPUDisplayShader > SHADER_CACHE
static void string_replace_all(std::string &haystack, const std::string &needle, const std::string &other)
static OCIO_GPUDisplayShader & getGPUDisplayShader(OCIO_ConstConfigRcPtr *config, const char *input, const char *view, const char *display, const char *look, OCIO_CurveMappingSettings *curve_mapping_settings)
unsigned int uint32_t
Definition stdint.h:80
OCIO_GPUCurveMappping curvemap
OCIO_GPUTextures textures
std::string sampler_name
GPUUniformBuf * parameters_buffer
OCIO_GPUParameters parameters
GPUTexture * dummy
std::vector< OCIO_GPUUniform > uniforms
GPUUniformBuf * uniforms_buffer
std::vector< OCIO_GPULutTexture > luts
GpuShaderDesc::UniformData data
const c_style_mat & ptr() const
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
Self & fragment_source(StringRefNull filename)
Self & vertex_in(int slot, Type type, StringRefNull name)
Self & push_constant(Type type, StringRefNull name, int array_size=0)
Self & typedef_source(StringRefNull filename)
Self & fragment_out(int slot, Type type, StringRefNull name, DualBlend blend=DualBlend::NONE, int raster_order_group=-1)
Self & vertex_out(StageInterfaceInfo &interface)
Self & vertex_source(StringRefNull filename)
Self & sampler(int slot, ImageType type, StringRefNull name, Frequency freq=Frequency::PASS, GPUSamplerState sampler=GPUSamplerState::internal_sampler())
Self & uniform_buf(int slot, StringRefNull type_name, StringRefNull name, Frequency freq=Frequency::PASS)
Self & define(StringRefNull name, StringRefNull value="")
Self & smooth(Type type, StringRefNull _name)