kis_opengl_image_textures.cpp 22.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 *  Copyright (c) 2005-2007 Adrian Page <adrian@pagenet.plus.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

19
#include "opengl/kis_opengl_image_textures.h"
20

Michael Abrahams's avatar
Michael Abrahams committed
21 22
#include <QOpenGLFunctions>
#include <QOpenGLContext>
23

Boudewijn Rempt's avatar
Boudewijn Rempt committed
24
#include <QMessageBox>
25 26
#include <QApplication>
#include <QDesktopWidget>
27

28
#include <KoColorSpaceRegistry.h>
29 30
#include <KoColorProfile.h>
#include <KoColorModelStandardIds.h>
31 32 33

#include "kis_image.h"
#include "kis_config.h"
34
#include "KisPart.h"
35 36 37 38

#ifdef HAVE_OPENEXR
#include <half.h>
#endif
39

40 41 42 43 44 45 46 47
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif

#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif

48 49 50 51

KisOpenGLImageTextures::ImageTexturesMap KisOpenGLImageTextures::imageTexturesMap;

KisOpenGLImageTextures::KisOpenGLImageTextures()
52 53
    : m_image(0)
    , m_monitorProfile(0)
54 55 56
    , m_proofingConfig(0)
    , m_proofingTransform(0)
    , m_createNewProofingTransform(true)
57 58
    , m_tilesDestinationColorSpace(0)
    , m_internalColorManagementActive(true)
59
    , m_checkerTexture(0)
60
    , m_glFuncs(0)
Boudewijn Rempt's avatar
Boudewijn Rempt committed
61
    , m_allChannelsSelected(true)
62
    , m_useOcio(false)
63
    , m_initialized(false)
64
{
65
    KisConfig cfg;
66
    m_renderingIntent = (KoColorConversionTransformation::Intent)cfg.monitorRenderIntent();
67 68

    m_conversionFlags = KoColorConversionTransformation::HighQuality;
69 70
    if (cfg.useBlackPointCompensation()) m_conversionFlags |= KoColorConversionTransformation::BlackpointCompensation;
    if (!cfg.allowLCMSOptimization()) m_conversionFlags |= KoColorConversionTransformation::NoOptimization;
71
    m_useOcio = cfg.useOcio();
72 73
}

74
KisOpenGLImageTextures::KisOpenGLImageTextures(KisImageWSP image,
75
                                               const KoColorProfile *monitorProfile,
76 77
                                               KoColorConversionTransformation::Intent renderingIntent,
                                               KoColorConversionTransformation::ConversionFlags conversionFlags)
78 79 80 81
    : m_image(image)
    , m_monitorProfile(monitorProfile)
    , m_renderingIntent(renderingIntent)
    , m_conversionFlags(conversionFlags)
82 83
    , m_proofingConfig(0)
    , m_proofingTransform(0)
84
    , m_tilesDestinationColorSpace(0)
85
    , m_createNewProofingTransform(true)
86
    , m_internalColorManagementActive(true)
87
    , m_checkerTexture(0)
88
    , m_glFuncs(0)
89 90
    , m_allChannelsSelected(true)
    , m_useOcio(false)
91
    , m_initialized(false)
92
{
93
    Q_ASSERT(renderingIntent < 4);
94
}
95

96 97
void KisOpenGLImageTextures::initGL(QOpenGLFunctions *f)
{
Michael Abrahams's avatar
Michael Abrahams committed
98 99 100
    if (f) {
        m_glFuncs = f;
    } else {
101
        errUI << "Tried to create OpenGLImageTextures with uninitialized QOpenGLFunctions";
Michael Abrahams's avatar
Michael Abrahams committed
102
    }
103

104 105
    getTextureSize(&m_texturesInfo);
    m_glFuncs->glGenTextures(1, &m_checkerTexture);
106 107
    createImageTextureTiles();

108 109
    KisOpenGLUpdateInfoSP info = updateCache(m_image->bounds());
    recalculateCache(info);
110 111 112 113 114 115
}

KisOpenGLImageTextures::~KisOpenGLImageTextures()
{
    ImageTexturesMap::iterator it = imageTexturesMap.find(m_image);
    if (it != imageTexturesMap.end()) {
116
        KisOpenGLImageTextures *textures = it.value();
117
        if (textures == this) {
Boudewijn Rempt's avatar
Boudewijn Rempt committed
118
            dbgUI << "Removing shared image context from map";
119
            imageTexturesMap.erase(it);
120 121
        }
    }
122

123
    destroyImageTextureTiles();
124
    m_glFuncs->glDeleteTextures(1, &m_checkerTexture);
125 126
}

