Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_texture_tile.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#define GL_GLEXT_PROTOTYPES
8#include "kis_texture_tile.h"
11
12#include <kis_debug.h>
13#if !defined(QT_OPENGL_ES)
14#include <QOpenGLBuffer>
15#endif
16
17#ifndef GL_BGRA
18#define GL_BGRA 0x814F
19#endif
20
21#ifndef GL_RGBA16_EXT
22#define GL_RGBA16_EXT 0x805B
23#endif
24
25
27{
28
29 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
30 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
31 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
32 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, m_numMipmapLevels);
33 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
34 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, m_numMipmapLevels);
35
36 if ((m_texturesInfo->internalFormat == GL_RGBA8 && m_texturesInfo->format == GL_RGBA)
37#ifndef QT_OPENGL_ES_2
38 || (m_texturesInfo->internalFormat == GL_RGBA16 && m_texturesInfo->format == GL_RGBA)
39#endif
41 ) {
42 // If image format is RGBA8, swap the red and blue channels for the proper color
43 // This is for OpenGL ES support and only used if lacking GL_EXT_texture_format_BGRA8888
44 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
45 f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
46 }
47
48 f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
49}
50
52{
53 // QPainter::drawText relies on this.
54 // Ref: https://bugreports.qt.io/browse/QTBUG-65496
55 f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
56}
57
58inline QRectF relativeRect(const QRect &br /* baseRect */,
59 const QRect &cr /* childRect */,
60 const KisGLTexturesInfo *texturesInfo)
61{
62 const qreal x = qreal(cr.x() - br.x()) / texturesInfo->width;
63 const qreal y = qreal(cr.y() - br.y()) / texturesInfo->height;
64 const qreal w = qreal(cr.width()) / texturesInfo->width;
65 const qreal h = qreal(cr.height()) / texturesInfo->height;
66
67 return QRectF(x, y, w, h);
68}
69
70#include "kis_debug.h"
71
72KisTextureTile::KisTextureTile(const QRect &imageRect, const KisGLTexturesInfo *texturesInfo,
73 const QByteArray &fillData, KisOpenGL::FilterMode filter,
74 KisOpenGLBufferCircularStorage *bufferStorage, int numMipmapLevels, QOpenGLFunctions *fcn)
75
76 : m_textureId(0)
77 , m_tileRectInImagePixels(imageRect)
78 , m_filter(filter)
79 , m_texturesInfo(texturesInfo)
80 , m_needsMipmapRegeneration(false)
81 , m_preparedLodPlane(0)
82 , m_numMipmapLevels(numMipmapLevels)
83 , f(fcn)
84 , m_bufferStorage(bufferStorage)
85{
86 const GLvoid *fd = fillData.constData();
87
90
94
95 f->glGenTextures(1, &m_textureId);
96 f->glBindTexture(GL_TEXTURE_2D, m_textureId);
97
99
102
103 f->glTexImage2D(GL_TEXTURE_2D, 0,
108 m_texturesInfo->type, fd);
109
111
113}
114
116{
117 f->glDeleteTextures(1, &m_textureId);
118}
119
120int KisTextureTile::bindToActiveTexture(bool blockMipmapRegeneration)
121{
122 f->glBindTexture(GL_TEXTURE_2D, m_textureId);
123
124 if (m_needsMipmapRegeneration && !blockMipmapRegeneration) {
127 }
128
129 return m_preparedLodPlane;
130}
131
140
146
148{
149 f->glGenerateMipmap(GL_TEXTURE_2D);
152}
153
154void KisTextureTile::update(const KisTextureTileUpdateInfo &updateInfo, bool blockMipmapRegeneration)
155{
156 f->glBindTexture(GL_TEXTURE_2D, m_textureId);
157
159
160 const int patchLevelOfDetail = updateInfo.patchLevelOfDetail();
161 const QSize patchSize = updateInfo.realPatchSize();
162 const QPoint patchOffset = updateInfo.realPatchOffset();
163
192 if (!blockMipmapRegeneration &&
193 patchLevelOfDetail > 0 &&
195 !updateInfo.isEntireTileUpdated())
197
199 }
200
201 /*
202 * To avoid unsightly seams in wraparound mode, we extend the tile at the
203 * edges by just repeating the top/left/right/bottom row/column until the
204 * end of the texture. For that, we shuffle the data into a buffer, then
205 * pass that to the PBO. Previously, this code used to allocate up to four
206 * additional, single-pixel thick (and sometimes zero-pixel long) PBOs and
207 * hammer out the extensions through multiple calls to glTexSubImage2D, but
208 * that caused very long stalls on Android. If you are in the future and
209 * for some reason need to revert that, also update KisOpenGLImageTextures
210 * to properly account for these extra PBOs being used, since it assumes
211 * each tile only grabs one PBO from the circular buffer storage.
212 */
213 QSize tileSize = updateInfo.realTileSize();
214 int pixelSize = updateInfo.pixelSize();
215 int centerWidth = patchSize.width();
216 int centerHeight = patchSize.height();
217
218 int topHeight;
219 if (updateInfo.isTopmost()) {
220 topHeight = patchOffset.y();
221 } else {
222 topHeight = 0;
223 }
224
225 int leftWidth;
226 if (updateInfo.isLeftmost()) {
227 leftWidth = patchOffset.x();
228 } else {
229 leftWidth = 0;
230 }
231
232 int rightWidth;
233 if (updateInfo.isRightmost()) {
234 rightWidth = tileSize.width() - patchOffset.x() - centerWidth;
235 } else {
236 rightWidth = 0;
237 }
238
239 int bottomHeight;
240 if (updateInfo.isBottommost()) {
241 bottomHeight = tileSize.height() - patchOffset.y() - centerHeight;
242 } else {
243 bottomHeight = 0;
244 }
245
246 if (topHeight > 0 || leftWidth > 0 || rightWidth > 0 || bottomHeight > 0) {
247 int bufWidth = leftWidth + centerWidth + rightWidth;
248 int bufHeight = topHeight + centerHeight + bottomHeight;
249
250 int centerStride = centerWidth * pixelSize;
251 int leftStride = leftWidth * pixelSize;
252 int rightStride = rightWidth * pixelSize;
253 int bufStride = bufWidth * pixelSize;
254
255 QByteArray buf(bufStride * bufHeight, 0);
256 quint8 *bufData = reinterpret_cast<quint8 *>(buf.data());
257 const quint8 *patchData = updateInfo.data();
258
259 if (topHeight > 0) {
260 const quint8 *topSrcPtr = patchData;
261 quint8 *topDstPtr = bufData + leftStride;
262 for (int y = 0; y < topHeight; ++y) {
263 memcpy(topDstPtr, topSrcPtr, centerStride);
264 topDstPtr += bufStride;
265 }
266 }
267
268 if (leftWidth > 0) {
269 int leftDstSkip = centerStride + rightStride;
270 const quint8 *leftSrcPtr = patchData;
271 quint8 *leftDstPtr = bufData + (topHeight * bufStride);
272 for (int y = 0; y < centerHeight; ++y) {
273 for (int x = 0; x < leftWidth; ++x) {
274 memcpy(leftDstPtr, leftSrcPtr, pixelSize);
275 leftDstPtr += pixelSize;
276 }
277 leftSrcPtr += centerStride;
278 leftDstPtr += leftDstSkip;
279 }
280 }
281
282 {
283 const quint8 *centerSrcPtr = patchData;
284 quint8 *centerDstPtr = bufData + (topHeight * bufStride) + leftStride;
285 for (int y = 0; y < centerHeight; ++y) {
286 memcpy(centerDstPtr, centerSrcPtr, centerStride);
287 centerSrcPtr += centerStride;
288 centerDstPtr += bufStride;
289 }
290 }
291
292 if (rightWidth > 0) {
293 int rightDstSkip = leftStride + centerStride;
294 const quint8 *rightSrcPtr = patchData + (centerStride - pixelSize);
295 quint8 *rightDstPtr = bufData + (topHeight * bufStride) + rightDstSkip;
296 for (int y = 0; y < centerHeight; ++y) {
297 for (int x = 0; x < rightWidth; ++x) {
298 memcpy(rightDstPtr, rightSrcPtr, pixelSize);
299 rightDstPtr += pixelSize;
300 }
301 rightSrcPtr += centerStride;
302 rightDstPtr += rightDstSkip;
303 }
304 }
305
306 if (bottomHeight > 0) {
307 const quint8 *bottomSrcPtr = patchData + ((centerHeight - 1) * centerStride);
308 quint8 *bottomDstPtr = bufData + ((topHeight + centerHeight) * bufStride) + leftStride;
309 for (int y = 0; y < bottomHeight; ++y) {
310 memcpy(bottomDstPtr, bottomSrcPtr, centerStride);
311 bottomDstPtr += bufStride;
312 }
313 }
314
315 const GLvoid *fd = bufData;
317 f->glTexSubImage2D(GL_TEXTURE_2D,
318 patchLevelOfDetail,
319 patchOffset.x() - leftWidth,
320 patchOffset.y() - topHeight,
321 bufWidth,
322 bufHeight,
325 fd);
326
327 } else if (updateInfo.isEntireTileUpdated()) {
328 const GLvoid *fd = updateInfo.data();
330 m_bufferStorage, &fd, updateInfo.patchPixelsLength());
331
332 f->glTexImage2D(GL_TEXTURE_2D, patchLevelOfDetail,
334 patchSize.width(),
335 patchSize.height(), 0,
338 fd);
339
340 } else {
341 const GLvoid *fd = updateInfo.data();
342 const int size = centerWidth * centerHeight * pixelSize;
344 m_bufferStorage, &fd, size);
345
346 f->glTexSubImage2D(GL_TEXTURE_2D, patchLevelOfDetail,
347 patchOffset.x(), patchOffset.y(),
348 patchSize.width(), patchSize.height(),
351 fd);
352 }
353
356 // if (!updateInfo.isEntireTileUpdated() &&
357 // !(!patchLevelOfDetail || !m_preparedLodPlane || patchLevelOfDetail == m_preparedLodPlane)) {
358 // qDebug() << "WARNING: LodN switch is requested for the partial tile update!. Flickering is possible..." << ppVar(patchSize);
359 // qDebug() << " " << ppVar(m_preparedLodPlane);
360 // qDebug() << " " << ppVar(patchLevelOfDetail);
361 // }
362
364
365 if (!patchLevelOfDetail) {
376 } else {
378 }
379 } else {
380 setPreparedLodPlane(patchLevelOfDetail);
381 }
382}
383
384QRectF KisTextureTile::imageRectInTexturePixels(const QRect &imageRect) const
385{
387 imageRect,
389
390}
@ NearestFilterMode
Definition kis_opengl.h:34
@ HighQualityFiltering
Definition kis_opengl.h:37
@ BilinearFilterMode
Definition kis_opengl.h:35
@ TrilinearFilterMode
Definition kis_opengl.h:36
QRect m_textureRectInImagePixels
const KisGLTexturesInfo * m_texturesInfo
QOpenGLFunctions * f
void restoreTextureParameters()
QRectF m_tileRectInTexturePixels
void setPreparedLodPlane(int lod)
KisOpenGL::FilterMode m_filter
KisTextureTile(const QRect &imageRect, const KisGLTexturesInfo *texturesInfo, const QByteArray &fillData, KisOpenGL::FilterMode mode, KisOpenGLBufferCircularStorage *bufferStorage, int numMipmapLevels, QOpenGLFunctions *f)
void update(const KisTextureTileUpdateInfo &updateInfo, bool blockMipmapRegeneration)
void setNeedsMipmapRegeneration()
int bindToActiveTexture(bool blockMipmapRegeneration)
QRect m_tileRectInImagePixels
KisOpenGLBufferCircularStorage * m_bufferStorage
QRectF imageRectInTexturePixels(const QRect &imageRect) const
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
void fillData(KisPaintDeviceSP pd, int w, int h, QDataStream &stream)
#define GL_RGBA16_EXT
#define GL_CLAMP_TO_EDGE
QRectF relativeRect(const QRect &br, const QRect &cr, const KisGLTexturesInfo *texturesInfo)