Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_opengl_image_textures.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005-2007 Adrian Page <adrian@pagenet.plus.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#ifdef QT_OPENGL_ES_2
10#include <qopengl.h>
11#endif
12
13#ifndef QT_OPENGL_ES_2
14#include <QOpenGLFunctions>
15#endif
16#include <QOpenGLContext>
17
18#include <QMessageBox>
19#include <QApplication>
20#include <QScreen>
21
23#include <KoColorProfile.h>
25
26#include "kis_image.h"
27#include "kis_config.h"
28#include "KisPart.h"
29#include "KisOpenGLModeProber.h"
31#include "KisOpenGLSync.h"
32#include <QVector3D>
33#include "kis_painting_tweaks.h"
36
39#if defined Q_OS_WIN && (defined QT_OPENGL_DYNAMIC || defined QT_OPENGL_ES_2_ANGLE)
40#include <EGL/egl.h>
41#include <EGL/eglext.h>
42#endif
43
44#ifdef HAVE_OPENEXR
45#include <half.h>
46#endif
47
48#ifndef GL_CLAMP_TO_EDGE
49#define GL_CLAMP_TO_EDGE 0x812F
50#endif
51
52#ifndef GL_BGRA
53#define GL_BGRA 0x80E1
54#endif
55
56// GL_EXT_texture_format_BGRA8888
57#ifndef GL_BGRA_EXT
58#define GL_BGRA_EXT 0x80E1
59#endif
60#ifndef GL_BGRA8_EXT
61#define GL_BGRA8_EXT 0x93A1
62#endif
63
64#ifndef GL_RGBA16_EXT
65#define GL_RGBA16_EXT 0x805B
66#endif
67
68//#define DEBUG_BUFFER_REALLOCATION
69
70
72 : m_image(0)
73 , m_monitorProfile(0)
74 , m_internalColorManagementActive(true)
75 , m_bufferStorage(QOpenGLBuffer::PixelUnpackBuffer)
76 , m_glFuncs(0)
77 , m_useOcio(false)
78 , m_initialized(false)
79{
80 KisConfig cfg(true);
82
86 m_useOcio = cfg.useOcio();
87}
88
90 const KoColorProfile *monitorProfile,
92 KoColorConversionTransformation::ConversionFlags conversionFlags)
93 : m_image(image)
94 , m_monitorProfile(monitorProfile)
95 , m_renderingIntent(renderingIntent)
96 , m_conversionFlags(conversionFlags)
97 , m_internalColorManagementActive(true)
98 , m_bufferStorage(QOpenGLBuffer::PixelUnpackBuffer)
99 , m_glFuncs(0)
100 , m_useOcio(false)
101 , m_initialized(false)
102{
103 Q_ASSERT(renderingIntent < 4);
104}
105
106void KisOpenGLImageTextures::initGL(QOpenGLFunctions *f)
107{
108 if (f) {
109 m_glFuncs = f;
110 } else {
111 errUI << "Tried to create OpenGLImageTextures with uninitialized QOpenGLFunctions";
112 }
113
115
116 // we use local static object for creating pools shared among
117 // different images
118 static KisTextureTileInfoPoolRegistry s_poolRegistry;
120
121 m_checkerTexture = GLuint();
122 m_glFuncs->glGenTextures(1, &(*m_checkerTexture));
124
126 recalculateCache(info, false);
127}
128
136
141
143{
144 if (useBuffer) {
145 const int numTextureBuffers = 16;
146
147 const KoColorSpace *tilesDestinationColorSpace =
149 const int pixelSize = tilesDestinationColorSpace->pixelSize();
150 const int tileSize = m_texturesInfo.width * m_texturesInfo.height * pixelSize;
151
152 m_bufferStorage.allocate(numTextureBuffers, tileSize);
153 } else {
155 }
156}
157
159 const KoColorProfile *monitorProfile,
161 KoColorConversionTransformation::ConversionFlags conversionFlags)
162{
163 return new KisOpenGLImageTextures(image, monitorProfile, renderingIntent, conversionFlags);
164}
165
167{
168
171
172 const KoColorSpace *tilesDestinationColorSpace =
174
175 if (!tilesDestinationColorSpace) {
176 qDebug() << "No destination colorspace!!!!";
177 return;
178 }
179
180
182 const int lastCol = xToCol(m_image->width());
183 const int lastRow = yToRow(m_image->height());
184
185 m_numCols = lastCol + 1;
186
187 // Default color is transparent black
188 const int pixelSize = tilesDestinationColorSpace->pixelSize();
189 QByteArray emptyTileData((m_texturesInfo.width) * (m_texturesInfo.height) * pixelSize, 0);
190
191 KisConfig config(true);
193
195
196 QOpenGLContext *ctx = QOpenGLContext::currentContext();
197 if (ctx) {
198 QOpenGLFunctions *f = ctx->functions();
199
200 m_initialized = true;
201 dbgUI << "OpenGL: creating texture tiles of size" << m_texturesInfo.height << "x" << m_texturesInfo.width;
202
203 QVector<QRectF> tileImageRect;
204 QVector<QRectF> tileTextureRect;
205
206 m_textureTiles.reserve((lastRow+1)*m_numCols);
207
208 tileImageRect.reserve(m_textureTiles.size());
209 tileTextureRect.reserve(m_textureTiles.size());
210
211 for (int row = 0; row <= lastRow; row++) {
212 for (int col = 0; col <= lastCol; col++) {
213 QRect tileRect = m_updateInfoBuilder.calculateEffectiveTileRect(col, row, m_image->bounds());
214
215 KisTextureTile *tile = new KisTextureTile(tileRect,
217 emptyTileData,
218 mode,
220 config.numMipmapLevels(),
221 f);
222 m_textureTiles.append(tile);
223 tileImageRect.append(tile->tileRectInImagePixels());
224 tileTextureRect.append(tile->tileRectInTexturePixels());
225 }
226 }
227
228
229
230 {
232 tileImageRect.size() * 6 * 3 * sizeof(float),
233 QOpenGLBuffer::StaticDraw);
234
235 QVector3D* mappedPtr = reinterpret_cast<QVector3D*>(bufferGuard.data());
236
237 Q_FOREACH (const QRectF &rc, tileImageRect) {
239 mappedPtr += 6;
240 }
241 }
242
243 {
245 tileImageRect.size() * 6 * 2 * sizeof(float),
246 QOpenGLBuffer::StaticDraw);
247
248 QVector2D* mappedPtr = reinterpret_cast<QVector2D*>(bufferGuard.data());
249
250 Q_FOREACH (const QRectF &rc, tileTextureRect) {
252 mappedPtr += 6;
253 }
254 }
255 }
256 else {
257 dbgUI << "Tried to init texture tiles without a current OpenGL Context.";
258 }
259}
260
262{
263 if (m_textureTiles.isEmpty()) return;
264
265 Q_FOREACH (KisTextureTile *tile, m_textureTiles) {
266 delete tile;
267 }
268 m_textureTiles.clear();
269 m_tileVertexBuffer.destroy();
270 m_tileTexCoordBuffer.destroy();
271 m_storedImageBounds = QRect();
272}
273
275{
276 return updateCacheImpl(rect, srcImage, true);
277}
278
283
284// TODO: add sanity checks about the conformance of the passed srcImage!
286{
287 if (!m_initialized) return new KisOpenGLUpdateInfo();
288 return m_updateInfoBuilder.buildUpdateInfo(rect, srcImage, convertColorSpace);
289}
290
291void KisOpenGLImageTextures::recalculateCache(KisUpdateInfoSP info, bool blockMipmapRegeneration)
292{
293 if (!m_initialized) {
294 dbgUI << "OpenGL: Tried to edit image texture cache before it was initialized.";
295 return;
296 }
297
298 KisOpenGLUpdateInfoSP glInfo = dynamic_cast<KisOpenGLUpdateInfo*>(info.data());
299 if(!glInfo) return;
300
301 QScopedPointer<KisOpenGLSync> sync;
302 int numProcessedTiles = 0;
303
305 Q_FOREACH (tileInfo, glInfo->tileList) {
306 KisTextureTile *tile = getTextureTileCR(tileInfo->tileCol(), tileInfo->tileRow());
308
309 if (m_bufferStorage.isValid() && numProcessedTiles > m_bufferStorage.size() &&
310 sync && !sync->isSignaled()) {
311
312#ifdef DEBUG_BUFFER_REALLOCATION
313 qDebug() << "Still unsignalled after processed" << numProcessedTiles << "tiles";
314#endif
315
317
318#ifdef DEBUG_BUFFER_REALLOCATION
319 qDebug() << " increased number of buffers to" << m_bufferStorage.size();
320#endif
321 }
322
323
324 tile->update(*tileInfo, blockMipmapRegeneration);
325
326 if (m_bufferStorage.isValid()) {
327 if (!sync) {
328 sync.reset(new KisOpenGLSync());
329 numProcessedTiles = 0;
330 } else if (sync && sync->isSignaled()) {
331 sync.reset();
332 }
333 numProcessedTiles++;
334 }
335 }
336}
337
339{
340 if (!m_initialized) {
341 return;
342 }
343
344 QOpenGLContext *ctx = QOpenGLContext::currentContext();
345 if (ctx) {
346 QOpenGLFunctions *f = ctx->functions();
347 dbgUI << "Attaching checker texture" << checkerTexture();
348 f->glBindTexture(GL_TEXTURE_2D, checkerTexture());
349
350 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
351 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
352 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
353 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
354
355 f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
356
357 QImage img = checkImage;
358 if (checkImage.width() != BACKGROUND_TEXTURE_SIZE || checkImage.height() != BACKGROUND_TEXTURE_SIZE) {
359 img = checkImage.scaled(BACKGROUND_TEXTURE_SIZE, BACKGROUND_TEXTURE_SIZE);
360 }
361
362 // convert from sRGB to display format, potentially HDR
363 const KoColorSpace *temporaryColorSpace = KoColorSpaceRegistry::instance()->rgb8();
364 const KoColorSpace *finalColorSpace =
368
369 KisFixedPaintDevice checkers(temporaryColorSpace);
370 checkers.convertFromQImage(img, temporaryColorSpace->profile()->name());
371 checkers.convertTo(finalColorSpace);
372
373 KIS_ASSERT(checkers.bounds().width() == BACKGROUND_TEXTURE_SIZE);
374 KIS_ASSERT(checkers.bounds().height() == BACKGROUND_TEXTURE_SIZE);
375
376 GLint format = m_texturesInfo.format;
377 GLint internalFormat = m_texturesInfo.internalFormat;
378 GLint type = m_texturesInfo.type;
379
380 f->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, BACKGROUND_TEXTURE_SIZE, BACKGROUND_TEXTURE_SIZE,
381 0, format, type, checkers.data());
382
383 // QPainter::drawText relies on this.
384 // Ref: https://bugreports.qt.io/browse/QTBUG-65496
385 f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
386 }
387 else {
388 dbgUI << "OpenGL: Tried to generate checker texture before OpenGL was initialized.";
389 }
390
391}
392
394{
395 if (m_glFuncs) {
396 if (!m_checkerTexture) {
397 m_checkerTexture = GLuint();
398 m_glFuncs->glGenTextures(1, &(*m_checkerTexture));
399 }
400 return *m_checkerTexture;
401 }
402 else {
403 dbgUI << "Tried to access checker texture before OpenGL was initialized";
404 return 0;
405 }
406}
407
408void KisOpenGLImageTextures::updateConfig(bool useBuffer, int NumMipmapLevels)
409{
410 if(m_textureTiles.isEmpty()) return;
411
412 const bool effectiveUseBuffer = KisOpenGL::shouldUseTextureBuffers(useBuffer);
413 initBufferStorage(effectiveUseBuffer);
414
415 Q_FOREACH (KisTextureTile *tile, m_textureTiles) {
416 tile->setBufferStorage(effectiveUseBuffer ? &m_bufferStorage : 0);
417 tile->setNumMipmapLevels(NumMipmapLevels);
418 }
419}
420
436
437void KisOpenGLImageTextures::slotImageSizeChanged(qint32 /*w*/, qint32 /*h*/)
438{
440}
441
446
451
452void KisOpenGLImageTextures::setMonitorProfile(const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
453{
454 //dbgUI << "Setting monitor profile to" << monitorProfile->name() << renderingIntent << conversionFlags;
456 m_renderingIntent = renderingIntent;
457 m_conversionFlags = conversionFlags;
458
460}
461
463{
464 Q_UNUSED(cs);
465 // TODO: implement lazy update: do not re-upload textures when not needed
466
468 return true;
469}
470
471void KisOpenGLImageTextures::setChannelFlags(const QBitArray &channelFlags)
472{
473 QBitArray targetChannelFlags = channelFlags;
474 int selectedChannels = 0;
475 const KoColorSpace *projectionCs = m_image->projection()->colorSpace();
476 const QList<KoChannelInfo*> channelInfo = projectionCs->channels();
477
478 if (targetChannelFlags.size() != channelInfo.size()) {
479 targetChannelFlags = QBitArray();
480 }
481
482 int selectedChannelIndex = -1;
483
484 for (int i = 0; i < targetChannelFlags.size(); ++i) {
485 if (targetChannelFlags.testBit(i) && channelInfo[i]->channelType() == KoChannelInfo::COLOR) {
486 selectedChannels++;
487 selectedChannelIndex = i;
488 }
489 }
490 const bool allChannelsSelected = (selectedChannels == targetChannelFlags.size());
491 const bool onlyOneChannelSelected = (selectedChannels == 1);
492
493 // OCIO has its own channel swizzling
494 if (allChannelsSelected || m_useOcio) {
495 m_updateInfoBuilder.setChannelFlags(QBitArray(), false, -1);
496 } else {
497 m_updateInfoBuilder.setChannelFlags(targetChannelFlags, onlyOneChannelSelected, selectedChannelIndex);
498 }
499}
500
505
507{
508 KisConfig cfg(true);
509
510 const GLint preferredTextureSize = cfg.openGLTextureSize();
511
512 GLint maxTextureSize;
513 if (m_glFuncs) {
514 m_glFuncs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
515 }
516 else {
517 dbgUI << "OpenGL: Tried to read texture size before OpenGL was initialized.";
518 maxTextureSize = GL_MAX_TEXTURE_SIZE;
519 }
520
521 texturesInfo->width = qMin(preferredTextureSize, maxTextureSize);
522 texturesInfo->height = qMin(preferredTextureSize, maxTextureSize);
523
524 texturesInfo->border = cfg.textureOverlapBorder();
525
526 texturesInfo->effectiveWidth = texturesInfo->width - 2 * texturesInfo->border;
527 texturesInfo->effectiveHeight = texturesInfo->height - 2 * texturesInfo->border;
528
531 QSize(texturesInfo->effectiveWidth, texturesInfo->effectiveHeight));
532}
533
538
540{
541 bool needsFinalRegeneration = m_internalColorManagementActive != value;
542
543 if (needsFinalRegeneration) {
546
547 // at this point the value of m_internalColorManagementActive might
548 // have been forcefully reverted to 'false' in case of some problems
549 }
550
551 return needsFinalRegeneration;
552}
553
554namespace {
555void initializeRGBA16FTextures(QOpenGLContext *ctx, KisGLTexturesInfo &texturesInfo, KoID &destinationColorDepthId)
556{
557 bool haveBuiltInOpenExr = false;
558#ifdef HAVE_OPENEXR
559 haveBuiltInOpenExr = true;
560#endif
561
562 if (haveBuiltInOpenExr && (KisOpenGL::hasOpenGLES() || KisOpenGL::hasOpenGL3())) {
563#ifndef QT_OPENGL_ES_2
564 texturesInfo.internalFormat = GL_RGBA16F;
565 dbgUI << "Using half (GLES or GL3)";
566 texturesInfo.type = GL_HALF_FLOAT;
567 destinationColorDepthId = Float16BitsColorDepthID;
568 dbgUI << "Pixel type half (GLES or GL3)";
569 texturesInfo.format = GL_RGBA;
570 } else if (haveBuiltInOpenExr && ctx->hasExtension("GL_ARB_half_float_pixel")) {
571 texturesInfo.internalFormat = GL_RGBA16F_ARB;
572 dbgUI << "Using ARB half";
573 texturesInfo.type = GL_HALF_FLOAT_ARB;
574 destinationColorDepthId = Float16BitsColorDepthID;
575 texturesInfo.format = GL_RGBA;
576 dbgUI << "Pixel type half";
577 } else if (haveBuiltInOpenExr && ctx->hasExtension("GL_ATI_texture_float")) {
578 texturesInfo.internalFormat = GL_RGBA_FLOAT16_ATI;
579 dbgUI << "Using ATI half";
580 texturesInfo.type = GL_HALF_FLOAT;
581 destinationColorDepthId = Float16BitsColorDepthID;
582 dbgUI << "Using half (GLES or GL3)";
583 texturesInfo.format = GL_RGBA;
584 } else {
585 texturesInfo.internalFormat = GL_RGBA32F;
586 texturesInfo.type = GL_FLOAT;
587 destinationColorDepthId = Float32BitsColorDepthID;
588 dbgUI << "Pixel type float";
589 texturesInfo.format = GL_RGBA;
590#else
591 if (ctx->format().majorVersion() >= 3) {
592 texturesInfo.internalFormat = GL_RGBA16F;
593 dbgUI << "Using half (GLES 3 non-Angle)";
594 texturesInfo.type = GL_HALF_FLOAT;
595 destinationColorDepthId = Float16BitsColorDepthID;
596 dbgUI << "Pixel type half (GLES 3 non-Angle)";
597 texturesInfo.format = GL_RGBA;
598 } else if (ctx->hasExtension("GL_OES_texture_half_float") && ctx->hasExtension("GL_EXT_color_buffer_half_float")
599 && ctx->hasExtension("GL_OES_texture_half_float_linear")) {
600 texturesInfo.internalFormat = GL_RGBA16F_EXT;
601 dbgUI << "Using half (GLES v2)";
602 texturesInfo.type = GL_HALF_FLOAT_OES;
603 destinationColorDepthId = Float16BitsColorDepthID;
604 dbgUI << "Pixel type half (GLES v2)";
605 texturesInfo.format = GL_RGBA;
606 } else if (ctx->hasExtension("GL_OES_texture_float") && (ctx->hasExtension("GL_EXT_texture_storage") || ctx->hasExtension("EXT_color_buffer_float"))
607 && ctx->hasExtension("GL_OES_texture_float_linear")) {
608 texturesInfo.internalFormat = GL_RGBA32F_EXT;
609 dbgUI << "Using float (GLES v2)";
610 texturesInfo.type = GL_FLOAT;
611 destinationColorDepthId = Float32BitsColorDepthID;
612 dbgUI << "Pixel type float (GLES v2)";
613 texturesInfo.format = GL_RGBA;
614 }
615 } else if (ctx->format().majorVersion() >= 3) {
616 texturesInfo.internalFormat = GL_RGBA32F;
617 dbgUI << "Using float (GLES 3 non-Angle)";
618 texturesInfo.type = GL_FLOAT;
619 destinationColorDepthId = Float32BitsColorDepthID;
620 dbgUI << "Pixel type float (GLES 3 non-Angle)";
621 texturesInfo.format = GL_RGBA;
622 } else if (ctx->hasExtension("GL_OES_texture_float") && (ctx->hasExtension("GL_EXT_texture_storage") || ctx->hasExtension("EXT_color_buffer_float"))
623 && ctx->hasExtension("GL_OES_texture_float_linear")) {
624 texturesInfo.internalFormat = GL_RGBA32F_EXT;
625 dbgUI << "Using float (GLES v2)";
626 texturesInfo.type = GL_FLOAT;
627 destinationColorDepthId = Float32BitsColorDepthID;
628 dbgUI << "Pixel type float (GLES v2)";
629 texturesInfo.format = GL_RGBA;
630#endif
631 }
632}
633}
634
636{
637 QOpenGLContext *ctx = QOpenGLContext::currentContext();
638 if (!(m_image && ctx)) return;
639
640 if (!KisOpenGL::hasOpenGLES()) {
641#ifndef QT_OPENGL_ES_2
643 m_texturesInfo.type = GL_UNSIGNED_BYTE;
645#else
646 KIS_ASSERT_X(false, "KisOpenGLImageTextures::updateTextureFormat",
647 "Unexpected KisOpenGL::hasOpenGLES returned false");
648#endif
649 } else {
650#ifdef QT_OPENGL_ES_2
652 m_texturesInfo.type = GL_UNSIGNED_BYTE;
653 m_texturesInfo.format = GL_RGBA;
654#else
656 m_texturesInfo.type = GL_UNSIGNED_BYTE;
658 if(!ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888"))) {
659 // The red and blue channels are swapped, but it will be re-swapped
660 // by texture swizzle mask set in KisTextureTile::setTextureParameters
662 m_texturesInfo.type = GL_UNSIGNED_BYTE;
663 m_texturesInfo.format = GL_RGBA;
664 }
665#endif
666 }
667
668 const bool useHDRMode = KisOpenGLModeProber::instance()->useHDRMode();
669 const KoID colorModelId = m_image->colorSpace()->colorModelId();
670 const KoID colorDepthId = useHDRMode ? Float16BitsColorDepthID : m_image->colorSpace()->colorDepthId();
671
672 KoID destinationColorModelId = RGBAColorModelID;
673 KoID destinationColorDepthId = Integer8BitsColorDepthID;
674
675 dbgUI << "Choosing texture format:";
676
677 if (colorModelId == RGBAColorModelID) {
678 if (colorDepthId == Float16BitsColorDepthID) {
679 initializeRGBA16FTextures(ctx, m_texturesInfo, destinationColorDepthId);
680 }
681 else if (colorDepthId == Float32BitsColorDepthID) {
683#ifndef QT_OPENGL_ES_2
684 m_texturesInfo.internalFormat = GL_RGBA32F;
685 dbgUI << "Using float (GLES or GL3)";
686 m_texturesInfo.type = GL_FLOAT;
687 m_texturesInfo.format = GL_RGBA;
688 destinationColorDepthId = Float32BitsColorDepthID;
689 } else if (ctx->hasExtension("GL_ARB_texture_float")) {
690 m_texturesInfo.internalFormat = GL_RGBA32F_ARB;
691 dbgUI << "Using ARB float";
692 m_texturesInfo.type = GL_FLOAT;
693 m_texturesInfo.format = GL_RGBA;
694 destinationColorDepthId = Float32BitsColorDepthID;
695 } else if (ctx->hasExtension("GL_ATI_texture_float")) {
696 m_texturesInfo.internalFormat = GL_RGBA_FLOAT32_ATI;
697 dbgUI << "Using ATI float";
698 m_texturesInfo.type = GL_FLOAT;
699 m_texturesInfo.format = GL_RGBA;
700 destinationColorDepthId = Float32BitsColorDepthID;
701#else
702 if (ctx->format().majorVersion() >= 3) {
703 m_texturesInfo.internalFormat = GL_RGBA32F;
704 dbgUI << "Using float (GLES 3 non-Angle)";
705 m_texturesInfo.type = GL_FLOAT;
706 m_texturesInfo.format = GL_RGBA;
707 destinationColorDepthId = Float32BitsColorDepthID;
708 /* GL_EXT_texture_storage is GLES 2*/
709 /* GL_EXT_color_buffer_float is GLES 3*/
710 } else if (ctx->hasExtension("GL_OES_texture_float")
711 && (ctx->hasExtension("GL_EXT_texture_storage") || ctx->hasExtension("EXT_color_buffer_float"))
712 && ctx->hasExtension("GL_OES_texture_float_linear")) {
713 m_texturesInfo.internalFormat = GL_RGBA32F_EXT;
714 dbgUI << "Using float (GLES v2)";
715 m_texturesInfo.type = GL_FLOAT;
716 m_texturesInfo.format = GL_RGBA;
717 destinationColorDepthId = Float32BitsColorDepthID;
718 }
719#endif
720 }
721 }
722 else if (colorDepthId == Integer16BitsColorDepthID) {
723 if (!KisOpenGL::hasOpenGLES()) {
724#ifndef QT_OPENGL_ES_2
725 m_texturesInfo.internalFormat = GL_RGBA16;
726 m_texturesInfo.type = GL_UNSIGNED_SHORT;
727
728 // On arm M1, GL_BGRA format is not aligned properly at the driver
729 // changing the pixel format fixes the rendering problem when using
730 // texture buffers
731 // BUG: 445561
732#ifdef Q_OS_MACOS
733 m_texturesInfo.format = GL_RGBA;
734#else
736#endif
737 destinationColorDepthId = Integer16BitsColorDepthID;
738 dbgUI << "Using 16 bits rgba";
739#else
740 KIS_ASSERT_X(false,
741 "KisOpenGLCanvas2::updateTextureFormat",
742 "Unexpected KisOpenGL::hasOpenGLES returned false");
743#endif
744 } else {
745#ifdef EGL_ANGLE_platform_angle
746 // If OpenGL ES, fall back to 16-bit float -- supports HDR
747 // Angle does ship GL_EXT_texture_norm16 but it doesn't seem
748 // to be renderable by DXGI - it returns a pixel size of 0
749 initializeRGBA16FTextures(ctx, m_texturesInfo, destinationColorDepthId);
750#else
751 if (ctx->hasExtension("GL_EXT_texture_norm16")) {
753 m_texturesInfo.type = GL_UNSIGNED_SHORT;
754 m_texturesInfo.format = GL_RGBA;
755 destinationColorDepthId = Integer16BitsColorDepthID;
756 dbgUI << "Using 16 bits rgba (GLES v2)";
757 }
758#endif
759 }
760 }
761 }
762 else {
763 // We will convert the colorspace to 16 bits rgba, instead of 8 bits
764 if (colorDepthId == Integer16BitsColorDepthID) {
765 if (!KisOpenGL::hasOpenGLES()) {
766#ifndef QT_OPENGL_ES_2
767 m_texturesInfo.internalFormat = GL_RGBA16;
768 m_texturesInfo.type = GL_UNSIGNED_SHORT;
769 // On arm M1, GL_BGRA format is not aligned properly at the driver
770 // changing the pixel format fixes the rendering problem when using
771 // texture buffers
772 // BUG: 445561
773#ifdef Q_OS_MACOS
774 m_texturesInfo.format = GL_RGBA;
775#else
777#endif
778 destinationColorDepthId = Integer16BitsColorDepthID;
779 dbgUI << "Using conversion to 16 bits rgba";
780#else
781 KIS_ASSERT_X(false, "KisOpenGLCanvas2::updateTextureFormat",
782 "Unexpected KisOpenGL::hasOpenGLES returned false");
783#endif
784 } else {
785#ifdef EGL_ANGLE_platform_angle
786 // If OpenGL ES, fall back to 16-bit float -- supports HDR
787 // Angle does ship GL_EXT_texture_norm16 but it doesn't seem
788 // to be renderable by DXGI - it returns a pixel size of 0
789 initializeRGBA16FTextures(ctx, m_texturesInfo, destinationColorDepthId);
790#else
791 if (ctx->hasExtension("GL_EXT_texture_norm16")) {
793 m_texturesInfo.type = GL_UNSIGNED_SHORT;
794 m_texturesInfo.format = GL_RGBA;
795 destinationColorDepthId = Integer16BitsColorDepthID;
796 dbgUI << "Using conversion to 16 bits rgba (GLES v2)";
797 }
798#endif
799 }
800 } else if (colorDepthId == Float16BitsColorDepthID) {
801 initializeRGBA16FTextures(ctx, m_texturesInfo, destinationColorDepthId);
802 }
803 }
804
806 colorModelId != destinationColorModelId) {
807
808 KisConfig cfg(false);
810
811 if (cm != KisConfig::INTERNAL) {
813 i18n("OpenColorIO is disabled: image color space is not supported"), 5000, true);
814 }
815
816 warnUI << "WARNING: Internal color management was forcibly enabled";
817 warnUI << "Color Management Mode: " << cm;
819 warnUI << ppVar(destinationColorModelId);
820 warnUI << ppVar(destinationColorDepthId);
821
824 }
825
826 const KoColorProfile *profile =
828 colorModelId != destinationColorModelId ?
830
836 const KoColorSpace *tilesDestinationColorSpace =
837 KoColorSpaceRegistry::instance()->colorSpace(destinationColorModelId.id(),
838 destinationColorDepthId.id(),
839 profile);
840
842 ConversionOptions(tilesDestinationColorSpace,
845}
846
float value(const T *src, size_t ch)
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
bool useOcio(bool defaultValue=false) const
OcioColorManagementMode ocioColorManagementMode(bool defaultValue=false) const
int openGLFilteringMode(bool defaultValue=false) const
bool allowLCMSOptimization(bool defaultValue=false) const
int numMipmapLevels(bool defaultValue=false) const
int textureOverlapBorder() const
qint32 monitorRenderIntent(bool defaultValue=false) const
int openGLTextureSize(bool defaultValue=false) const
bool useOpenGLTextureBuffer(bool defaultValue=false) const
OcioColorManagementMode
Definition kis_config.h:471
void setOcioColorManagementMode(OcioColorManagementMode mode) const
bool useBlackPointCompensation(bool defaultValue=false) const
virtual void convertFromQImage(const QImage &image, const QString &srcProfileName)
void convertTo(const KoColorSpace *dstColorSpace=0, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags())
const KoColorSpace * colorSpace() const
KisPaintDeviceSP projection() const
qint32 width() const
qint32 height() const
QRect bounds() const override
bool setInternalColorManagementActive(bool value)
KisOpenGLUpdateInfoSP updateCache(const QRect &rect, KisImageSP srcImage)
void generateCheckerTexture(const QImage &checkImage)
KisOpenGLBufferCircularStorage m_bufferStorage
void sigShowFloatingMessage(const QString &message, int timeout, bool priority)
const KoColorProfile * monitorProfile()
void initGL(QOpenGLFunctions *f)
void slotImageSizeChanged(qint32 w, qint32 h)
KoColorConversionTransformation::ConversionFlags m_conversionFlags
void updateConfig(bool useBuffer, int NumMipmapLevels)
void recalculateCache(KisUpdateInfoSP info, bool blockMipmapRegeneration)
KisOpenGLUpdateInfoSP updateCacheImpl(const QRect &rect, KisImageSP srcImage, bool convertColorSpace)
KoColorConversionTransformation::Intent m_renderingIntent
bool setImageColorSpace(const KoColorSpace *cs)
KisOpenGLUpdateInfoSP updateCacheNoConversion(const QRect &rect)
static KisOpenGLImageTexturesSP createImageTextures(KisImageWSP image, const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
QVector< KisTextureTile * > m_textureTiles
boost::optional< GLuint > m_checkerTexture
void setChannelFlags(const QBitArray &channelFlags)
const KoColorProfile * m_monitorProfile
KisTextureTile * getTextureTileCR(int col, int row)
KisOpenGLUpdateInfoBuilder & updateInfoBuilder()
KisOpenGLUpdateInfoBuilder m_updateInfoBuilder
void setMonitorProfile(const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
void getTextureSize(KisGLTexturesInfo *texturesInfo)
void setProofingConfig(KisProofingConfigurationSP)
static KisOpenGLModeProber * instance()
KisTextureTileUpdateInfoSPList tileList
static bool hasOpenGLES()
static bool shouldUseTextureBuffers(bool userPreference)
static bool hasOpenGL3()
const KoColorSpace * colorSpace() const
KisTextureTileInfoPoolSP getPool(int tileWidth, int tileHeight)
void setNumMipmapLevels(int num)
QRect tileRectInImagePixels()
QRectF tileRectInTexturePixels()
void update(const KisTextureTileUpdateInfo &updateInfo, bool blockMipmapRegeneration)
void setBufferStorage(KisOpenGLBufferCircularStorage *bufferStorage)
@ COLOR
The channel represents a color.
virtual quint32 pixelSize() const =0
QList< KoChannelInfo * > channels
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define KIS_ASSERT_X(cond, where, what)
Definition kis_assert.h:40
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
#define errUI
Definition kis_debug.h:114
#define dbgUI
Definition kis_debug.h:52
#define ppVar(var)
Definition kis_debug.h:155
#define warnUI
Definition kis_debug.h:94
#define GL_BGRA
#define GL_RGBA16_EXT
#define GL_BGRA8_EXT
#define GL_BGRA_EXT
QSharedPointer< T > toQShared(T *ptr)
void rectToTexCoords(QVector2D *texCoords, const QRectF &rc)
void rectToVertices(QVector3D *vertices, const QRectF &rc)
KoColorConversionTransformation::ConversionFlags m_conversionFlags
const KoColorSpace * m_destinationColorSpace
KoColorConversionTransformation::Intent m_renderingIntent
void allocate(int numBuffers, int bufferSize)
void setChannelFlags(const QBitArray &channelFrags, bool onlyOneChannelSelected, int selectedChannelIndex)
QRect calculateEffectiveTileRect(int col, int row, const QRect &imageBounds) const
KisOpenGLUpdateInfoSP buildUpdateInfo(const QRect &rect, KisImageSP srcImage, bool convertColorSpace)
void setProofingConfig(KisProofingConfigurationSP config)
void setConversionOptions(const ConversionOptions &options)
const KoColorSpace * destinationColorSpace() const
void setEffectiveTextureSize(const QSize &size)
void setTextureInfoPool(KisTextureTileInfoPoolSP pool)
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())