127 128 129 130 131
KisImageSP KisOpenGLImageTextures::image() const
{
    return m_image;
}

132
bool KisOpenGLImageTextures::imageCanShareTextures()
133
{
134
    KisConfig cfg;
135 136 137 138 139 140 141 142 143
    if (cfg.useOcio()) return false;
    if (KisPart::instance()->mainwindowCount() == 1) return true;
    if (qApp->desktop()->screenCount() == 1) return true;
    for (int i = 1; i < qApp->desktop()->screenCount(); i++) {
        if (cfg.displayProfile(i) != cfg.displayProfile(i - 1)) {
            return false;
        }
    }
    return true;
144 145
}

146
KisOpenGLImageTexturesSP KisOpenGLImageTextures::getImageTextures(KisImageWSP image,
147
                                                                  const KoColorProfile *monitorProfile,
148 149
                                                                  KoColorConversionTransformation::Intent renderingIntent,
                                                                  KoColorConversionTransformation::ConversionFlags conversionFlags)
150
{
151 152
    // Disabled until we figure out why we're deleting the shared textures on closing the second view on a single image
    if (false && imageCanShareTextures()) {
153 154 155
        ImageTexturesMap::iterator it = imageTexturesMap.find(image);

        if (it != imageTexturesMap.end()) {
156
            KisOpenGLImageTexturesSP textures = it.value();
157
            textures->setMonitorProfile(monitorProfile, renderingIntent, conversionFlags);
158 159 160

            return textures;
        } else {
161
            KisOpenGLImageTextures *imageTextures = new KisOpenGLImageTextures(image, monitorProfile, renderingIntent, conversionFlags);
162
            imageTexturesMap[image] = imageTextures;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
163
            dbgUI << "Added shareable textures to map";
164 165 166 167

            return imageTextures;
        }
    } else {
168
        return new KisOpenGLImageTextures(image, monitorProfile, renderingIntent, conversionFlags);
169 170 171
    }
}

172 173 174
QRect KisOpenGLImageTextures::calculateTileRect(int col, int row) const
{
    return m_image->bounds() &
175 176 177 178
            QRect(col * m_texturesInfo.effectiveWidth,
                  row * m_texturesInfo.effectiveHeight,
                  m_texturesInfo.effectiveWidth,
                  m_texturesInfo.effectiveHeight);
179 180
}

181 182
void KisOpenGLImageTextures::createImageTextureTiles()
{
183

184
    destroyImageTextureTiles();
185 186
    updateTextureFormat();

187 188 189 190 191 192
    if (!m_tilesDestinationColorSpace) {
        qDebug() << "No destination colorspace!!!!";
        return;
    }


193
    m_storedImageBounds = m_image->bounds();
194 195
    const int lastCol = xToCol(m_image->width());
    const int lastRow = yToRow(m_image->height());
196

197 198 199
    m_numCols = lastCol + 1;

    // Default color is transparent black
200
    const int pixelSize = m_tilesDestinationColorSpace->pixelSize();
201
    QByteArray emptyTileData((m_texturesInfo.width) * (m_texturesInfo.height) * pixelSize, 0);
202

203
    KisConfig config;
204
    KisOpenGL::FilterMode mode = (KisOpenGL::FilterMode)config.openGLFilteringMode();
205

Michael Abrahams's avatar
Michael Abrahams committed
206 207
    QOpenGLContext *ctx = QOpenGLContext::currentContext();
    if (ctx) {
208 209 210 211 212
        QOpenGLFunctions *f = ctx->functions();

        m_initialized = true;
        dbgUI  << "OpenGL: creating texture tiles of size" << m_texturesInfo.height << "x" << m_texturesInfo.width;

213
        m_textureTiles.reserve((lastRow+1)*m_numCols);
214 215 216 217 218
        for (int row = 0; row <= lastRow; row++) {
            for (int col = 0; col <= lastCol; col++) {
                QRect tileRect = calculateTileRect(col, row);

                KisTextureTile *tile = new KisTextureTile(tileRect,
219 220 221 222 223 224
                                                          &m_texturesInfo,
                                                          emptyTileData,
                                                          mode,
                                                          config.useOpenGLTextureBuffer(),
                                                          config.numMipmapLevels(),
                                                          f);
225 226
                m_textureTiles.append(tile);
            }
227
        }
228
    }
229
    else {
230
        dbgUI << "Tried to init texture tiles without a current OpenGL Context.";
231
    }
232 233 234 235
}

