14#include <QOpenGLFunctions>
16#include <QOpenGLContext>
19#include <QApplication>
39#if defined Q_OS_WIN && (defined QT_OPENGL_DYNAMIC || defined QT_OPENGL_ES_2_ANGLE)
41#include <EGL/eglext.h>
48#ifndef GL_CLAMP_TO_EDGE
49#define GL_CLAMP_TO_EDGE 0x812F
58#define GL_BGRA_EXT 0x80E1
61#define GL_BGRA8_EXT 0x93A1
65#define GL_RGBA16_EXT 0x805B
74 , m_internalColorManagementActive(true)
75 , m_bufferStorage(QOpenGLBuffer::PixelUnpackBuffer)
78 , m_initialized(false)
92 KoColorConversionTransformation::ConversionFlags conversionFlags)
94 , m_monitorProfile(monitorProfile)
95 , m_renderingIntent(renderingIntent)
96 , m_conversionFlags(conversionFlags)
97 , m_internalColorManagementActive(true)
98 , m_bufferStorage(QOpenGLBuffer::PixelUnpackBuffer)
101 , m_initialized(false)
103 Q_ASSERT(renderingIntent < 4);
111 errUI <<
"Tried to create OpenGLImageTextures with uninitialized QOpenGLFunctions";
145 const int numTextureBuffers = 16;
149 const int pixelSize = tilesDestinationColorSpace->
pixelSize();
161 KoColorConversionTransformation::ConversionFlags conversionFlags)
175 if (!tilesDestinationColorSpace) {
176 qDebug() <<
"No destination colorspace!!!!";
188 const int pixelSize = tilesDestinationColorSpace->
pixelSize();
196 QOpenGLContext *ctx = QOpenGLContext::currentContext();
198 QOpenGLFunctions *f = ctx->functions();
211 for (
int row = 0; row <= lastRow; row++) {
212 for (
int col = 0; col <= lastCol; col++) {
232 tileImageRect.size() * 6 * 3 *
sizeof(
float),
233 QOpenGLBuffer::StaticDraw);
235 QVector3D* mappedPtr =
reinterpret_cast<QVector3D*
>(bufferGuard.
data());
237 Q_FOREACH (
const QRectF &rc, tileImageRect) {
245 tileImageRect.size() * 6 * 2 *
sizeof(
float),
246 QOpenGLBuffer::StaticDraw);
248 QVector2D* mappedPtr =
reinterpret_cast<QVector2D*
>(bufferGuard.
data());
250 Q_FOREACH (
const QRectF &rc, tileTextureRect) {
257 dbgUI <<
"Tried to init texture tiles without a current OpenGL Context.";
294 dbgUI <<
"OpenGL: Tried to edit image texture cache before it was initialized.";
301 QScopedPointer<KisOpenGLSync> sync;
302 int numProcessedTiles = 0;
305 Q_FOREACH (tileInfo, glInfo->
tileList) {
310 sync && !sync->isSignaled()) {
312#ifdef DEBUG_BUFFER_REALLOCATION
313 qDebug() <<
"Still unsignalled after processed" << numProcessedTiles <<
"tiles";
318#ifdef DEBUG_BUFFER_REALLOCATION
324 tile->
update(*tileInfo, blockMipmapRegeneration);
329 numProcessedTiles = 0;
330 }
else if (sync && sync->isSignaled()) {
344 QOpenGLContext *ctx = QOpenGLContext::currentContext();
346 QOpenGLFunctions *f = ctx->functions();
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);
355 f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
357 QImage img = checkImage;
381 0, format, type, checkers.
data());
385 f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
388 dbgUI <<
"OpenGL: Tried to generate checker texture before OpenGL was initialized.";
403 dbgUI <<
"Tried to access checker texture before OpenGL was initialized";
473 QBitArray targetChannelFlags = channelFlags;
474 int selectedChannels = 0;
478 if (targetChannelFlags.size() != channelInfo.size()) {
479 targetChannelFlags = QBitArray();
482 int selectedChannelIndex = -1;
484 for (
int i = 0; i < targetChannelFlags.size(); ++i) {
487 selectedChannelIndex = i;
490 const bool allChannelsSelected = (selectedChannels == targetChannelFlags.size());
491 const bool onlyOneChannelSelected = (selectedChannels == 1);
512 GLint maxTextureSize;
514 m_glFuncs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
517 dbgUI <<
"OpenGL: Tried to read texture size before OpenGL was initialized.";
518 maxTextureSize = GL_MAX_TEXTURE_SIZE;
521 texturesInfo->
width = qMin(preferredTextureSize, maxTextureSize);
522 texturesInfo->
height = qMin(preferredTextureSize, maxTextureSize);
543 if (needsFinalRegeneration) {
551 return needsFinalRegeneration;
555void initializeRGBA16FTextures(QOpenGLContext *ctx,
KisGLTexturesInfo &texturesInfo,
KoID &destinationColorDepthId)
557 bool haveBuiltInOpenExr =
false;
559 haveBuiltInOpenExr =
true;
563#ifndef QT_OPENGL_ES_2
565 dbgUI <<
"Using half (GLES or GL3)";
566 texturesInfo.
type = GL_HALF_FLOAT;
568 dbgUI <<
"Pixel type half (GLES or GL3)";
569 texturesInfo.
format = GL_RGBA;
570 }
else if (haveBuiltInOpenExr && ctx->hasExtension(
"GL_ARB_half_float_pixel")) {
572 dbgUI <<
"Using ARB half";
573 texturesInfo.
type = GL_HALF_FLOAT_ARB;
575 texturesInfo.
format = GL_RGBA;
576 dbgUI <<
"Pixel type half";
577 }
else if (haveBuiltInOpenExr && ctx->hasExtension(
"GL_ATI_texture_float")) {
579 dbgUI <<
"Using ATI half";
580 texturesInfo.
type = GL_HALF_FLOAT;
582 dbgUI <<
"Using half (GLES or GL3)";
583 texturesInfo.
format = GL_RGBA;
586 texturesInfo.
type = GL_FLOAT;
588 dbgUI <<
"Pixel type float";
589 texturesInfo.
format = GL_RGBA;
591 if (ctx->format().majorVersion() >= 3) {
593 dbgUI <<
"Using half (GLES 3 non-Angle)";
594 texturesInfo.
type = GL_HALF_FLOAT;
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")) {
601 dbgUI <<
"Using half (GLES v2)";
602 texturesInfo.
type = GL_HALF_FLOAT_OES;
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")) {
609 dbgUI <<
"Using float (GLES v2)";
610 texturesInfo.
type = GL_FLOAT;
612 dbgUI <<
"Pixel type float (GLES v2)";
613 texturesInfo.
format = GL_RGBA;
615 }
else if (ctx->format().majorVersion() >= 3) {
617 dbgUI <<
"Using float (GLES 3 non-Angle)";
618 texturesInfo.
type = GL_FLOAT;
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")) {
625 dbgUI <<
"Using float (GLES v2)";
626 texturesInfo.
type = GL_FLOAT;
628 dbgUI <<
"Pixel type float (GLES v2)";
629 texturesInfo.
format = GL_RGBA;
637 QOpenGLContext *ctx = QOpenGLContext::currentContext();
641#ifndef QT_OPENGL_ES_2
646 KIS_ASSERT_X(
false,
"KisOpenGLImageTextures::updateTextureFormat",
647 "Unexpected KisOpenGL::hasOpenGLES returned false");
658 if(!ctx->hasExtension(QByteArrayLiteral(
"GL_EXT_texture_format_BGRA8888"))) {
675 dbgUI <<
"Choosing texture format:";
679 initializeRGBA16FTextures(ctx,
m_texturesInfo, destinationColorDepthId);
683#ifndef QT_OPENGL_ES_2
685 dbgUI <<
"Using float (GLES or GL3)";
689 }
else if (ctx->hasExtension(
"GL_ARB_texture_float")) {
691 dbgUI <<
"Using ARB float";
695 }
else if (ctx->hasExtension(
"GL_ATI_texture_float")) {
697 dbgUI <<
"Using ATI float";
702 if (ctx->format().majorVersion() >= 3) {
704 dbgUI <<
"Using float (GLES 3 non-Angle)";
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")) {
714 dbgUI <<
"Using float (GLES v2)";
724#ifndef QT_OPENGL_ES_2
738 dbgUI <<
"Using 16 bits rgba";
741 "KisOpenGLCanvas2::updateTextureFormat",
742 "Unexpected KisOpenGL::hasOpenGLES returned false");
745#ifdef EGL_ANGLE_platform_angle
749 initializeRGBA16FTextures(ctx,
m_texturesInfo, destinationColorDepthId);
751 if (ctx->hasExtension(
"GL_EXT_texture_norm16")) {
756 dbgUI <<
"Using 16 bits rgba (GLES v2)";
766#ifndef QT_OPENGL_ES_2
779 dbgUI <<
"Using conversion to 16 bits rgba";
781 KIS_ASSERT_X(
false,
"KisOpenGLCanvas2::updateTextureFormat",
782 "Unexpected KisOpenGL::hasOpenGLES returned false");
785#ifdef EGL_ANGLE_platform_angle
789 initializeRGBA16FTextures(ctx,
m_texturesInfo, destinationColorDepthId);
791 if (ctx->hasExtension(
"GL_EXT_texture_norm16")) {
796 dbgUI <<
"Using conversion to 16 bits rgba (GLES v2)";
801 initializeRGBA16FTextures(ctx,
m_texturesInfo, destinationColorDepthId);
806 colorModelId != destinationColorModelId) {
813 i18n(
"OpenColorIO is disabled: image color space is not supported"), 5000,
true);
816 warnUI <<
"WARNING: Internal color management was forcibly enabled";
817 warnUI <<
"Color Management Mode: " << cm;
828 colorModelId != destinationColorModelId ?
838 destinationColorDepthId.
id(),
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
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
QRect bounds() const override
QOpenGLBuffer m_tileTexCoordBuffer
bool setInternalColorManagementActive(bool value)
static const int BACKGROUND_TEXTURE_SIZE
void destroyImageTextureTiles()
KisOpenGLUpdateInfoSP updateCache(const QRect &rect, KisImageSP srcImage)
void generateCheckerTexture(const QImage &checkImage)
QOpenGLFunctions * m_glFuncs
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)
QRect m_storedImageBounds
KoColorConversionTransformation::ConversionFlags m_conversionFlags
bool internalColorManagementActive() const
void updateConfig(bool useBuffer, int NumMipmapLevels)
void recalculateCache(KisUpdateInfoSP info, bool blockMipmapRegeneration)
void initBufferStorage(bool useBuffer)
KisOpenGLUpdateInfoSP updateCacheImpl(const QRect &rect, KisImageSP srcImage, bool convertColorSpace)
KoColorConversionTransformation::Intent m_renderingIntent
bool setImageColorSpace(const KoColorSpace *cs)
QOpenGLBuffer m_tileVertexBuffer
KisOpenGLUpdateInfoSP updateCacheNoConversion(const QRect &rect)
static KisOpenGLImageTexturesSP createImageTextures(KisImageWSP image, const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
QVector< KisTextureTile * > m_textureTiles
bool m_internalColorManagementActive
boost::optional< GLuint > m_checkerTexture
void setChannelFlags(const QBitArray &channelFlags)
const KoColorProfile * m_monitorProfile
KisTextureTile * getTextureTileCR(int col, int row)
void testingForceInitialized()
KisOpenGLUpdateInfoBuilder & updateInfoBuilder()
KisOpenGLUpdateInfoBuilder m_updateInfoBuilder
void setMonitorProfile(const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
void getTextureSize(KisGLTexturesInfo *texturesInfo)
void updateTextureFormat()
KisGLTexturesInfo m_texturesInfo
void setProofingConfig(KisProofingConfigurationSP)
void recreateImageTextureTiles()
virtual ~KisOpenGLImageTextures()
static KisOpenGLModeProber * instance()
KisTextureTileUpdateInfoSPList tileList
static bool hasOpenGLES()
static bool shouldUseTextureBuffers(bool userPreference)
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
#define KIS_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_X(cond, where, what)
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 allocateMoreBuffers()
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)
void setTextureBorder(int value)
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())