[krita/krita/4.1] libs: Fix flickering on Instant Preview finishing original regeneration

Boudewijn Rempt null at kde.org
Mon Sep 24 08:17:00 BST 2018


Git commit 8739c93870f0ce63633402ceb175cad9362fd4cf by Boudewijn Rempt, on behalf of Dmitry Kazakov.
Committed on 24/09/2018 at 06:57.
Pushed by rempt into branch 'krita/4.1'.

Fix flickering on Instant Preview finishing original regeneration

The problem happened mipmap regeneration. Basically, we should not
start regenerating tile mipmaps until all the updates have been
completed. Otherwise, some parts of the regenerated mipmap will
have outdated (old) content and the user will see flickering.

Now KisImage has two special signals that notify the canvas thay
a special "lod rest updates batch" is coming. The canvas will block
tile regeneration for this batch and will start it right after the
batch is completed. Therefore the user will see completely prepared
data.

BUG:361448
Fixes T2145
CC:kimageshop at kde.org

M  +20   -0    libs/image/kis_image.h
M  +16   -0    libs/image/kis_image_signal_router.cpp
M  +3    -0    libs/image/kis_image_signal_router.h
M  +19   -5    libs/image/kis_suspend_projection_updates_stroke_strategy.cpp
M  +2    -0    libs/ui/canvas/kis_abstract_canvas_widget.h
M  +70   -16   libs/ui/canvas/kis_canvas2.cpp
M  +2    -0    libs/ui/canvas/kis_canvas2.h
M  +4    -0    libs/ui/canvas/kis_qpainter_canvas.h
M  +23   -0    libs/ui/canvas/kis_update_info.cpp
M  +21   -0    libs/ui/canvas/kis_update_info.h
M  +11   -4    libs/ui/opengl/kis_opengl_canvas2.cpp
M  +1    -0    libs/ui/opengl/kis_opengl_canvas2.h
M  +15   -20   libs/ui/opengl/kis_texture_tile.cpp
M  +8    -4    libs/ui/opengl/kis_texture_tile.h

https://commits.kde.org/krita/8739c93870f0ce63633402ceb175cad9362fd4cf

diff --git a/libs/image/kis_image.h b/libs/image/kis_image.h
index fcea5fd28a1..41eda07d7b9 100644
--- a/libs/image/kis_image.h
+++ b/libs/image/kis_image.h
@@ -710,6 +710,26 @@ Q_SIGNALS:
      */
     void sigImageUpdated(const QRect &);
 