void KisOpenGLImageTextures::destroyImageTextureTiles()
{
236
    if (m_textureTiles.isEmpty()) return;
237

238
    Q_FOREACH (KisTextureTile *tile, m_textureTiles) {
239
        delete tile;
240
    }
241
    m_textureTiles.clear();
242
    m_storedImageBounds = QRect();
243 244
}

245
KisOpenGLUpdateInfoSP KisOpenGLImageTextures::updateCache(const QRect& rect)
246
{
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
    return updateCacheImpl(rect, true);
}

KisOpenGLUpdateInfoSP KisOpenGLImageTextures::updateCacheNoConversion(const QRect& rect)
{
    return updateCacheImpl(rect, false);
}

KisOpenGLUpdateInfoSP KisOpenGLImageTextures::updateCacheImpl(const QRect& rect, bool convertColorSpace)
{
    const KoColorSpace *dstCS = m_tilesDestinationColorSpace;

    ConversionOptions options;

    if (convertColorSpace) {
        options = ConversionOptions(dstCS, m_renderingIntent, m_conversionFlags);
    }

    KisOpenGLUpdateInfoSP info = new KisOpenGLUpdateInfo(options);
266 267

    QRect updateRect = rect & m_image->bounds();
268
    if (updateRect.isEmpty() || !(m_initialized)) return info;
269

270 271 272 273 274 275 276 277 278 279
    /**
     * Why the rect is artificial? That's easy!
     * It does not represent any real piece of the image. It is
     * intentionally stretched to get through the overlappping
     * stripes of neutrality and poke neighbouring tiles.
     * Thanks to the rect we get the coordinates of all the tiles
     * involved into update process
     */

    QRect artificialRect = stretchRect(updateRect, m_texturesInfo.border);
280
    artificialRect &= m_image->bounds();
281 282 283 284 285 286

    int firstColumn = xToCol(artificialRect.left());
    int lastColumn = xToCol(artificialRect.right());
    int firstRow = yToRow(artificialRect.top());
    int lastRow = yToRow(artificialRect.bottom());

287 288
    QBitArray channelFlags; // empty by default

Boudewijn Rempt's avatar
Boudewijn Rempt committed
289
    if (m_channelFlags.size() != m_image->projection()->colorSpace()->channels().size()) {
290 291 292 293 294 295
        setChannelFlags(QBitArray());
    }
    if (!m_useOcio) { // Ocio does its own channel flipping
        if (!m_allChannelsSelected) { // and we do it only if necessary
            channelFlags = m_channelFlags;
        }
296 297
    }

298 299
    qint32 numItems = (lastColumn - firstColumn + 1) * (lastRow - firstRow + 1);
    info->tileList.reserve(numItems);
300

301 302 303
    const QRect bounds = m_image->bounds();
    const int levelOfDetail = m_image->currentLevelOfDetail();

304 305 306 307 308 309 310
    QRect alignedUpdateRect = updateRect;
    QRect alignedBounds = bounds;

    if (levelOfDetail) {
        alignedUpdateRect = KisLodTransform::alignedRect(alignedUpdateRect, levelOfDetail);
        alignedBounds = KisLodTransform::alignedRect(alignedBounds, levelOfDetail);
    }
311

312 313
    for (int col = firstColumn; col <= lastColumn; col++) {
        for (int row = firstRow; row <= lastRow; row++) {
314

315 316 317 318
            const QRect tileRect = calculateTileRect(col, row);
            const QRect tileTextureRect = stretchRect(tileRect, m_texturesInfo.border);

            QRect alignedTileTextureRect = levelOfDetail ?
319 320
                        KisLodTransform::alignedRect(tileTextureRect, levelOfDetail) :
                        tileTextureRect;
321

322
            KisTextureTileUpdateInfoSP tileInfo(
323 324 325 326 327
                        new KisTextureTileUpdateInfo(col, row,
                                                     alignedTileTextureRect,
                                                     alignedUpdateRect,
                                                     alignedBounds,
                                                     levelOfDetail));
Boudewijn Rempt's avatar
Boudewijn Rempt committed
328
            // Don't update empty tiles
329 330
            if (tileInfo->valid()) {
                tileInfo->retrieveData(m_image, channelFlags, m_onlyOneChannelSelected, m_selectedChannelIndex);
331

332 333 334
                //create transform
                if (m_createNewProofingTransform) {
                    const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(m_proofingConfig->proofingModel,m_proofingConfig->proofingDepth,m_proofingConfig->proofingProfile);
335
                    m_proofingTransform = tileInfo->generateProofingTransform(dstCS, proofingSpace, m_renderingIntent, m_proofingConfig->intent, m_proofingConfig->conversionFlags, m_proofingConfig->warningColor, m_proofingConfig->adaptationState);
336 337 338
                    m_createNewProofingTransform = false;
                }

339
                if (convertColorSpace) {
340 341
                    if (m_proofingConfig && m_proofingTransform && m_proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::SoftProofing)) {
                        tileInfo->proofTo(dstCS, m_proofingConfig->conversionFlags, m_proofingTransform);
342 343 344
                    } else {
                        tileInfo->convertTo(dstCS, m_renderingIntent, m_conversionFlags);
                    }
345
                }
346

Boudewijn Rempt's avatar
Boudewijn Rempt committed
347 348 349
                info->tileList.append(tileInfo);
            }
            else {
350
                dbgUI << "Trying to create an empty tileinfo record" << col << row << tileTextureRect << updateRect << m_image->bounds();
Boudewijn Rempt's avatar
Boudewijn Rempt committed
351
            }
352 353
        }
    }
