21QOpenGLTextureGlyphCache::QOpenGLTextureGlyphCache(QFontEngine::GlyphFormat format,
const QTransform &matrix,
const QColor &color)
22 : QImageTextureGlyphCache(format, matrix, color)
23 , m_textureResource(
nullptr)
25 , m_blitProgram(
nullptr)
26 , m_filterMode(Nearest)
27 , m_serialNumber(next_qopengltextureglyphcache_serial_number())
28 , m_buffer(QOpenGLBuffer::VertexBuffer)
30#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
31 qDebug(
" -> QOpenGLTextureGlyphCache() %p for context %p.",
this, QOpenGLContext::currentContext());
33 m_vertexCoordinateArray[0] = -1.0f;
34 m_vertexCoordinateArray[1] = -1.0f;
35 m_vertexCoordinateArray[2] = 1.0f;
36 m_vertexCoordinateArray[3] = -1.0f;
37 m_vertexCoordinateArray[4] = 1.0f;
38 m_vertexCoordinateArray[5] = 1.0f;
39 m_vertexCoordinateArray[6] = -1.0f;
40 m_vertexCoordinateArray[7] = 1.0f;
42 m_textureCoordinateArray[0] = 0.0f;
43 m_textureCoordinateArray[1] = 0.0f;
44 m_textureCoordinateArray[2] = 1.0f;
45 m_textureCoordinateArray[3] = 0.0f;
46 m_textureCoordinateArray[4] = 1.0f;
47 m_textureCoordinateArray[5] = 1.0f;
48 m_textureCoordinateArray[6] = 0.0f;
49 m_textureCoordinateArray[7] = 1.0f;
67void QOpenGLTextureGlyphCache::createTextureData(
int width,
int height)
69 QOpenGLContext *ctx =
const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
71 qWarning(
"QOpenGLTextureGlyphCache::createTextureData: Called with no context");
78 if (ctx->d_func()->workaround_brokenFBOReadBack && image().isNull())
79 QImageTextureGlyphCache::createTextureData(width, height);
87 if (m_textureResource && !m_textureResource->m_texture) {
88 delete m_textureResource;
89 m_textureResource =
nullptr;
92 if (!m_textureResource)
93 m_textureResource =
new QOpenGLGlyphTexture(ctx);
95 QOpenGLFunctions *funcs = ctx->functions();
96 funcs->glGenTextures(1, &m_textureResource->m_texture);
97 funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
99 m_textureResource->m_width = width;
100 m_textureResource->m_height = height;
102 if (m_format == QFontEngine::Format_A32 || m_format == QFontEngine::Format_ARGB) {
103 QVarLengthArray<uchar> data(width * height * 4);
104 for (
int i = 0; i < data.size(); ++i)
106 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
108 QVarLengthArray<uchar> data(width * height);
109 for (
int i = 0; i < data.size(); ++i)
111#if !QT_CONFIG(opengles2)
112 const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA;
113 const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
115 const GLint internalFormat = GL_ALPHA;
116 const GLenum format = GL_ALPHA;
118 funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, &data[0]);
121 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
122 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
123 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
124 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
125 m_filterMode = Nearest;
127 if (!m_buffer.isCreated()) {
130 static GLfloat buf[
sizeof(m_vertexCoordinateArray) +
sizeof(m_textureCoordinateArray)];
131 memcpy(buf, m_vertexCoordinateArray,
sizeof(m_vertexCoordinateArray));
132 memcpy(buf + (
sizeof(m_vertexCoordinateArray) /
sizeof(GLfloat)),
133 m_textureCoordinateArray,
134 sizeof(m_textureCoordinateArray));
135 m_buffer.allocate(buf,
sizeof(buf));
139 if (!m_vao.isCreated())
158 QOpenGLFunctions *funcs = ctx->functions();
160 const int imgWidth = img.width();
161 const int imgHeight = img.height();
163 if (img.format() == QImage::Format_Mono) {
164 img = img.convertToFormat(QImage::Format_Grayscale8);
165 }
else if (img.depth() == 32) {
166 if (img.format() == QImage::Format_RGB32
169#if Q_BYTE_ORDER == Q_BIG_ENDIAN
170 || img.format() == QImage::Format_ARGB32_Premultiplied
172 || (img.format() == QImage::Format_ARGB32_Premultiplied
173 && ctx->isOpenGLES())
176 for (
int y = 0; y < imgHeight; ++y) {
177 QRgb *src = (
QRgb *) img.scanLine(y);
178 for (
int x = 0; x < imgWidth; ++x) {
183 if (img.format() == QImage::Format_RGB32)
184 avg = (r + g + b + 1) / 3;
190#if Q_BYTE_ORDER != Q_BIG_ENDIAN
191 if (ctx->isOpenGLES())
193 src[x] = ARGB2RGBA(src[x]);
199 funcs->glBindTexture(GL_TEXTURE_2D, texture);
200 if (img.depth() == 32) {
201#if QT_CONFIG(opengles2)
202 GLenum fmt = GL_RGBA;
204 GLenum fmt = ctx->isOpenGLES() ? GL_RGBA : GL_BGRA;
207#if Q_BYTE_ORDER == Q_BIG_ENDIAN
210 funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, fmt, GL_UNSIGNED_BYTE, img.constBits());
214#if !QT_CONFIG(opengles2)
215 const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
217 const GLenum format = GL_ALPHA;
219 funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, format, GL_UNSIGNED_BYTE, img.constBits());
241void QOpenGLTextureGlyphCache::resizeTextureData(
int width,
int height)
243 QOpenGLContext *ctx = QOpenGLContext::currentContext();
244 if (ctx ==
nullptr) {
245 qWarning(
"QOpenGLTextureGlyphCache::resizeTextureData: Called with no context");
249 QOpenGLFunctions *funcs = ctx->functions();
251 funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFbo);
253 int oldWidth = m_textureResource->m_width;
254 int oldHeight = m_textureResource->m_height;
262 GLuint oldTexture = m_textureResource->m_texture;
263 createTextureData(width, height);
265 if (ctx->d_func()->workaround_brokenFBOReadBack) {
266 QImageTextureGlyphCache::resizeTextureData(width, height);
267 load_glyph_image_region_to_texture(ctx, image(), 0, 0, qMin(oldWidth, width), qMin(oldHeight, height),
268 m_textureResource->m_texture, 0, 0);
275 funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo);
278 funcs->glGenTextures(1, &tmp_texture);
279 funcs->glBindTexture(GL_TEXTURE_2D, tmp_texture);
280 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
281 GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
282 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
283 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
284 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
285 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
286 m_filterMode = Nearest;
287 funcs->glBindTexture(GL_TEXTURE_2D, 0);
288 funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
289 GL_TEXTURE_2D, tmp_texture, 0);
291 funcs->glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
292 funcs->glBindTexture(GL_TEXTURE_2D, oldTexture);
295 pex->transferMode(BrushDrawingMode);
297 funcs->glDisable(GL_STENCIL_TEST);
298 funcs->glDisable(GL_DEPTH_TEST);
299 funcs->glDisable(GL_SCISSOR_TEST);
300 funcs->glDisable(GL_BLEND);
302 funcs->glViewport(0, 0, oldWidth, oldHeight);
304 QOpenGLShaderProgram *blitProgram =
nullptr;
305 if (pex ==
nullptr) {
306 if (m_blitProgram ==
nullptr) {
307 m_blitProgram =
new QOpenGLShaderProgram;
308 const bool isCoreProfile = ctx->format().profile() == QSurfaceFormat::CoreProfile;
313 source.append(QLatin1StringView(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader));
314 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader));
316 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader));
317 source.append(QLatin1StringView(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader));
319 m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, source);
325 source.append(QLatin1StringView(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader));
326 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader));
328 source.append(QLatin1StringView(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader));
329 source.append(QLatin1StringView(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader));
331 m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, source);
334 m_blitProgram->bindAttributeLocation(
"vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
335 m_blitProgram->bindAttributeLocation(
"textureCoordArray", QT_TEXTURE_COORDS_ATTR);
337 m_blitProgram->link();
339 if (m_vao.isCreated()) {
341 setupVertexAttribs();
345 if (m_vao.isCreated())
348 setupVertexAttribs();
350 m_blitProgram->bind();
351 blitProgram = m_blitProgram;
354 pex->uploadData(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray, 8);
355 pex->uploadData(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray, 8);
357 pex->shaderManager->useBlitProgram();
358 blitProgram = pex->shaderManager->blitProgram();
361 blitProgram->setUniformValue(
"imageTexture", QT_IMAGE_TEXTURE_UNIT);
363 funcs->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
365 funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
367 funcs->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
369 funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
371 funcs->glDeleteTextures(1, &tmp_texture);
372 funcs->glDeleteTextures(1, &oldTexture);
374 funcs->glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)oldFbo);
376 if (pex !=
nullptr) {
377 funcs->glViewport(0, 0, pex->width, pex->height);
378 pex->updateClipScissorTest();
380 if (m_vao.isCreated()) {
383 m_blitProgram->disableAttributeArray(
int(QT_VERTEX_COORDS_ATTR));
384 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)