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>
23#include <QOpenGLVersionFunctions>
34#if defined(QT_OPENGL_ES_2)
35#define GL_RGBA32F_ARB GL_RGBA32F_EXT
36#define GL_RGB32F_ARB GL_RGB32F_EXT
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
49 , inputColorSpaceName(0)
54 , m_interface(interface)
76 OCIO::PackedImageDesc img(
reinterpret_cast<float *
>(pixels), numPixels, 1, 4);
79 for (quint32 i = 0; i < numPixels; i++) {
93 OCIO::PackedImageDesc img(
reinterpret_cast<float *
>(pixels), numPixels, 1, 4);
96 for (quint32 i = 0; i < numPixels; i++) {
108 if (numPixels > 16) {
110 OCIO::PackedImageDesc img(
reinterpret_cast<float *
>(pixels), numPixels, 1, 4);
113 for (quint32 i = 0; i < numPixels; i++) {
166 OCIO::DisplayViewTransformRcPtr transform = OCIO::DisplayViewTransform::Create();
169 transform->setView(
view);
171 OCIO::LegacyViewingPipelineRcPtr vpt = OCIO::LegacyViewingPipeline::Create();
173 vpt->setDisplayViewTransform(transform);
192 vpt->setLooksOverride(
look);
193 vpt->setLooksOverrideEnabled(
true);
196 OCIO::GroupTransformRcPtr approximateTransform = OCIO::GroupTransform::Create();
200 const double exposureGain = pow(2.0,
exposure);
202 const double minRange = 0.001;
210 const double newMin[] = {0.0, 0.0, 0.0, 0.0};
211 const double newMax[] = {exposureGain, exposureGain, exposureGain, 1.0};
215 OCIO::MatrixTransform::Fit(m44, offset4, oldMin, oldMax, newMin, newMax);
216 OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create();
218 mtx->setOffset(offset4);
219 vpt->setLinearCC(mtx);
222 approximateTransform->appendTransform(mtx);
267 config->getDefaultLumaCoefs(lumacoef);
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);
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);
286 approximateTransform->appendTransform(expTransform);
293 }
catch (OCIO::Exception &e) {
295 errKrita <<
"OCIO exception while parsing the current context:" << e.what();
307 warnKrita <<
"OCIO inverted matrix does not exist!";
317 QOpenGLContext *ctx = QOpenGLContext::currentContext();
321 if (ctx->format().majorVersion() >= 3) {
322 QOpenGLExtraFunctions *
f = ctx->extraFunctions();
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();
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";
339#if defined(QT_OPENGL_3)
341#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
342 QOpenGLFunctions_3_2_Core *
f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
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()));
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>();
360 QOpenGLFunctions_3_0 *
f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_0>();
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()));
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()));
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>();
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()));
401 if (!cfg.useOpenGL())
408 qWarning() <<
"Failed to get valid OpenGL functions for OcioDisplayFilter!";
412 f->initializeOpenGLFunctions();
414 bool shouldRecompileShader =
false;
417 OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc();
419#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
421 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_3_0);
423 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_1_0);
427 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3);
429 shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_2);
433 shaderDesc->setFunctionName(
"OCIODisplay");
434 shaderDesc->setResourcePrefix(
"ocio_");
437#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
440 const auto gpu =
m_processor->getOptimizedGPUProcessor(OCIO::OptimizationFlags::OPTIMIZATION_DEFAULT);
442 const int lut3DEdgeSize = cfg.ocioLutEdgeSize();
444 m_processor->getOptimizedLegacyGPUProcessor(OCIO::OptimizationFlags::OPTIMIZATION_DEFAULT, lut3DEdgeSize);
447 gpu->extractGpuShaderInfo(shaderDesc);
461 f->glDeleteTextures(1, &tex.m_uid);
467 unsigned currIndex = 1;
471 const unsigned maxTexture3D = shaderDesc->getNum3DTextures();
472 for (
unsigned idx = 0; idx < maxTexture3D; ++idx) {
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);
481 if (!textureName || !*textureName || !samplerName || !*samplerName || edgelen == 0) {
482 errOpenGL <<
"The texture data is corrupted";
486 const float *values =
nullptr;
487 shaderDesc->get3DTextureValues(idx, values);
489 errOpenGL <<
"The texture values are missing";
497 if (values ==
nullptr) {
498 errOpenGL <<
"3D LUT" << idx <<
"Missing texture data";
502 f->glGenTextures(1, &texId);
504 f->glActiveTexture(GL_TEXTURE0 + currIndex);
506 f->glBindTexture(GL_TEXTURE_3D, texId);
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);
513 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
514 f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
522 f->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F_ARB, edgelen, edgelen, edgelen, 0, GL_RGB, GL_FLOAT, values);
527 m_lut3dTexIDs.push_back({texId, textureName, samplerName, GL_TEXTURE_3D});
534 const unsigned maxTexture2D = shaderDesc->getNumTextures();
535 for (
unsigned idx = 0; idx < maxTexture2D; ++idx) {
538 const char *textureName =
nullptr;
539 const char *samplerName =
nullptr;
542 OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL;
543 OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
545#if OCIO_VERSION_HEX >= 0x2030000
546 OCIO::GpuShaderCreator::TextureDimensions dimensions;
547 shaderDesc->getTexture(idx, textureName, samplerName, width, height, channel, dimensions, interpolation);
549 shaderDesc->getTexture(idx, textureName, samplerName, width, height, channel, interpolation);
552 if (!textureName || !*textureName || !samplerName || !*samplerName || width == 0) {
553 errOpenGL <<
"The texture data is corrupted";
557 const float *values =
nullptr;
558 shaderDesc->getTextureValues(idx, values);
560 errOpenGL <<
"The texture values are missing";
568 if (values ==
nullptr) {
569 errOpenGL <<
"1D LUT" << idx <<
"Missing texture data.";
573 unsigned internalformat = GL_RGB32F_ARB;
574 unsigned format = GL_RGB;
576 if (channel == OCIO::GpuShaderCreator::TEXTURE_RED_CHANNEL) {
577 internalformat = GL_R32F;
581 f->glGenTextures(1, &texId);
583 f->glActiveTexture(GL_TEXTURE0 + currIndex);
585#if OCIO_VERSION_HEX >= 0x2010100 || OCIO_VERSION_HEX >= 0x2020000
591 f->glBindTexture(GL_TEXTURE_2D, texId);
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);
598 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
599 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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
611 errOpenGL <<
"1D texture detected @" << idx <<
", not supported by OpenGLES";
619 unsigned type = GL_TEXTURE_2D;
620 m_lut3dTexIDs.push_back({texId, textureName, samplerName, type});
625 QString shaderCacheID = QString::fromLatin1(shaderDesc->getCacheID());
631 m_program = QString::fromLatin1(
"%1\n").arg(shaderDesc->getShaderText());
632 shouldRecompileShader =
true;
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";
651 return shouldRecompileShader;
656 for (
unsigned int idx = 0; idx <
m_lut3dTexIDs.size(); ++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));
664 const int m_handle =
program->uniformLocation(uniform.m_name);
666 const OCIO::GpuShaderDesc::UniformData &m_data = uniform.m_data;
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(),
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());
686 errOpenGL <<
"Uniform" << uniform.m_name <<
"is not linked to any value";
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()
std::vector< KisTextureUniform > m_lut3dUniforms
void setupTextures(GLFunctions *f, QOpenGLShaderProgram *program) const override
void approximateInverseTransformation(quint8 *pixels, quint32 numPixels) override
bool updateShaderImpl(F *f)
OCIO::ConstConfigRcPtr config
OCIO::ConstCPUProcessorRcPtr m_reverseApproximationProcessorCPU
const char * displayDevice
OCIO::ConstProcessorRcPtr m_processor
KisExposureGammaCorrectionInterface * m_interface
bool m_lockCurrentColorVisualRepresentation
const char * inputColorSpaceName
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
bool forceInternalColorManagement
OCIO::ConstCPUProcessorRcPtr m_forwardApproximationProcessorCPU
void filter(quint8 *pixels, quint32 numPixels) override
bool updateShader() 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)
const char * name(StandardAction id)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)