354 355

    info->assignDirtyImageRect(rect);
356
    info->assignLevelOfDetail(levelOfDetail);
357 358
    return info;
}
359

360 361
void KisOpenGLImageTextures::recalculateCache(KisUpdateInfoSP info)
{
362
    if (!m_initialized) {
363
        dbgUI << "OpenGL: Tried to edit image texture cache before it was initialized.";
364 365 366
        return;
    }

367 368
    KisOpenGLUpdateInfoSP glInfo = dynamic_cast<KisOpenGLUpdateInfo*>(info.data());
    if(!glInfo) return;
369

370
    KisTextureTileUpdateInfoSP tileInfo;
371
    Q_FOREACH (tileInfo, glInfo->tileList) {
372
        KisTextureTile *tile = getTextureTileCR(tileInfo->tileCol(), tileInfo->tileRow());
373 374
        KIS_ASSERT_RECOVER_RETURN(tile);

375
        tile->update(*tileInfo);
376 377 378
    }
}

379
void KisOpenGLImageTextures::generateCheckerTexture(const QImage &checkImage)
380 381
{

382 383 384
    QOpenGLContext *ctx = QOpenGLContext::currentContext();
    if (ctx) {
        QOpenGLFunctions *f = ctx->functions();
385
        dbgUI << "Attaching checker texture" << checkerTexture();
386
        f->glBindTexture(GL_TEXTURE_2D, checkerTexture());
387

388 389 390 391
        f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
392

393
        f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
394

395 396 397 398
        QImage img = checkImage;
        if (checkImage.width() != BACKGROUND_TEXTURE_SIZE || checkImage.height() != BACKGROUND_TEXTURE_SIZE) {
            img = checkImage.scaled(BACKGROUND_TEXTURE_SIZE, BACKGROUND_TEXTURE_SIZE);
        }
399
        f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BACKGROUND_TEXTURE_SIZE, BACKGROUND_TEXTURE_SIZE,
400
                        0, GL_BGRA, GL_UNSIGNED_BYTE, img.constBits());
401 402
    }
    else {
403
        dbgUI << "OpenGL: Tried to generate checker texture before OpenGL was initialized.";
404
    }
405

406 407
}

408
GLuint KisOpenGLImageTextures::checkerTexture()
409
{
410 411 412 413 414 415 416
    if (m_glFuncs) {
        if (m_checkerTexture == 0) {
            m_glFuncs->glGenTextures(1, &m_checkerTexture);
        }
        return m_checkerTexture;
    }
    else {
417
        dbgUI << "Tried to access checker texture before OpenGL was initialized";
418 419
        return 0;
    }
420 421
}