+    /**
+     * Emitted whenever the image is going to reset load planes from lodN to
+     * lod0. All the signals emitted with sigImageUpdated() between the calls
+     * to sigBeginLodResetUpdatesBatch() and sigEndLodResetUpdatesBatch() will be
+     * considered as belonging to the same "batch". During processing a "batch"
+     * GUI is not permitted to change lod level of the tile textures. It should
+     * just update internal caches. The call to sigEndLodResetUpdatesBatch()
+     * will start rerendering of the canvas.
+     *
+     * NOTE: this feature is used to avoid flickering when switching
+     * back from lodN plane back to lod0. All the texture tiles should
+     * be loaded with new information before mipmaps can be regenerated.
+     */
+    void sigBeginLodResetUpdatesBatch();
+
+    /**
+     * @see sigBeginLodResetUpdatesBatch()
+     */
+    void sigEndLodResetUpdatesBatch();
+
     /**
        Emitted whenever the image has been modified, so that it
        doesn't match with the version saved on disk.
diff --git a/libs/image/kis_image_signal_router.cpp b/libs/image/kis_image_signal_router.cpp
index 284e735713a..0145ad87c95 100644
--- a/libs/image/kis_image_signal_router.cpp
+++ b/libs/image/kis_image_signal_router.cpp
@@ -113,6 +113,22 @@ void KisImageSignalRouter::emitAboutToRemoveANode(KisNode *parent, int index)
     emit sigRemoveNodeAsync(removedNode);
 }
 
+void KisImageSignalRouter::emitBeginLodResetUpdatesBatch()
+{
+    KisImageSP image = m_image.toStrongRef();
+    KIS_SAFE_ASSERT_RECOVER_RETURN(image);
+
+    emit image->sigBeginLodResetUpdatesBatch();
+}
+
+void KisImageSignalRouter::emitEndLodResetUpdatesBatch()
+{
+    KisImageSP image = m_image.toStrongRef();
+    KIS_SAFE_ASSERT_RECOVER_RETURN(image);
+
+    emit image->sigEndLodResetUpdatesBatch();
+}
+
 
 void KisImageSignalRouter::slotNotification(KisImageSignalType type)
 {
diff --git a/libs/image/kis_image_signal_router.h b/libs/image/kis_image_signal_router.h
index be8f68c66e3..10701deab8c 100644
--- a/libs/image/kis_image_signal_router.h
+++ b/libs/image/kis_image_signal_router.h
@@ -149,6 +149,9 @@ public:
     void emitNodeHasBeenAdded(KisNode *parent, int index);
     void emitAboutToRemoveANode(KisNode *parent, int index);
 
+    void emitBeginLodResetUpdatesBatch();
+    void emitEndLodResetUpdatesBatch();
+
 private Q_SLOTS:
     void slotNotification(KisImageSignalType type);
 
diff --git a/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp b/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp
index ee645ab89ee..bf6b36bbf9d 100644
--- a/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp
+++ b/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp
@@ -21,6 +21,7 @@
 #include <kis_image.h>
 #include <krita_utils.h>
 #include <kis_projection_updates_filter.h>
+#include "kis_image_signal_router.h"
 
 
 inline uint qHash(const QRect &rc) {
@@ -129,9 +130,16 @@ struct KisSuspendProjectionUpdatesStrokeStrategy::Private
             {}
     };
 
-    class UpdatesBarrierData : public KisStrokeJobData {
+    class StartBatchUpdate : public KisStrokeJobData {
     public:
-        UpdatesBarrierData()
+        StartBatchUpdate()
+            : KisStrokeJobData(BARRIER)
+            {}
+    };
+
+    class EndBatchUpdate : public KisStrokeJobData {
+    public:
+        EndBatchUpdate()
             : KisStrokeJobData(BARRIER)
             {}
     };
@@ -215,7 +223,8 @@ void KisSuspendProjectionUpdatesStrokeStrategy::doStrokeCallback(KisStrokeJobDat
 {
     Private::SuspendData *suspendData = dynamic_cast<Private::SuspendData*>(data);
     Private::ResumeAndIssueGraphUpdatesData *resumeData = dynamic_cast<Private::ResumeAndIssueGraphUpdatesData*>(data);
-    Private::UpdatesBarrierData *barrierData = dynamic_cast<Private::UpdatesBarrierData*>(data);
+    Private::StartBatchUpdate *startBatchData = dynamic_cast<Private::StartBatchUpdate*>(data);
+    Private::EndBatchUpdate *endBatchData = dynamic_cast<Private::EndBatchUpdate*>(data);
     Private::IssueCanvasUpdatesData *canvasUpdates = dynamic_cast<Private::IssueCanvasUpdatesData*>(data);
 
     KisImageSP image = m_d->image.toStrongRef();
@@ -229,10 +238,13 @@ void KisSuspendProjectionUpdatesStrokeStrategy::doStrokeCallback(KisStrokeJobDat
     } else if (resumeData) {
         image->disableUIUpdates();
         resumeAndIssueUpdates(false);
-    } else if (barrierData) {
+    } else if (startBatchData) {
         image->enableUIUpdates();
+        image->signalRouter()->emitBeginLodResetUpdatesBatch();
     } else if (canvasUpdates) {
         image->notifyProjectionUpdated(canvasUpdates->updateRect);
+    } else if (endBatchData) {
+        image->signalRouter()->emitEndLodResetUpdatesBatch();
     }
 }
 
@@ -248,7 +260,7 @@ QList<KisStrokeJobData*> KisSuspendProjectionUpdatesStrokeStrategy::createResume
     QList<KisStrokeJobData*> jobsData;
 
     jobsData << new Private::ResumeAndIssueGraphUpdatesData();
-    jobsData << new Private::UpdatesBarrierData();
+    jobsData << new Private::StartBatchUpdate();
 
     using KritaUtils::splitRectIntoPatches;
     using KritaUtils::optimalPatchSize;
@@ -259,6 +271,8 @@ QList<KisStrokeJobData*> KisSuspendProjectionUpdatesStrokeStrategy::createResume
         jobsData << new Private::IssueCanvasUpdatesData(rc);
     }
 
+    jobsData << new Private::EndBatchUpdate();
+
     return jobsData;
 }
 
diff --git a/libs/ui/canvas/kis_abstract_canvas_widget.h b/libs/ui/canvas/kis_abstract_canvas_widget.h
index c769f3cbb60..3a3771ef637 100644
--- a/libs/ui/canvas/kis_abstract_canvas_widget.h
+++ b/libs/ui/canvas/kis_abstract_canvas_widget.h
@@ -88,6 +88,8 @@ public:
      * compress update events.
      */
     virtual bool isBusy() const = 0;
