20QOpenGLTextureGlyphCache::QOpenGLTextureGlyphCache(QFontEngine::GlyphFormat format,
const QTransform &matrix,
const QColor &color)
21 : QImageTextureGlyphCache(format, matrix, color)
22 , m_textureResource(
nullptr)
24 , m_blitProgram(
nullptr)
25 , m_filterMode(Nearest)
26 , m_serialNumber(next_qopengltextureglyphcache_serial_number())
27 , m_buffer(QOpenGLBuffer::VertexBuffer)
29#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
30 qDebug(
" -> QOpenGLTextureGlyphCache() %p for context %p.",
this, QOpenGLContext::currentContext());
32 m_vertexCoordinateArray[0] = -1.0f;
33 m_vertexCoordinateArray[1] = -1.0f;
34 m_vertexCoordinateArray[2] = 1.0f;
35 m_vertexCoordinateArray[3] = -1.0f;
36 m_vertexCoordinateArray[4] = 1.0f;
37 m_vertexCoordinateArray[5] = 1.0f;
38 m_vertexCoordinateArray[6] = -1.0f;
39 m_vertexCoordinateArray[7] = 1.0f;
41 m_textureCoordinateArray[0] = 0.0f;
42 m_textureCoordinateArray[1] = 0.0f;
43 m_textureCoordinateArray[2] = 1.0f;
44 m_textureCoordinateArray[3] = 0.0f;
45 m_textureCoordinateArray[4] = 1.0f;
46 m_textureCoordinateArray[5] = 1.0f;
47 m_textureCoordinateArray[6] = 0.0f;
48 m_textureCoordinateArray[7] = 1.0f;
66void QOpenGLTextureGlyphCache::createTextureData(
int width,
int height)
68 QOpenGLContext *ctx =
const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
70 qWarning(
"QOpenGLTextureGlyphCache::createTextureData: Called with no context");
77 if (ctx->d_func()->workaround_brokenFBOReadBack && image().isNull())
78 QImageTextureGlyphCache::createTextureData(width, height);
86 if (m_textureResource && !m_textureResource->m_texture) {
87 delete m_textureResource;
88 m_textureResource =
nullptr;
91 if (!m_textureResource)
92 m_textureResource =
new QOpenGLGlyphTexture(ctx);
94 QOpenGLFunctions *funcs = ctx->functions();
95 funcs->glGenTextures(1, &m_textureResource->m_texture);
96 funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
98 m_textureResource->m_width = width;
99 m_textureResource->m_height = height;
101 if (m_format == QFontEngine::Format_A32 || m_format == QFontEngine::Format_ARGB) {
102 QVarLengthArray<uchar> data(width * height * 4);
103 for (
int i = 0; i < data.size(); ++i)
105 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
107 QVarLengthArray<uchar> data(width * height);
108 for (
int i = 0; i < data.size(); ++i)
110#if !QT_CONFIG(opengles2)
111 const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA;
112 const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
114 const GLint internalFormat = GL_ALPHA;
115 const GLenum format = GL_ALPHA;
117 funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, &data[0]);
120 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
121 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
122 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
123 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
124 m_filterMode = Nearest;
126 if (!m_buffer.isCreated()) {
129 static GLfloat buf[
sizeof(m_vertexCoordinateArray) +
sizeof(m_textureCoordinateArray)];
130 memcpy(buf, m_vertexCoordinateArray,
sizeof(m_vertexCoordinateArray));
131 memcpy(buf + (
sizeof(m_vertexCoordinateArray) /
sizeof(GLfloat)),
132 m_textureCoordinateArray,
133 sizeof(m_textureCoordinateArray));
134 m_buffer.allocate(buf,
sizeof(buf));
138 if (!m_vao.isCreated())
157 QOpenGLFunctions *funcs = ctx->functions();
159 const int imgWidth = img.width();
160 const int imgHeight = img.height();
162 if (img.format() == QImage::Format_Mono) {
163 img = img.convertToFormat(QImage::Format_Grayscale8);
164 }
else if (img.depth() == 32) {
165 if (img.format() == QImage::Format_RGB32
168#if Q_BYTE_ORDER == Q_BIG_ENDIAN
169 || img.format() == QImage::Format_ARGB32_Premultiplied
171 || (img.format() == QImage::Format_ARGB32_Premultiplied
172 && ctx->isOpenGLES())
175 for (
int y = 0; y < imgHeight; ++y) {
176 QRgb *src = (
QRgb *) img.scanLine(y);
177 for (
int x = 0; x < imgWidth; ++x) {
182 if (img.format() == QImage::Format_RGB32)
183 avg = (r + g + b + 1) / 3;
189#if Q_BYTE_ORDER != Q_BIG_ENDIAN
190 if (ctx->isOpenGLES())
192 src[x] = ARGB2RGBA(src[x]);
198 funcs->glBindTexture(GL_TEXTURE_2D, texture);
199 if (img.depth() == 32) {
200#if QT_CONFIG(opengles2)
201 GLenum fmt = GL_RGBA;
203 GLenum fmt = ctx->isOpenGLES() ? GL_RGBA : GL_BGRA;
206#if Q_BYTE_ORDER == Q_BIG_ENDIAN
209 funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, fmt, GL_UNSIGNED_BYTE, img.constBits());
213#if !QT_CONFIG(opengles2)
214 const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
216 const GLenum format = GL_ALPHA;
218 funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, format, GL_UNSIGNED_BYTE, img.constBits());
240void QOpenGLTextureGlyphCache::resizeTextureData(
int width,
int height)
242 QOpenGLContext *ctx = QOpenGLContext::currentContext();
243 if (ctx ==
nullptr) {
244 qWarning(
"QOpenGLTextureGlyphCache::resizeTextureData: Called with no context");
248 QOpenGLFunctions *funcs = ctx->functions();
250 funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFbo);
252 int oldWidth = m_textureResource->m_width;
253 int oldHeight = m_textureResource->m_height;
261 GLuint oldTexture = m_textureResource->m_texture;
262 createTextureData(width, height);
264 if (ctx->d_func()->workaround_brokenFBOReadBack) {
265 QImageTextureGlyphCache::resizeTextureData(width, height);
266 load_glyph_image_region_to_texture(ctx, image(), 0, 0, qMin(oldWidth, width), qMin(oldHeight, height),
267 m_textureResource->m_texture, 0, 0);
274 funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo);
277 funcs->glGenTextures(1, &tmp_texture);
278 funcs->glBindTexture(GL_TEXTURE_2D, tmp_texture);
279 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
280 GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
281 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
282 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
283 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
284 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
285 m_filterMode = Nearest;
286 funcs->glBindTexture(GL_TEXTURE_2D, 0);
287 funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
288 GL_TEXTURE_2D, tmp_texture, 0);
290 funcs->glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
291 funcs->glBindTexture(GL_TEXTURE_2D, oldTexture);
294 pex->transferMode(BrushDrawingMode);
296 funcs->glDisable(GL_STENCIL_TEST);
297 funcs->glDisable(GL_DEPTH_TEST);
298 funcs->glDisable(GL_SCISSOR_TEST);
299 funcs->glDisable(GL_BLEND);
301 funcs->glViewport(0, 0, oldWidth, oldHeight);
303 QOpenGLShaderProgram *blitProgram =
nullptr;
304 if (pex ==
nullptr) {
305 if (m_blitProgram ==
nullptr) {
306 m_blitProgram =
new QOpenGLShaderProgram;
307 const bool isCoreProfile = ctx->format().profile() == QSurfaceFormat::CoreProfile;
312 source.append(QLatin1StringView(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader));
313 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader));
315 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader));
316 source.append(QLatin1StringView(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader));
318 m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, source);
324 source.append(QLatin1StringView(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader));
325 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader));
327 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader));
328 source.append(QLatin1StringView(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader));
330 m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, source);
333 m_blitProgram->bindAttributeLocation(
"vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
334 m_blitProgram->bindAttributeLocation(
"textureCoordArray", QT_TEXTURE_COORDS_ATTR);
336 m_blitProgram->link();
338 if (m_vao.isCreated()) {
340 setupVertexAttribs();
344 if (m_vao.isCreated())
347 setupVertexAttribs();
349 m_blitProgram->bind();
350 blitProgram = m_blitProgram;
353 pex->uploadData(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray, 8);
354 pex->uploadData(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray, 8);
356 pex->shaderManager->useBlitProgram();
357 blitProgram = pex->shaderManager->blitProgram();
360 blitProgram->setUniformValue(
"imageTexture", QT_IMAGE_TEXTURE_UNIT);
362 funcs->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
364 funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
366 funcs->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
368 funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
370 funcs->glDeleteTextures(1, &tmp_texture);
371 funcs->glDeleteTextures(1, &oldTexture);
373 funcs->glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)oldFbo);
375 if (pex !=
nullptr) {
376 funcs->glViewport(0, 0, pex->width, pex->height);
377 pex->updateClipScissorTest();
379 if (m_vao.isCreated()) {
382 m_blitProgram->disableAttributeArray(
int(QT_VERTEX_COORDS_ATTR));
383 m_blitProgram->disableAttributeArray(
int(QT_TEXTURE_COORDS_ATTR));
static void load_glyph_image_region_to_texture(QOpenGLContext *ctx, const QImage &srcImg, int x, int y, int w, int h, GLuint texture, int tx, int ty)