422
void KisOpenGLImageTextures::updateConfig(bool useBuffer, int NumMipmapLevels)
423
{
424 425
    if(m_textureTiles.isEmpty()) return;

426
    Q_FOREACH (KisTextureTile *tile, m_textureTiles) {
427
        tile->setUseBuffer(useBuffer);
428
        tile->setNumMipmapLevels(NumMipmapLevels);
429 430 431
    }
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
432
void KisOpenGLImageTextures::slotImageSizeChanged(qint32 /*w*/, qint32 /*h*/)
433 434 435 436
{
    createImageTextureTiles();
}

437
void KisOpenGLImageTextures::setMonitorProfile(const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
438
{
439
    //dbgUI << "Setting monitor profile to" << monitorProfile->name() << renderingIntent << conversionFlags;
440 441 442
    m_monitorProfile = monitorProfile;
    m_renderingIntent = renderingIntent;
    m_conversionFlags = conversionFlags;
443 444

    createImageTextureTiles();
445 446
}

447 448 449
void KisOpenGLImageTextures::setChannelFlags(const QBitArray &channelFlags)
{
    m_channelFlags = channelFlags;
450 451 452
    int selectedChannels = 0;
    const KoColorSpace *projectionCs = m_image->projection()->colorSpace();
    QList<KoChannelInfo*> channelInfo = projectionCs->channels();
453 454 455 456 457

    if (m_channelFlags.size() != channelInfo.size()) {
        m_channelFlags = QBitArray();
    }

458 459 460 461 462 463 464 465
    for (int i = 0; i < m_channelFlags.size(); ++i) {
        if (m_channelFlags.testBit(i) && channelInfo[i]->channelType() == KoChannelInfo::COLOR) {
            selectedChannels++;
            m_selectedChannelIndex = i;
        }
    }
    m_allChannelsSelected = (selectedChannels == m_channelFlags.size());
    m_onlyOneChannelSelected = (selectedChannels == 1);
466 467
}

468 469 470
void KisOpenGLImageTextures::setProofingConfig(KisProofingConfiguration *proofingConfig)
{
    m_proofingConfig = proofingConfig;
471
    m_createNewProofingTransform = true;
472 473
}

474 475
void KisOpenGLImageTextures::getTextureSize(KisGLTexturesInfo *texturesInfo)
{
476 477 478
    KisConfig cfg;

    const GLint preferredTextureSize = cfg.openGLTextureSize();
479 480

    GLint maxTextureSize;
481 482 483 484
    if (m_glFuncs) {
        m_glFuncs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
    }
    else {
485
        dbgUI << "OpenGL: Tried to read texture size before OpenGL was initialized.";
486 487
        maxTextureSize = GL_MAX_TEXTURE_SIZE;
    }
488 489 490

    texturesInfo->width = qMin(preferredTextureSize, maxTextureSize);
    texturesInfo->height = qMin(preferredTextureSize, maxTextureSize);
491

492
    texturesInfo->border = cfg.textureOverlapBorder();
493 494 495

    texturesInfo->effectiveWidth = texturesInfo->width - 2 * texturesInfo->border;
    texturesInfo->effectiveHeight = texturesInfo->height - 2 * texturesInfo->border;
496
}
497

498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
bool KisOpenGLImageTextures::internalColorManagementActive() const
{
    return m_internalColorManagementActive;
}

bool KisOpenGLImageTextures::setInternalColorManagementActive(bool value)
{
    bool needsFinalRegeneration = m_internalColorManagementActive != value;

    if (needsFinalRegeneration) {
        m_internalColorManagementActive = value;
        createImageTextureTiles();

        // at this point the value of m_internalColorManagementActive might
        // have been forcely reverted to 'false' in case of some problems
    }

    return needsFinalRegeneration;
}

518
void KisOpenGLImageTextures::updateTextureFormat()
519
{
Michael Abrahams's avatar
Michael Abrahams committed
520 521
    QOpenGLContext *ctx = QOpenGLContext::currentContext();
    if (!(m_image && ctx)) return;
522

523
    m_texturesInfo.internalFormat = GL_RGBA8;
524
    m_texturesInfo.type = GL_UNSIGNED_BYTE;
525
    m_texturesInfo.format = GL_BGRA;
526

527 528
    KoID colorModelId = m_image->colorSpace()->colorModelId();
    KoID colorDepthId = m_image->colorSpace()->colorDepthId();
529

530 531 532
    KoID destinationColorModelId = RGBAColorModelID;
    KoID destinationColorDepthId = Integer8BitsColorDepthID;

Boudewijn Rempt's avatar
Boudewijn Rempt committed
533
    dbgUI << "Choosing texture format:";
534

535
    if (colorModelId == RGBAColorModelID) {
536
        if (colorDepthId == Float16BitsColorDepthID) {
537

Michael Abrahams's avatar
Michael Abrahams committed
538
            if (ctx->hasExtension("GL_ARB_texture_float")) {
539
                m_texturesInfo.internalFormat = GL_RGBA16F_ARB;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
540
                dbgUI << "Using ARB half";
541
            }
Michael Abrahams's avatar
Michael Abrahams committed
542
            else if (ctx->hasExtension("GL_ATI_texture_float")) {
543
                m_texturesInfo.internalFormat = GL_RGBA_FLOAT16_ATI;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
544
                dbgUI << "Using ATI half";
545
            }
546

547 548 549 550 551
            bool haveBuiltInOpenExr = false;
#ifdef HAVE_OPENEXR
            haveBuiltInOpenExr = true;
#endif

552
            if (haveBuiltInOpenExr && ctx->hasExtension("GL_ARB_half_float_pixel")) {
553
                m_texturesInfo.type = GL_HALF_FLOAT_ARB;
554 555
                destinationColorDepthId = Float16BitsColorDepthID;
                dbgUI << "Pixel type half";
556
            } else {
557
                m_texturesInfo.type = GL_FLOAT;
558 559
                destinationColorDepthId = Float32BitsColorDepthID;
                dbgUI << "Pixel type float";
560
            }
561
            m_texturesInfo.format = GL_RGBA;
562
        }
563
        else if (colorDepthId == Float32BitsColorDepthID) {
564
            if (ctx->hasExtension("GL_ARB_texture_float")) {
565
                m_texturesInfo.internalFormat = GL_RGBA32F_ARB;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
566
                dbgUI << "Using ARB float";
567
            } else if (ctx->hasExtension("GL_ATI_texture_float")) {
568
                m_texturesInfo.internalFormat = GL_RGBA_FLOAT32_ATI;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
569
                dbgUI << "Using ATI float";
570
            }
571 572

            m_texturesInfo.type = GL_FLOAT;
573
            m_texturesInfo.format = GL_RGBA;
574
            destinationColorDepthId = Float32BitsColorDepthID;
575
        }
576
        else if (colorDepthId == Integer16BitsColorDepthID) {
577
            m_texturesInfo.internalFormat = GL_RGBA16;
578
            m_texturesInfo.type = GL_UNSIGNED_SHORT;
579 580 581
            m_texturesInfo.format = GL_BGRA;
            destinationColorDepthId = Integer16BitsColorDepthID;
            dbgUI << "Using 16 bits rgba";
582 583 584 585 586
        }
    }
    else {
        // We will convert the colorspace to 16 bits rgba, instead of 8 bits
        if (colorDepthId == Integer16BitsColorDepthID) {
587
            m_texturesInfo.internalFormat = GL_RGBA16;
588
            m_texturesInfo.type = GL_UNSIGNED_SHORT;
589 590 591
            m_texturesInfo.format = GL_BGRA;
            destinationColorDepthId = Integer16BitsColorDepthID;
            dbgUI << "Using conversion to 16 bits rgba";
592
        }
593
    }
594 595

    if (!m_internalColorManagementActive &&
596
            colorModelId != destinationColorModelId) {
597

598 599 600 601 602 603 604 605
        KisConfig cfg;
        KisConfig::OcioColorManagementMode cm = cfg.ocioColorManagementMode();

        if (cm != KisConfig::INTERNAL) {
            QMessageBox::critical(0,
                                  i18nc("@title:window", "Krita"),
                                  i18n("You enabled OpenColorIO based color management, but your image is not an RGB image.\n"
                                       "OpenColorIO-based color management only works with RGB images.\n"
606
                                       "Please check the settings in the LUT docker.\n"
607 608
                                       "OpenColorIO will now be deactivated."));
        }
609

610 611 612 613 614
        warnUI << "WARNING: Internal color management was forcely enabled";
        warnUI << "Color Management Mode: " << cm;
        warnUI << ppVar(m_image->colorSpace());
        warnUI << ppVar(destinationColorModelId);
        warnUI << ppVar(destinationColorDepthId);
615

616 617
        cfg.setOcioColorManagementMode(KisConfig::INTERNAL);
        m_internalColorManagementActive = true;
618 619 620
    }

    const KoColorProfile *profile =
621 622 623
            m_internalColorManagementActive ||
            colorModelId != destinationColorModelId ?
                m_monitorProfile : m_image->colorSpace()->profile();
624 625 626 627 628 629 630

    /**
     * TODO: add an optimization so that the tile->convertTo() method
     *       would not be called when not needed (DK)
     */

    m_tilesDestinationColorSpace =
631 632 633
            KoColorSpaceRegistry::instance()->colorSpace(destinationColorModelId.id(),
                                                         destinationColorDepthId.id(),
                                                         profile);
634 635
}