+
+    virtual void setLodResetInProgress(bool value) = 0;
 };
 
 #endif // _KIS_ABSTRACT_CANVAS_WIDGET_
diff --git a/libs/ui/canvas/kis_canvas2.cpp b/libs/ui/canvas/kis_canvas2.cpp
index bc9530f3b85..568a5a1c03a 100644
--- a/libs/ui/canvas/kis_canvas2.cpp
+++ b/libs/ui/canvas/kis_canvas2.cpp
@@ -148,6 +148,7 @@ public:
     QRect regionOfInterest;
 
     QRect renderingLimit;
+    int lodResetBatchActive = 0;
 
     bool effectiveLodAllowedInImage() {
         return lodAllowedInImage && !bootstrapLodBlocked;
@@ -553,6 +554,9 @@ void KisCanvas2::initializeImage()
     m_d->toolProxy.initializeImage(image);
 
     connect(image, SIGNAL(sigImageUpdated(QRect)), SLOT(startUpdateCanvasProjection(QRect)), Qt::DirectConnection);
+    connect(image, SIGNAL(sigBeginLodResetUpdatesBatch()), SLOT(slotBeginLodResetUpdatesBatch()), Qt::DirectConnection);
+    connect(image, SIGNAL(sigEndLodResetUpdatesBatch()), SLOT(slotEndLodResetUpdatesBatch()), Qt::DirectConnection);
+
     connect(image, SIGNAL(sigProofingConfigChanged()), SLOT(slotChangeProofingConfig()));
     connect(image, SIGNAL(sigSizeChanged(const QPointF&, const QPointF&)), SLOT(startResizingImage()), Qt::DirectConnection);
     connect(image->undoAdapter(), SIGNAL(selectionChanged()), SLOT(slotTrySwitchShapeManager()));
@@ -745,28 +749,78 @@ void KisCanvas2::startUpdateCanvasProjection(const QRect & rc)
 
 void KisCanvas2::updateCanvasProjection()
 {
-    QVector<KisUpdateInfoSP> infoObjects;
-    while (KisUpdateInfoSP info = m_d->projectionUpdatesCompressor.takeUpdateInfo()) {
-        infoObjects << info;
-    }
+    auto tryIssueCanvasUpdates = [this](const QRect &vRect) {
+        if (!m_d->lodResetBatchActive) {
+            // TODO: Implement info->dirtyViewportRect() for KisOpenGLCanvas2 to avoid updating whole canvas
+            if (m_d->currentCanvasIsOpenGL) {
+                m_d->savedUpdateRect = QRect();
+
+                // we already had a compression in frameRenderStartCompressor, so force the update directly
+                slotDoCanvasUpdate();
+            } else if (/* !m_d->currentCanvasIsOpenGL && */ !vRect.isEmpty()) {
+                m_d->savedUpdateRect = m_d->coordinatesConverter->viewportToWidget(vRect).toAlignedRect();
+
+                // we already had a compression in frameRenderStartCompressor, so force the update directly
+                slotDoCanvasUpdate();
+            }
+        }
+    };
 
-    QVector<QRect> viewportRects = m_d->canvasWidget->updateCanvasProjection(infoObjects);
+    auto uploadData = [this, tryIssueCanvasUpdates](const QVector<KisUpdateInfoSP> &infoObjects) {
+        QVector<QRect> viewportRects = m_d->canvasWidget->updateCanvasProjection(infoObjects);
+        const QRect vRect = std::accumulate(viewportRects.constBegin(), viewportRects.constEnd(),
+                                            QRect(), std::bit_or<QRect>());
 
-    const QRect vRect = std::accumulate(viewportRects.constBegin(), viewportRects.constEnd(),
-                                        QRect(), std::bit_or<QRect>());
+        tryIssueCanvasUpdates(vRect);
+    };
 
-    // TODO: Implement info->dirtyViewportRect() for KisOpenGLCanvas2 to avoid updating whole canvas
-    if (m_d->currentCanvasIsOpenGL) {
-        m_d->savedUpdateRect = QRect();
 
-        // we already had a compression in frameRenderStartCompressor, so force the update directly
-        slotDoCanvasUpdate();
-    } else if (/* !m_d->currentCanvasIsOpenGL && */ !vRect.isEmpty()) {
-        m_d->savedUpdateRect = m_d->coordinatesConverter->viewportToWidget(vRect).toAlignedRect();
+    QVector<KisUpdateInfoSP> infoObjects;
+    while (KisUpdateInfoSP info = m_d->projectionUpdatesCompressor.takeUpdateInfo()) {
+        const KisBatchControlUpdateInfo *batchInfo = dynamic_cast<const KisBatchControlUpdateInfo*>(info.data());
+        if (batchInfo) {
+            if (!infoObjects.isEmpty()) {
+                uploadData(infoObjects);
+                infoObjects.clear();
+            }
 
-        // we already had a compression in frameRenderStartCompressor, so force the update directly
-        slotDoCanvasUpdate();
+            if (batchInfo->type() == KisBatchControlUpdateInfo::StartBatch) {
+                m_d->lodResetBatchActive++;
+                m_d->canvasWidget->setLodResetInProgress(true);
+            } else if (batchInfo->type() == KisBatchControlUpdateInfo::EndBatch) {
+                m_d->canvasWidget->setLodResetInProgress(false);
+                m_d->lodResetBatchActive--;
+                KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->lodResetBatchActive >= 0);
+                if (m_d->lodResetBatchActive == 0) {
+                    tryIssueCanvasUpdates(m_d->coordinatesConverter->imageRectInImagePixels());
+                }
+            }
+        } else {
+            infoObjects << info;
+        }
     }
+
+    if (!infoObjects.isEmpty()) {
+        uploadData(infoObjects);
+    }
+}
+
+void KisCanvas2::slotBeginLodResetUpdatesBatch()
+{
+    KisUpdateInfoSP info =
+        new KisBatchControlUpdateInfo(KisBatchControlUpdateInfo::StartBatch,
+                                      m_d->coordinatesConverter->imageRectInImagePixels());
+    m_d->projectionUpdatesCompressor.putUpdateInfo(info);
+    emit sigCanvasCacheUpdated();
+}
+
+void KisCanvas2::slotEndLodResetUpdatesBatch()
+{
+    KisUpdateInfoSP info =
+        new KisBatchControlUpdateInfo(KisBatchControlUpdateInfo::EndBatch,
+                                      m_d->coordinatesConverter->imageRectInImagePixels());
+    m_d->projectionUpdatesCompressor.putUpdateInfo(info);
+    emit sigCanvasCacheUpdated();
 }
 
 void KisCanvas2::slotDoCanvasUpdate()
diff --git a/libs/ui/canvas/kis_canvas2.h b/libs/ui/canvas/kis_canvas2.h
index 38b18950f09..2ee4296d022 100644
--- a/libs/ui/canvas/kis_canvas2.h
+++ b/libs/ui/canvas/kis_canvas2.h
@@ -279,6 +279,8 @@ private Q_SLOTS:
     void startUpdateCanvasProjection(const QRect & rc);
     void updateCanvasProjection();
 
+    void slotBeginLodResetUpdatesBatch();
+    void slotEndLodResetUpdatesBatch();
 
     /**
      * Called whenever the view widget needs to show a different part of
diff --git a/libs/ui/canvas/kis_qpainter_canvas.h b/libs/ui/canvas/kis_qpainter_canvas.h
index 70ef94996ef..0c3f3919fcf 100644
--- a/libs/ui/canvas/kis_qpainter_canvas.h
+++ b/libs/ui/canvas/kis_qpainter_canvas.h
@@ -78,6 +78,10 @@ public: // Implement kis_abstract_canvas_widget interface
         return false;
     }
 
+    void setLodResetInProgress(bool value) override {
+        Q_UNUSED(value);
+    }
+
 protected: // KisCanvasWidgetBase
 
     bool callFocusNextPrevChild(bool next) override;
diff --git a/libs/ui/canvas/kis_update_info.cpp b/libs/ui/canvas/kis_update_info.cpp
index 9640d437357..9330a4c2b57 100644
--- a/libs/ui/canvas/kis_update_info.cpp
+++ b/libs/ui/canvas/kis_update_info.cpp
@@ -96,3 +96,26 @@ bool KisOpenGLUpdateInfo::tryMergeWith(const KisOpenGLUpdateInfo &rhs)
 
     return true;
 }
+
+KisBatchControlUpdateInfo::KisBatchControlUpdateInfo(KisBatchControlUpdateInfo::Type type, const QRect &dirtyImageRect)
+    : m_type(type),
+      m_dirtyImageRect(dirtyImageRect)
+{
+}
+
+KisBatchControlUpdateInfo::Type KisBatchControlUpdateInfo::type() const
+{
+    return m_type;
+}
+
+QRect KisBatchControlUpdateInfo::dirtyImageRect() const
+{
+    return m_dirtyImageRect;
+}
+
+int KisBatchControlUpdateInfo::levelOfDetail() const
+{
+    // return invalid level of detail to avoid merging the update info
+    // with other updates
+    return m_type == StartBatch ? -1 : -2;
+}
diff --git a/libs/ui/canvas/kis_update_info.h b/libs/ui/canvas/kis_update_info.h
index bebf2519cb1..76ecb7e19e3 100644
--- a/libs/ui/canvas/kis_update_info.h
+++ b/libs/ui/canvas/kis_update_info.h
@@ -142,4 +142,25 @@ public:
     KisImagePatch patch;
 };
 
+class KisBatchControlUpdateInfo : public KisUpdateInfo
+{
+public:
+    enum Type {
+        StartBatch,
+        EndBatch
+    };
+
+public:
+    KisBatchControlUpdateInfo(Type type, const QRect &dirtyImageRect);
+
+    Type type() const;
+
+    QRect dirtyImageRect() const override;
+    int levelOfDetail() const override;
+
+private:
+    Type m_type;
+    QRect m_dirtyImageRect;
+};
+
 #endif /* KIS_UPDATE_INFO_H_ */
diff --git a/libs/ui/opengl/kis_opengl_canvas2.cpp b/libs/ui/opengl/kis_opengl_canvas2.cpp
index a14b2b68046..0b874fec924 100644
--- a/libs/ui/opengl/kis_opengl_canvas2.cpp
+++ b/libs/ui/opengl/kis_opengl_canvas2.cpp
@@ -111,6 +111,8 @@ public:
     QColor gridColor;
     QColor cursorColor;
 
+    bool lodSwitchInProgress = false;
+
     int xToColWithWrapCompensation(int x, const QRect &imageRect) {
         int firstImageColumn = openGLImageTextures->xToCol(imageRect.left());
         int lastImageColumn = openGLImageTextures->xToCol(imageRect.right());
@@ -469,6 +471,11 @@ bool KisOpenGLCanvas2::isBusy() const
     return isBusyStatus;
 }
 
+void KisOpenGLCanvas2::setLodResetInProgress(bool value)
+{
+    d->lodSwitchInProgress = value;
+}
+
 void KisOpenGLCanvas2::drawCheckers()
 {
     if (!d->checkerShader) {
@@ -749,15 +756,15 @@ void KisOpenGLCanvas2::drawImage()
                 d->displayShader->setUniformValue(d->displayShader->location(Uniform::Texture1), 1);
             }
 
-            int currentLodPlane = tile->currentLodPlane();
+            glActiveTexture(GL_TEXTURE0);
+
+            const int currentLodPlane = tile->bindToActiveTexture(d->lodSwitchInProgress);
+
             if (d->displayShader->location(Uniform::FixedLodLevel) >= 0) {
                 d->displayShader->setUniformValue(d->displayShader->location(Uniform::FixedLodLevel),
                                                   (GLfloat) currentLodPlane);
             }
 
-            glActiveTexture(GL_TEXTURE0);
-            tile->bindToActiveTexture();
-
             if (currentLodPlane > 0) {
                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
             } else if (SCALE_MORE_OR_EQUAL_TO(scaleX, scaleY, 2.0)) {
diff --git a/libs/ui/opengl/kis_opengl_canvas2.h b/libs/ui/opengl/kis_opengl_canvas2.h
index 7e177efecc3..c6051c3b37b 100644
--- a/libs/ui/opengl/kis_opengl_canvas2.h
+++ b/libs/ui/opengl/kis_opengl_canvas2.h
@@ -96,6 +96,7 @@ public: // Implement kis_abstract_canvas_widget interface
     }
 
     bool isBusy() const override;
+    void setLodResetInProgress(bool value) override;
 
     void setDisplayFilterImpl(QSharedPointer<KisDisplayFilter> displayFilter, bool initializing);
 
diff --git a/libs/ui/opengl/kis_texture_tile.cpp b/libs/ui/opengl/kis_texture_tile.cpp
index 63389c5205f..bc7e8960881 100644
--- a/libs/ui/opengl/kis_texture_tile.cpp
+++ b/libs/ui/opengl/kis_texture_tile.cpp
@@ -74,7 +74,7 @@ KisTextureTile::KisTextureTile(const QRect &imageRect, const KisGLTexturesInfo *
     , m_filter(filter)
     , m_texturesInfo(texturesInfo)
     , m_needsMipmapRegeneration(false)
-    , m_currentLodPlane(0)
+    , m_preparedLodPlane(0)
     , m_useBuffer(useBuffer)
     , m_numMipmapLevels(numMipmapLevels)
     , f(fcn)
@@ -123,14 +123,16 @@ KisTextureTile::~KisTextureTile()
     f->glDeleteTextures(1, &m_textureId);
 }
 
-void KisTextureTile::bindToActiveTexture()
+int KisTextureTile::bindToActiveTexture(bool blockMipmapRegeneration)
 {
     f->glBindTexture(GL_TEXTURE_2D, m_textureId);
 
-    if (m_needsMipmapRegeneration) {
+    if (m_needsMipmapRegeneration && !blockMipmapRegeneration) {
         f->glGenerateMipmap(GL_TEXTURE_2D);
-        m_needsMipmapRegeneration = false;
+        setPreparedLodPlane(0);
     }
+
+    return m_preparedLodPlane;
 }
 
 void KisTextureTile::setNeedsMipmapRegeneration()
@@ -140,18 +142,11 @@ void KisTextureTile::setNeedsMipmapRegeneration()
 
         m_needsMipmapRegeneration = true;
     }
-
-    m_currentLodPlane = 0;
-}
-
-int KisTextureTile::currentLodPlane() const
-{
-    return m_currentLodPlane;
 }
 
-void KisTextureTile::setCurrentLodPlane(int lod)
+void KisTextureTile::setPreparedLodPlane(int lod)
 {
-    m_currentLodPlane = lod;
+    m_preparedLodPlane = lod;
     m_needsMipmapRegeneration = false;
 }
 
@@ -182,7 +177,7 @@ void KisTextureTile::update(const KisTextureTileUpdateInfo &updateInfo)
      *
      * 2) [here, ideally, the canvas should be re-rendered, so that
      *     the mipmap would be regenerated in bindToActiveTexture()
-     *     call, by in some cases (if you cancel and paint to quickly,
+     *     call, by in some cases (if you cancel and paint to quickly),
      *     that doesn't have time to happen]
      *
      * 3) The new LodN stroke issues a *partial* update of a LodN
@@ -360,17 +355,17 @@ void KisTextureTile::update(const KisTextureTileUpdateInfo &updateInfo)
 
     //// Uncomment this warning if you see any weird flickering when
     //// Instant Preview updates
-    //
-    // if (!patchLevelOfDetail &&
-    //     m_currentLodPlane &&
-    //     !updateInfo.isEntireTileUpdated()) {
-    //     qDebug() << "WARNING: LodN -> Lod0 switch is requested for the partial tile update! Flickering is possible..." << ppVar(patchSize);
+    // if (!updateInfo.isEntireTileUpdated() &&
+    //     !(!patchLevelOfDetail || !m_preparedLodPlane || patchLevelOfDetail == m_preparedLodPlane)) {
+    //     qDebug() << "WARNING: LodN switch is requested for the partial tile update!. Flickering is possible..." << ppVar(patchSize);
+    //     qDebug() << "    " << ppVar(m_preparedLodPlane);
+    //     qDebug() << "    " << ppVar(patchLevelOfDetail);
     // }
 
     if (!patchLevelOfDetail) {
         setNeedsMipmapRegeneration();
     } else {
-        setCurrentLodPlane(patchLevelOfDetail);
+        setPreparedLodPlane(patchLevelOfDetail);
     }
 }
 
