Krita Source Code Documentation
Loading...
Searching...
No Matches
ocio_display_filter_vfx2021.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2012 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
9
10#include <QMessageBox>
11#include <QOpenGLContext>
12#include <QOpenGLExtraFunctions>
13#include <QOpenGLFunctions_2_0>
14#include <QOpenGLFunctions_3_0>
15#include <QOpenGLFunctions_3_2_Core>
16#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
17#include <QOpenGLVersionFunctionsFactory>
18#include <QOpenGLFunctions_3_0>
19#include <QOpenGLFunctions_3_1>
20#include <QOpenGLFunctions_3_2_Core>
21#include <QOpenGLFunctions_2_0>
22#else
23#include <QOpenGLVersionFunctions>
24#endif
25
26#include <cmath>
27#include <cstring>
28
29#include <kis_config.h>
30#include <kis_debug.h>
31#include <opengl/kis_opengl.h>
32#include <qsurface.h>
33
34#if defined(QT_OPENGL_ES_2)
35#define GL_RGBA32F_ARB GL_RGBA32F_EXT
36#define GL_RGB32F_ARB GL_RGB32F_EXT
37#endif
38
39#if defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_3)
40#define GL_R32F GL_R32F_EXT
41#define GL_RED GL_RED_EXT
42#define GL_TEXTURE_WRAP_R GL_TEXTURE_WRAP_R_OES
43#endif
44
46
49 , inputColorSpaceName(0)
50 , displayDevice(0)
51 , view(0)
52 , look(0)
53 , swizzle(RGBA)
54 , m_interface(interface)
55 , m_lut3dTexIDs()
56 , m_lut3dUniforms()
57 , m_shaderDirty(true)
58{
59}
60
62{
63}
64
66{
67 return m_interface;
68}
69
70void OcioDisplayFilter::filter(quint8 *pixels, quint32 numPixels)
71{
72 // processes that data _in_ place
73 if (m_processor) {
74 if (numPixels > 16) {
75 // creation of PackedImageDesc is really slow on Windows due to malloc/free
76 OCIO::PackedImageDesc img(reinterpret_cast<float *>(pixels), numPixels, 1, 4);
77 m_processorCPU->apply(img);
78 } else {
79 for (quint32 i = 0; i < numPixels; i++) {
80 m_processorCPU->applyRGBA(reinterpret_cast<float*>(pixels));
81 pixels+=4;
82 }
83 }
84 }
85}
86
87void OcioDisplayFilter::approximateInverseTransformation(quint8 *pixels, quint32 numPixels)
88{
89 // processes that data _in_ place
91 if (numPixels > 16) {
92 // creation of PackedImageDesc is really slow on Windows due to malloc/free
93 OCIO::PackedImageDesc img(reinterpret_cast<float *>(pixels), numPixels, 1, 4);
95 } else {
96 for (quint32 i = 0; i < numPixels; i++) {
97 m_reverseApproximationProcessorCPU->applyRGBA(reinterpret_cast<float*>(pixels));
98 pixels+=4;
99 }
100 }
101 }
102}
103
104void OcioDisplayFilter::approximateForwardTransformation(quint8 *pixels, quint32 numPixels)
105{
106 // processes that data _in_ place
108 if (numPixels > 16) {
109 // creation of PackedImageDesc is really slow on Windows due to malloc/free
110 OCIO::PackedImageDesc img(reinterpret_cast<float *>(pixels), numPixels, 1, 4);
112 } else {
113 for (quint32 i = 0; i < numPixels; i++) {
114 m_forwardApproximationProcessorCPU->applyRGBA(reinterpret_cast<float*>(pixels));
115 pixels+=4;
116 }
117 }
118 }
119}
120
122{
124}
125
127{
129}
130
132{
134}
135
136QString OcioDisplayFilter::program() const
137{
138 return m_program;
139}
140
142{
143 if (!config) {
144 return;
145 }
146
147 if (!displayDevice) {
148 displayDevice = config->getDefaultDisplay();
149 }
150
151 if (!view) {
152 view = config->getDefaultView(displayDevice);
153 }
154
155 if (!inputColorSpaceName) {
156 inputColorSpaceName = config->getColorSpaceNameByIndex(0);
157 }
158 if (!look) {
159 look = config->getLookNameByIndex(0);
160 }
161
163 return;
164 }
165
166 OCIO::DisplayViewTransformRcPtr transform = OCIO::DisplayViewTransform::Create();
167 transform->setSrc(inputColorSpaceName);
168 transform->setDisplay(displayDevice);
169 transform->setView(view);
170
171 OCIO::LegacyViewingPipelineRcPtr vpt = OCIO::LegacyViewingPipeline::Create();
172
173 vpt->setDisplayViewTransform(transform);
174
191 if (config->getLook(look)) {
192 vpt->setLooksOverride(look);
193 vpt->setLooksOverrideEnabled(true);
194 }
195
196 OCIO::GroupTransformRcPtr approximateTransform = OCIO::GroupTransform::Create();
197
198 // fstop exposure control -- not sure how that translates to our exposure
199 {
200 const double exposureGain = pow(2.0, exposure);
201
202 const double minRange = 0.001;
203 if (qAbs(blackPoint - whitePoint) < minRange) {
204 whitePoint = blackPoint + minRange;
205 }
206
207 const double oldMin[] = {blackPoint, blackPoint, blackPoint, 0.0};
208 const double oldMax[] = {whitePoint, whitePoint, whitePoint, 1.0};
209
210 const double newMin[] = {0.0, 0.0, 0.0, 0.0};
211 const double newMax[] = {exposureGain, exposureGain, exposureGain, 1.0};
212
213 double m44[16];
214 double offset4[4];
215 OCIO::MatrixTransform::Fit(m44, offset4, oldMin, oldMax, newMin, newMax);
216 OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create();
217 mtx->setMatrix(m44);
218 mtx->setOffset(offset4);
219 vpt->setLinearCC(mtx);
220
221 // approximation (no color correction);
222 approximateTransform->appendTransform(mtx);
223 }
224
225 // channel swizzle
226 {
227 int channelHot[4];
228 switch (swizzle) {
229 case LUMINANCE:
230 channelHot[0] = 1;
231 channelHot[1] = 1;
232 channelHot[2] = 1;
233 channelHot[3] = 0;
234 break;
235 case RGBA:
236 channelHot[0] = 1;
237 channelHot[1] = 1;
238 channelHot[2] = 1;
239 channelHot[3] = 1;
240 break;
241 case R:
242 channelHot[0] = 1;
243 channelHot[1] = 0;
244 channelHot[2] = 0;
245 channelHot[3] = 0;
246 break;
247 case G:
248 channelHot[0] = 0;
249 channelHot[1] = 1;
250 channelHot[2] = 0;
251 channelHot[3] = 0;
252 break;
253 case B:
254 channelHot[0] = 0;
255 channelHot[1] = 0;
256 channelHot[2] = 1;
257 channelHot[3] = 0;
258 break;
259 case A:
260 channelHot[0] = 0;
261 channelHot[1] = 0;
262 channelHot[2] = 0;
263 channelHot[3] = 1;
264 default:;
265 }
266 double lumacoef[3];
267 config->getDefaultLumaCoefs(lumacoef);
268 double m44[16];
269 double offset[4];
270 OCIO::MatrixTransform::View(m44, offset, channelHot, lumacoef);
271 OCIO::MatrixTransformRcPtr swizzleTransform = OCIO::MatrixTransform::Create();
272 swizzleTransform->setMatrix(m44);
273 swizzleTransform->setOffset(offset);
274 vpt->setChannelView(swizzleTransform);
275 }
276
277 // Post-display transform gamma
278 {
279 double exponent = 1.0 / std::max(1e-6, gamma);
280 const double exponent4f[] = {exponent, exponent, exponent, exponent};
281 OCIO::ExponentTransformRcPtr expTransform = OCIO::ExponentTransform::Create();
282 expTransform->setValue(exponent4f);
283 vpt->setDisplayCC(expTransform);
284
285 // approximation (no color correction);
286 approximateTransform->appendTransform(expTransform);
287 }
288
289 try {
291 m_processor = vpt->getProcessor(config, config->getCurrentContext());
292 m_processorCPU = m_processor->getDefaultCPUProcessor();
293 } catch (OCIO::Exception &e) {
294 // XXX: How to not break the OCIO shader now?
295 errKrita << "OCIO exception while parsing the current context:" << e.what();
296 m_shaderDirty = false;
297 return;
298 }
299
300 m_forwardApproximationProcessor = config->getProcessor(approximateTransform, OCIO::TRANSFORM_DIR_FORWARD);
302
303 try {
304 m_reverseApproximationProcessor = config->getProcessor(approximateTransform, OCIO::TRANSFORM_DIR_INVERSE);
306 } catch (...) {
307 warnKrita << "OCIO inverted matrix does not exist!";
308 // m_reverseApproximationProcessor;
309 }
310
311 m_shaderDirty = true;
312}
313
315{
317 QOpenGLContext *ctx = QOpenGLContext::currentContext();
318
320
321 if (ctx->format().majorVersion() >= 3) {
322 QOpenGLExtraFunctions *f = ctx->extraFunctions();
323 if (f) {
324 return updateShaderImpl(f);
325 }
326 } else if (ctx->hasExtension("GL_OES_texture_float")
327 && (ctx->hasExtension("GL_EXT_texture_storage") || ctx->hasExtension("EXT_color_buffer_float"))
328 && ctx->hasExtension("GL_OES_texture_float_linear")) {
329 QOpenGLExtraFunctions *f = ctx->extraFunctions();
330 if (f) {
331 return updateShaderImpl(f);
332 }
333 } else {
334 dbgKrita << "OcioDisplayFilter::updateShader"
335 << "OpenGL ES v2+ support detected but no OES_texture_float,"
336 "GL_EXT_color_buffer_float or GL_EXT_texture_storage, or GL_OES_texture_float_linear were found";
337 return false;
338 }
339#if defined(QT_OPENGL_3)
340 } else if (KisOpenGL::hasOpenGL3()) {
341#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
342 QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
343#else
344 QOpenGLVersionProfile profile(QOpenGLContext::currentContext()->surface()->format());
345 profile.setVersion(3,2);
346 QOpenGLFunctions_3_2_Core *f = reinterpret_cast<QOpenGLFunctions_3_2_Core *>(QOpenGLVersionFunctionsFactory::get(profile, QOpenGLContext::currentContext()));
347#endif
348 if (f) {
349 return updateShaderImpl(f);
350 }
351#endif
352 }
353
355#if defined(QT_OPENGL_3)
356#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
357#if defined(Q_OS_MAC) && defined(QT_OPENGL_3_2)
358 QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
359#else
360 QOpenGLFunctions_3_0 *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_0>();
361#endif
362#else
363#if defined(Q_OS_MAC) && defined(QT_OPENGL_3_2)
364 QOpenGLVersionProfile profile(QOpenGLContext::currentContext()->surface()->format());
365 profile.setVersion(3,2);
366 QOpenGLFunctions_3_2_Core *f = reinterpret_cast<QOpenGLFunctions_3_2_Core *>(QOpenGLVersionFunctionsFactory::get(profile, QOpenGLContext::currentContext()));
367#else
368 QOpenGLVersionProfile profile(QOpenGLContext::currentContext()->surface()->format());
369 profile.setVersion(3,0);
370 QOpenGLFunctions_3_0 *f = reinterpret_cast<QOpenGLFunctions_3_0 *>(QOpenGLVersionFunctionsFactory::get(profile, QOpenGLContext::currentContext()));
371#endif
372
373#endif
374 if (f) {
375 return updateShaderImpl(f);
376 }
377#endif
378 }
379#if !defined(QT_OPENGL_ES_2)
380#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
381 QOpenGLFunctions_2_0 *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_2_0>();
382#else
383 QOpenGLVersionProfile profile(QOpenGLContext::currentContext()->surface()->format());
384 profile.setVersion(2,0);
385 QOpenGLFunctions_2_0 *f = reinterpret_cast<QOpenGLFunctions_2_0 *>(QOpenGLVersionFunctionsFactory::get(profile, QOpenGLContext::currentContext()));
386#endif
387 if (f) {
388 return updateShaderImpl(f);
389 }
390#endif
391
392 return false;
393}
394
395template<class F>
397{
398 // check whether we are allowed to use shaders -- though that should
399 // work for everyone these days
400 KisConfig cfg(true);
401 if (!cfg.useOpenGL())
402 return false;
403
404 if (!m_shaderDirty)
405 return false;
406
407 if (!f) {
408 qWarning() << "Failed to get valid OpenGL functions for OcioDisplayFilter!";
409 return false;
410 }
411
412 f->initializeOpenGLFunctions();
413
414 bool shouldRecompileShader = false;
415
416 // Step 1: Create a GPU Shader Description
417 OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc();
418
419#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
421 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_3_0);
422 } else {
423 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_1_0);
424 }
425#else
427 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3);
428 } else {
429 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_2);
430 }
431#endif
432
433 shaderDesc->setFunctionName("OCIODisplay");
434 shaderDesc->setResourcePrefix("ocio_");
435
436 // Step 2: Compute the 3D LUT
437#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
438 // ensure the new GPU pipeline is used with our GLES3 patch
439 // this way users won't run into errors when using Angle along with OCIO
440 const auto gpu = m_processor->getOptimizedGPUProcessor(OCIO::OptimizationFlags::OPTIMIZATION_DEFAULT);
441#else
442 const int lut3DEdgeSize = cfg.ocioLutEdgeSize();
443 const auto gpu =
444 m_processor->getOptimizedLegacyGPUProcessor(OCIO::OptimizationFlags::OPTIMIZATION_DEFAULT, lut3DEdgeSize);
445#endif
446
447 gpu->extractGpuShaderInfo(shaderDesc);
448
449 // OCIO v2 assumes you'll use the OglApp helpers
450 // these are unusable from a Qt backend, because they rely on GLUT/GLFW
451 // ociodisplay original pipeline:
452 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/508b3f4a0618435aeed2f45058208bdfa99e0887/src/apps/ociodisplay/main.cpp
453 // ociodisplay new pipeline is a single call:
454 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/ffddc3341f5775c7866fe2c93275e1d5e0b0540f/src/apps/ociodisplay/main.cpp#L427
455 // we need to replicate this loop:
456 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/dd59baf555656e09f52c3838e85ccf154497ec1d/src/libutils/oglapphelpers/oglapp.cpp#L191-L223
457 // calls functions from here:
458 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/dd59baf555656e09f52c3838e85ccf154497ec1d/src/libutils/oglapphelpers/glsl.cpp
459
460 for (const auto &tex : m_lut3dTexIDs) {
461 f->glDeleteTextures(1, &tex.m_uid);
462 }
463
464 m_lut3dTexIDs.clear();
465
466 // This is the first available index for the textures.
467 unsigned currIndex = 1;
468
469 // Process the 3D LUT first.
470
471 const unsigned maxTexture3D = shaderDesc->getNum3DTextures();
472 for (unsigned idx = 0; idx < maxTexture3D; ++idx) {
473 // 1. Get the information of the 3D LUT.
474
475 const char *textureName = nullptr;
476 const char *samplerName = nullptr;
477 unsigned edgelen = 0;
478 OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
479 shaderDesc->get3DTexture(idx, textureName, samplerName, edgelen, interpolation);
480
481 if (!textureName || !*textureName || !samplerName || !*samplerName || edgelen == 0) {
482 errOpenGL << "The texture data is corrupted";
483 return false;
484 }
485
486 const float *values = nullptr;
487 shaderDesc->get3DTextureValues(idx, values);
488 if (!values) {
489 errOpenGL << "The texture values are missing";
490 return false;
491 }
492
493 // 2. Allocate the 3D LUT.
494
495 unsigned texId = 0;
496 {
497 if (values == nullptr) {
498 errOpenGL << "3D LUT" << idx << "Missing texture data";
499 return false;
500 }
501
502 f->glGenTextures(1, &texId);
503
504 f->glActiveTexture(GL_TEXTURE0 + currIndex);
505
506 f->glBindTexture(GL_TEXTURE_3D, texId);
507
508 {
509 if (interpolation == OCIO::INTERP_NEAREST) {
510 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
511 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
512 } else {
513 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
514 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
515 }
516
517 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
518 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
519 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
520 }
521
522 f->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F_ARB, edgelen, edgelen, edgelen, 0, GL_RGB, GL_FLOAT, values);
523 }
524
525 // 3. Keep the texture id & name for the later enabling.
526
527 m_lut3dTexIDs.push_back({texId, textureName, samplerName, GL_TEXTURE_3D});
528
529 currIndex++;
530 }
531
532 // Process the 1D LUTs.
533
534 const unsigned maxTexture2D = shaderDesc->getNumTextures();
535 for (unsigned idx = 0; idx < maxTexture2D; ++idx) {
536 // 1. Get the information of the 1D LUT.
537
538 const char *textureName = nullptr;
539 const char *samplerName = nullptr;
540 unsigned width = 0;
541 unsigned height = 0;
542 OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL;
543 OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
544
545#if OCIO_VERSION_HEX >= 0x2030000
546 OCIO::GpuShaderCreator::TextureDimensions dimensions;
547 shaderDesc->getTexture(idx, textureName, samplerName, width, height, channel, dimensions, interpolation);
548#else
549 shaderDesc->getTexture(idx, textureName, samplerName, width, height, channel, interpolation);
550#endif
551
552 if (!textureName || !*textureName || !samplerName || !*samplerName || width == 0) {
553 errOpenGL << "The texture data is corrupted";
554 return false;
555 }
556
557 const float *values = nullptr;
558 shaderDesc->getTextureValues(idx, values);
559 if (!values) {
560 errOpenGL << "The texture values are missing";
561 return false;
562 }
563
564 // 2. Allocate the 1D LUT (a 2D texture is needed to hold large LUTs).
565
566 unsigned texId = 0;
567 {
568 if (values == nullptr) {
569 errOpenGL << "1D LUT" << idx << "Missing texture data.";
570 return false;
571 }
572
573 unsigned internalformat = GL_RGB32F_ARB;
574 unsigned format = GL_RGB;
575
576 if (channel == OCIO::GpuShaderCreator::TEXTURE_RED_CHANNEL) {
577 internalformat = GL_R32F;
578 format = GL_RED;
579 }
580
581 f->glGenTextures(1, &texId);
582
583 f->glActiveTexture(GL_TEXTURE0 + currIndex);
584
585#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
586#else
587 // 1D Textures are unsupported by OpenGL ES.
588 // https://github.com/AcademySoftwareFoundation/OpenColorIO/issues/1486
589 if (height > 1) {
590#endif
591 f->glBindTexture(GL_TEXTURE_2D, texId);
592
593 {
594 if (interpolation == OCIO::INTERP_NEAREST) {
595 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
596 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
597 } else {
598 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
599 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
600 }
601
602 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
603 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
604 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
605 }
606
607 f->glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, GL_FLOAT, values);
608#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
609#else
610 } else {
611 errOpenGL << "1D texture detected @" << idx << ", not supported by OpenGLES";
612 return false;
613 }
614#endif
615 }
616
617 // 3. Keep the texture id & name for the later enabling.
618
619 unsigned type = GL_TEXTURE_2D;
620 m_lut3dTexIDs.push_back({texId, textureName, samplerName, type});
621 currIndex++;
622 }
623
624 // Step 3: Generate the shader text
625 QString shaderCacheID = QString::fromLatin1(shaderDesc->getCacheID());
626 if (m_program.isEmpty() || shaderCacheID != m_shadercacheid) {
627 // dbgKrita << "Computing Shader " << m_shadercacheid;
628
629 m_shadercacheid = shaderCacheID;
630
631 m_program = QString::fromLatin1("%1\n").arg(shaderDesc->getShaderText());
632 shouldRecompileShader = true;
633 }
634
635 // Step 4: mirror and bind uniforms
636 m_lut3dUniforms.clear();
637
638 const unsigned maxUniforms = shaderDesc->getNumUniforms();
639 for (unsigned idx = 0; idx < maxUniforms; ++idx) {
640 OCIO::GpuShaderDesc::UniformData data;
641 const char *name = shaderDesc->getUniform(idx, data);
642 if (data.m_type == OCIO::UNIFORM_UNKNOWN) {
643 errOpenGL << "Uniform" << idx << "has an unknown type";
644 return false;
645 }
646 // Transfer uniform.
647 m_lut3dUniforms.push_back({name, data});
648 }
649
650 m_shaderDirty = false;
651 return shouldRecompileShader;
652}
653
654void OcioDisplayFilter::setupTextures(GLFunctions *f, QOpenGLShaderProgram *program) const
655{
656 for (unsigned int idx = 0; idx < m_lut3dTexIDs.size(); ++idx) {
657 const auto &data = m_lut3dTexIDs[idx];
658 f->glActiveTexture(GL_TEXTURE0 + 1 + idx);
659 f->glBindTexture(data.m_type, data.m_uid);
660 program->setUniformValue(program->uniformLocation(data.m_samplerName), GLint(1 + idx));
661 }
662
663 for (const KisTextureUniform &uniform : m_lut3dUniforms) {
664 const int m_handle = program->uniformLocation(uniform.m_name);
665
666 const OCIO::GpuShaderDesc::UniformData &m_data = uniform.m_data;
667
668 // Update value.
669 if (m_data.m_getDouble) {
670 program->setUniformValue(m_handle, static_cast<GLfloat>(m_data.m_getDouble()));
671 } else if (m_data.m_getBool) {
672 program->setUniformValue(m_handle, static_cast<GLfloat>(m_data.m_getBool() ? 1.0f : 0.0f));
673 } else if (m_data.m_getFloat3) {
674 program->setUniformValue(m_handle,
675 m_data.m_getFloat3()[0],
676 m_data.m_getFloat3()[1],
677 m_data.m_getFloat3()[2]);
678 } else if (m_data.m_vectorFloat.m_getSize && m_data.m_vectorFloat.m_getVector) {
679 program->setUniformValueArray(m_handle,
680 m_data.m_vectorFloat.m_getVector(),
681 m_data.m_vectorFloat.m_getSize(),
682 1);
683 } else if (m_data.m_vectorInt.m_getSize && m_data.m_vectorInt.m_getVector) {
684 program->setUniformValueArray(m_handle, m_data.m_vectorInt.m_getVector(), m_data.m_vectorInt.m_getSize());
685 } else {
686 errOpenGL << "Uniform" << uniform.m_name << "is not linked to any value";
687 continue;
688 }
689 }
690}
float value(const T *src, size_t ch)
The KisDisplayFilter class is the base class for filters that are applied by the canvas to the projec...
static bool hasOpenGLES()
static bool supportsLoD()
static bool hasOpenGL3()
std::vector< KisTextureUniform > m_lut3dUniforms
void setupTextures(GLFunctions *f, QOpenGLShaderProgram *program) const override
void approximateInverseTransformation(quint8 *pixels, quint32 numPixels) override
OCIO::ConstConfigRcPtr config
OCIO::ConstCPUProcessorRcPtr m_reverseApproximationProcessorCPU
OCIO::ConstProcessorRcPtr m_processor
KisExposureGammaCorrectionInterface * m_interface
void approximateForwardTransformation(quint8 *pixels, quint32 numPixels) override
virtual QString program() const override
OCIO_CHANNEL_SWIZZLE swizzle
OCIO::ConstProcessorRcPtr m_reverseApproximationProcessor
bool lockCurrentColorVisualRepresentation() const override
OCIO::ConstCPUProcessorRcPtr m_processorCPU
OcioDisplayFilter(KisExposureGammaCorrectionInterface *interface, QObject *parent=0)
OCIO::ConstProcessorRcPtr m_forwardApproximationProcessor
OCIO::ConstCPUProcessorRcPtr m_forwardApproximationProcessorCPU
void filter(quint8 *pixels, quint32 numPixels) override
bool useInternalColorManagement() const override
KisExposureGammaCorrectionInterface * correctionInterface() const override
void setLockCurrentColorVisualRepresentation(bool value)
std::vector< KisTextureEntry > m_lut3dTexIDs
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define dbgKrita
Definition kis_debug.h:45
#define errKrita
Definition kis_debug.h:107
#define warnKrita
Definition kis_debug.h:87
#define errOpenGL
Definition kis_debug.h:122
#define GL_CLAMP_TO_EDGE
const char * name(StandardAction id)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327