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
48 : KisDisplayFilter(parent)
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
64
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
125
130
135
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 bool shouldRecompileShader = false;
413
414 // Step 1: Create a GPU Shader Description
415 OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc();
416
417#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
419 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_3_0);
420 } else {
421 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_1_0);
422 }
423#else
425 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3);
426 } else {
427 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_2);
428 }
429#endif
430
431 shaderDesc->setFunctionName("OCIODisplay");
432 shaderDesc->setResourcePrefix("ocio_");
433
434 // Step 2: Compute the 3D LUT
435#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
436 // ensure the new GPU pipeline is used with our GLES3 patch
437 // this way users won't run into errors when using Angle along with OCIO
438 const auto gpu = m_processor->getOptimizedGPUProcessor(OCIO::OptimizationFlags::OPTIMIZATION_DEFAULT);
439#else
440 const int lut3DEdgeSize = cfg.ocioLutEdgeSize();
441 const auto gpu =
442 m_processor->getOptimizedLegacyGPUProcessor(OCIO::OptimizationFlags::OPTIMIZATION_DEFAULT, lut3DEdgeSize);
443#endif
444
445 gpu->extractGpuShaderInfo(shaderDesc);
446
447 // OCIO v2 assumes you'll use the OglApp helpers
448 // these are unusable from a Qt backend, because they rely on GLUT/GLFW
449 // ociodisplay original pipeline:
450 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/508b3f4a0618435aeed2f45058208bdfa99e0887/src/apps/ociodisplay/main.cpp
451 // ociodisplay new pipeline is a single call:
452 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/ffddc3341f5775c7866fe2c93275e1d5e0b0540f/src/apps/ociodisplay/main.cpp#L427
453 // we need to replicate this loop:
454 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/dd59baf555656e09f52c3838e85ccf154497ec1d/src/libutils/oglapphelpers/oglapp.cpp#L191-L223
455 // calls functions from here:
456 // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/dd59baf555656e09f52c3838e85ccf154497ec1d/src/libutils/oglapphelpers/glsl.cpp
457
458 for (const auto &tex : m_lut3dTexIDs) {
459 f->glDeleteTextures(1, &tex.m_uid);
460 }
461
462 m_lut3dTexIDs.clear();
463
464 // This is the first available index for the textures.
465 unsigned currIndex = 1;
466
467 // Process the 3D LUT first.
468
469 const unsigned maxTexture3D = shaderDesc->getNum3DTextures();
470 for (unsigned idx = 0; idx < maxTexture3D; ++idx) {
471 // 1. Get the information of the 3D LUT.
472
473 const char *textureName = nullptr;
474 const char *samplerName = nullptr;
475 unsigned edgelen = 0;
476 OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
477 shaderDesc->get3DTexture(idx, textureName, samplerName, edgelen, interpolation);
478
479 if (!textureName || !*textureName || !samplerName || !*samplerName || edgelen == 0) {
480 errOpenGL << "The texture data is corrupted";
481 return false;
482 }
483
484 const float *values = nullptr;
485 shaderDesc->get3DTextureValues(idx, values);
486 if (!values) {
487 errOpenGL << "The texture values are missing";
488 return false;
489 }
490
491 // 2. Allocate the 3D LUT.
492
493 unsigned texId = 0;
494 {
495 if (values == nullptr) {
496 errOpenGL << "3D LUT" << idx << "Missing texture data";
497 return false;
498 }
499
500 f->glGenTextures(1, &texId);
501
502 f->glActiveTexture(GL_TEXTURE0 + currIndex);
503
504 f->glBindTexture(GL_TEXTURE_3D, texId);
505
506 {
507 if (interpolation == OCIO::INTERP_NEAREST) {
508 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
509 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
510 } else {
511 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
512 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
513 }
514
515 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
516 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
517 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
518 }
519
520 f->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F_ARB, edgelen, edgelen, edgelen, 0, GL_RGB, GL_FLOAT, values);
521 }
522
523 // 3. Keep the texture id & name for the later enabling.
524
525 m_lut3dTexIDs.push_back({texId, textureName, samplerName, GL_TEXTURE_3D});
526
527 currIndex++;
528 }
529
530 // Process the 1D LUTs.
531
532 const unsigned maxTexture2D = shaderDesc->getNumTextures();
533 for (unsigned idx = 0; idx < maxTexture2D; ++idx) {
534 // 1. Get the information of the 1D LUT.
535
536 const char *textureName = nullptr;
537 const char *samplerName = nullptr;
538 unsigned width = 0;
539 unsigned height = 0;
540 OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL;
541 OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
542
543#if OCIO_VERSION_HEX >= 0x2030000
544 OCIO::GpuShaderCreator::TextureDimensions dimensions;
545 shaderDesc->getTexture(idx, textureName, samplerName, width, height, channel, dimensions, interpolation);
546#else
547 shaderDesc->getTexture(idx, textureName, samplerName, width, height, channel, interpolation);
548#endif
549
550 if (!textureName || !*textureName || !samplerName || !*samplerName || width == 0) {
551 errOpenGL << "The texture data is corrupted";
552 return false;
553 }
554
555 const float *values = nullptr;
556 shaderDesc->getTextureValues(idx, values);
557 if (!values) {
558 errOpenGL << "The texture values are missing";
559 return false;
560 }
561
562 // 2. Allocate the 1D LUT (a 2D texture is needed to hold large LUTs).
563
564 unsigned texId = 0;
565 {
566 if (values == nullptr) {
567 errOpenGL << "1D LUT" << idx << "Missing texture data.";
568 return false;
569 }
570
571 unsigned internalformat = GL_RGB32F_ARB;
572 unsigned format = GL_RGB;
573
574 if (channel == OCIO::GpuShaderCreator::TEXTURE_RED_CHANNEL) {
575 internalformat = GL_R32F;
576 format = GL_RED;
577 }
578
579 f->glGenTextures(1, &texId);
580
581 f->glActiveTexture(GL_TEXTURE0 + currIndex);
582
583#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
584#else
585 // 1D Textures are unsupported by OpenGL ES.
586 // https://github.com/AcademySoftwareFoundation/OpenColorIO/issues/1486
587 if (height > 1) {
588#endif
589 f->glBindTexture(GL_TEXTURE_2D, texId);
590
591 {
592 if (interpolation == OCIO::INTERP_NEAREST) {
593 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
594 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
595 } else {
596 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
597 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
598 }
599
600 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
601 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
602 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
603 }
604
605 f->glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, GL_FLOAT, values);
606#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
607#else
608 } else {
609 errOpenGL << "1D texture detected @" << idx << ", not supported by OpenGLES";
610 return false;
611 }
612#endif
613 }
614
615 // 3. Keep the texture id & name for the later enabling.
616
617 unsigned type = GL_TEXTURE_2D;
618 m_lut3dTexIDs.push_back({texId, textureName, samplerName, type});
619 currIndex++;
620 }
621
622 // Step 3: Generate the shader text
623 QString shaderCacheID = QString::fromLatin1(shaderDesc->getCacheID());
624 if (m_program.isEmpty() || shaderCacheID != m_shadercacheid) {
625 // dbgKrita << "Computing Shader " << m_shadercacheid;
626
627 m_shadercacheid = shaderCacheID;
628
629 m_program = QString::fromLatin1("%1\n").arg(shaderDesc->getShaderText());
630 shouldRecompileShader = true;
631 }
632
633 // Step 4: mirror and bind uniforms
634 m_lut3dUniforms.clear();
635
636 const unsigned maxUniforms = shaderDesc->getNumUniforms();
637 for (unsigned idx = 0; idx < maxUniforms; ++idx) {
638 OCIO::GpuShaderDesc::UniformData data;
639 const char *name = shaderDesc->getUniform(idx, data);
640 if (data.m_type == OCIO::UNIFORM_UNKNOWN) {
641 errOpenGL << "Uniform" << idx << "has an unknown type";
642 return false;
643 }
644 // Transfer uniform.
645 m_lut3dUniforms.push_back({name, data});
646 }
647
648 m_shaderDirty = false;
649 return shouldRecompileShader;
650}
651
652void OcioDisplayFilter::setupTextures(GLFunctions *f, QOpenGLShaderProgram *program) const
653{
654 for (unsigned int idx = 0; idx < m_lut3dTexIDs.size(); ++idx) {
655 const auto &data = m_lut3dTexIDs[idx];
656 f->glActiveTexture(GL_TEXTURE0 + 1 + idx);
657 f->glBindTexture(data.m_type, data.m_uid);
658 program->setUniformValue(program->uniformLocation(data.m_samplerName), GLint(1 + idx));
659 }
660
661 for (const KisTextureUniform &uniform : m_lut3dUniforms) {
662 const int m_handle = program->uniformLocation(uniform.m_name);
663
664 const OCIO::GpuShaderDesc::UniformData &m_data = uniform.m_data;
665
666 // Update value.
667 if (m_data.m_getDouble) {
668 program->setUniformValue(m_handle, static_cast<GLfloat>(m_data.m_getDouble()));
669 } else if (m_data.m_getBool) {
670 program->setUniformValue(m_handle, static_cast<GLfloat>(m_data.m_getBool() ? 1.0f : 0.0f));
671 } else if (m_data.m_getFloat3) {
672 program->setUniformValue(m_handle,
673 m_data.m_getFloat3()[0],
674 m_data.m_getFloat3()[1],
675 m_data.m_getFloat3()[2]);
676 } else if (m_data.m_vectorFloat.m_getSize && m_data.m_vectorFloat.m_getVector) {
677 program->setUniformValueArray(m_handle,
678 m_data.m_vectorFloat.m_getVector(),
679 m_data.m_vectorFloat.m_getSize(),
680 1);
681 } else if (m_data.m_vectorInt.m_getSize && m_data.m_vectorInt.m_getVector) {
682 program->setUniformValueArray(m_handle, m_data.m_vectorInt.m_getVector(), m_data.m_vectorInt.m_getSize());
683 } else {
684 errOpenGL << "Uniform" << uniform.m_name << "is not linked to any value";
685 continue;
686 }
687 }
688}
float value(const T *src, size_t ch)
int ocioLutEdgeSize(bool defaultValue=false) const
bool useOpenGL(bool defaultValue=false) const
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
void approximateForwardTransformation(quint8 *pixels, quint32 numPixels) override
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
KisExposureGammaCorrectionInterface * m_interface
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