diff --git a/libs/ui/opengl/kis_texture_tile.h b/libs/ui/opengl/kis_texture_tile.h
index d18dcee172d..2fd77d52dbc 100644
--- a/libs/ui/opengl/kis_texture_tile.h
+++ b/libs/ui/opengl/kis_texture_tile.h
@@ -91,14 +91,18 @@ public:
 
     QRectF imageRectInTexturePixels(const QRect &imageRect) const;
 
-    void bindToActiveTexture();
-    int currentLodPlane() const;
+    /**
+     * Binds the tile's testure to the current GL_TEXTURE_2D binding point,
+     * regenerates the mipmap if needed and returns the levelOfDetail that
+     * should be used for painting
+     */
+    int bindToActiveTexture(bool blockMipmapRegeneration);
 
 private:
     inline void setTextureParameters();
 
     void setNeedsMipmapRegeneration();
-    void setCurrentLodPlane(int lod);
+    void setPreparedLodPlane(int lod);
 
     GLuint m_textureId;
 
@@ -113,7 +117,7 @@ private:
     KisOpenGL::FilterMode m_filter;
     const KisGLTexturesInfo *m_texturesInfo;
     bool m_needsMipmapRegeneration;
-    int m_currentLodPlane;
+    int m_preparedLodPlane;
     bool m_useBuffer;
     int m_numMipmapLevels;
     QOpenGLFunctions *f;



More information about the kimageshop mailing list