Qt 4.8
qtextureglyphcache_gl.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
44 #include "private/qglengineshadersource_p.h"
45 
46 #if defined QT_OPENGL_ES_2 && !defined(QT_NO_EGL)
47 #include "private/qeglcontext_p.h"
48 #endif
49 
51 
52 #ifdef Q_WS_WIN
54 #endif
55 
57 
60  , ctx(0)
61  , pex(0)
62  , m_blitProgram(0)
63  , m_filterMode(Nearest)
64  , m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
65 {
66 #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
67  qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, ctx);
68 #endif
69  setContext(context);
70 
71  m_vertexCoordinateArray[0] = -1.0f;
72  m_vertexCoordinateArray[1] = -1.0f;
73  m_vertexCoordinateArray[2] = 1.0f;
74  m_vertexCoordinateArray[3] = -1.0f;
75  m_vertexCoordinateArray[4] = 1.0f;
76  m_vertexCoordinateArray[5] = 1.0f;
77  m_vertexCoordinateArray[6] = -1.0f;
78  m_vertexCoordinateArray[7] = 1.0f;
79 
80  m_textureCoordinateArray[0] = 0.0f;
81  m_textureCoordinateArray[1] = 0.0f;
82  m_textureCoordinateArray[2] = 1.0f;
83  m_textureCoordinateArray[3] = 0.0f;
84  m_textureCoordinateArray[4] = 1.0f;
85  m_textureCoordinateArray[5] = 1.0f;
86  m_textureCoordinateArray[6] = 0.0f;
87  m_textureCoordinateArray[7] = 1.0f;
88 }
89 
91 {
92 #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
93  qDebug(" -> ~QGLTextureGlyphCache() %p.", this);
94 #endif
95  delete m_blitProgram;
96 }
97 
99 {
100  ctx = context;
101  m_h = 0;
102 }
103 
105 {
106  if (ctx == 0) {
107  qWarning("QGLTextureGlyphCache::createTextureData: Called with no context");
108  return;
109  }
110 
111  // create in QImageTextureGlyphCache baseclass is meant to be called
112  // only to create the initial image and does not preserve the content,
113  // so we don't call when this function is called from resize.
116 
117  // Make the lower glyph texture size 16 x 16.
118  if (width < 16)
119  width = 16;
120  if (height < 16)
121  height = 16;
122 
123  QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
124  glGenTextures(1, &glyphTexture->m_texture);
125  glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
126 
127  glyphTexture->m_width = width;
128  glyphTexture->m_height = height;
129 
131  QVarLengthArray<uchar> data(width * height * 4);
132  for (int i = 0; i < data.size(); ++i)
133  data[i] = 0;
134  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
135  } else {
136  QVarLengthArray<uchar> data(width * height);
137  for (int i = 0; i < data.size(); ++i)
138  data[i] = 0;
139  glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
140  }
141 
147 }
148 
150 {
151  if (ctx == 0) {
152  qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context");
153  return;
154  }
155  QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
156 
157  int oldWidth = glyphTexture->m_width;
158  int oldHeight = glyphTexture->m_height;
159 
160  // Make the lower glyph texture size 16 x 16.
161  if (width < 16)
162  width = 16;
163  if (height < 16)
164  height = 16;
165 
166  GLuint oldTexture = glyphTexture->m_texture;
167  createTextureData(width, height);
168 
171  Q_ASSERT(image().depth() == 8);
172  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits());
173  glDeleteTextures(1, &oldTexture);
174  return;
175  }
176 
177  // ### the QTextureGlyphCache API needs to be reworked to allow
178  // ### resizeTextureData to fail
179 
181 
182  GLuint tmp_texture;
183  glGenTextures(1, &tmp_texture);
184  glBindTexture(GL_TEXTURE_2D, tmp_texture);
185  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
186  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
192  glBindTexture(GL_TEXTURE_2D, 0);
194  GL_TEXTURE_2D, tmp_texture, 0);
195 
197  glBindTexture(GL_TEXTURE_2D, oldTexture);
198 
199  if (pex != 0)
201 
202  glDisable(GL_STENCIL_TEST);
203  glDisable(GL_DEPTH_TEST);
204  glDisable(GL_SCISSOR_TEST);
205  glDisable(GL_BLEND);
206 
207  glViewport(0, 0, oldWidth, oldHeight);
208 
209  QGLShaderProgram *blitProgram = 0;
210  if (pex == 0) {
211  if (m_blitProgram == 0) {
213 
214  {
215  QString source;
218 
219  QGLShader *vertexShader = new QGLShader(QGLShader::Vertex, m_blitProgram);
220  vertexShader->compileSourceCode(source);
221 
222  m_blitProgram->addShader(vertexShader);
223  }
224 
225  {
226  QString source;
229 
230  QGLShader *fragmentShader = new QGLShader(QGLShader::Fragment, m_blitProgram);
231  fragmentShader->compileSourceCode(source);
232 
233  m_blitProgram->addShader(fragmentShader);
234  }
235 
238 
239  m_blitProgram->link();
240  }
241 
244 
245  m_blitProgram->bind();
249 
250  blitProgram = m_blitProgram;
251 
252  } else {
255 
257  blitProgram = pex->shaderManager->blitProgram();
258  }
259 
260  blitProgram->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
261 
262  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
263 
264  glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
265 
266  glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
267 
270  glDeleteTextures(1, &tmp_texture);
271  glDeleteTextures(1, &oldTexture);
272 
274 
275  if (pex != 0) {
276  glViewport(0, 0, pex->width, pex->height);
278  }
279 }
280 
281 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
282 {
283  if (ctx == 0) {
284  qWarning("QGLTextureGlyphCache::fillTexture: Called with no context");
285  return;
286  }
287 
288  QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
290  QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition);
291 
292  glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
293  const QImage &texture = image();
294  const uchar *bits = texture.constBits();
295  bits += c.y * texture.bytesPerLine() + c.x;
296  for (int i=0; i<c.h; ++i) {
297  glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits);
298  bits += texture.bytesPerLine();
299  }
300  return;
301  }
302 
303  QImage mask = textureMapForGlyph(glyph, subPixelPosition);
304  const int maskWidth = mask.width();
305  const int maskHeight = mask.height();
306 
307  if (mask.format() == QImage::Format_Mono) {
309  for (int y = 0; y < maskHeight; ++y) {
310  uchar *src = (uchar *) mask.scanLine(y);
311  for (int x = 0; x < maskWidth; ++x)
312  src[x] = -src[x]; // convert 0 and 1 into 0 and 255
313  }
314  } else if (mask.format() == QImage::Format_RGB32) {
315  // Make the alpha component equal to the average of the RGB values.
316  // This is needed when drawing sub-pixel antialiased text on translucent targets.
317  for (int y = 0; y < maskHeight; ++y) {
318  quint32 *src = (quint32 *) mask.scanLine(y);
319  for (int x = 0; x < maskWidth; ++x) {
320  uchar r = src[x] >> 16;
321  uchar g = src[x] >> 8;
322  uchar b = src[x];
323  quint32 avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding.
324  src[x] = (src[x] & 0x00ffffff) | (avg << 24);
325  }
326  }
327  }
328 
329  glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
330  if (mask.format() == QImage::Format_RGB32) {
331  glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
332  } else {
333  // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
334  // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
335  // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a
336  // multiple of four bytes per line, and most of the glyph shows up correctly in the
337  // texture, which makes me think that this is a driver bug.
338  // One workaround is to make sure the mask width is a multiple of four bytes, for instance
339  // by converting it to a format with four bytes per pixel. Another is to copy one line at a
340  // time.
341 
343  // don't know which driver versions exhibit this bug, so be conservative for now
344  const QByteArray vendorString(reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
345  ctx->d_ptr->workaround_brokenAlphaTexSubImage = vendorString.indexOf("NVIDIA") >= 0;
347  }
348 
350  for (int i = 0; i < maskHeight; ++i)
351  glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
352  } else {
353  glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
354  }
355  }
356 }
357 
359 {
360  return 1;
361 }
362 
364 {
365  if (ctx == 0)
367  else
368  return ctx->d_ptr->maxTextureSize();
369 }
370 
372 {
373  if (ctx == 0)
375 
377  return qMin(1024, ctx->d_ptr->maxTextureSize());
378  else
379  return ctx->d_ptr->maxTextureSize();
380 }
381 
383 {
384  if (ctx != 0) {
386 
387  m_w = 0;
388  m_h = 0;
389  m_cx = 0;
390  m_cy = 0;
391  m_currentRowHeight = 0;
392  coords.clear();
393  }
394 }
395 
void bindAttributeLocation(const char *name, int location)
Binds the attribute name to the specified location.
static bool hasOpenGLFramebufferObjects()
Returns true if the OpenGL GL_EXT_framebuffer_object extension is present on this system; otherwise r...
virtual int maxTextureWidth() const
#define GL_BGRA
Definition: glfunctions.h:63
void disableAttributeArray(int location)
Disables the vertex array at location in this shader program that was enabled by a previous call to e...
QScopedPointer< QGLContextPrivate > d_ptr
Definition: qgl.h:430
void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer)
int type
Definition: qmetatype.cpp:239
#define GL_CLAMP_TO_EDGE
Definition: glfunctions.h:62
#define GL_TEXTURE_MIN_FILTER
bool compileSourceCode(const char *source)
Sets the source code for this shader and compiles it.
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
T * value(const QGLContext *context)
Definition: qgl_p.h:775
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QHash< GlyphAndSubPixelPosition, Coord > coords
Q_GUI_EXPORT bool qt_cleartype_enabled
QGLEngineShaderManager * shaderManager
static const char *const qglslMainFragmentShader
#define GL_DEPTH_TEST
#define QT_IMAGE_TEXTURE_UNIT
const QImage & image() const
virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
QGLShaderProgram * blitProgram()
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
virtual void createTextureData(int width, int height)
#define glVertexAttribPointer
Definition: glfunctions.h:71
#define GL_TEXTURE_WRAP_S
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
int bytesPerLine() const
Returns the number of bytes per image scanline.
Definition: qimage.cpp:1812
uint workaround_brokenTexSubImage
Definition: qgl_p.h:433
#define GL_FRAMEBUFFER_EXT
The QString class provides a Unicode character string.
Definition: qstring.h:83
QImage textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
#define GL_STENCIL_TEST
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Definition: qbasicatomic.h:218
virtual int maxTextureHeight() const
#define glBindFramebuffer
#define GL_TEXTURE_2D
void cleanup(const QGLContext *context)
Definition: qgl.cpp:5928
QFontEngineGlyphCache::Type m_type
Format format() const
Returns the format of the image.
Definition: qimage.cpp:2305
#define GL_COLOR_ATTACHMENT0_EXT
uint workaround_brokenAlphaTexSubImage
Definition: qgl_p.h:440
#define GL_SCISSOR_TEST
virtual void createTextureData(int width, int height)
static const GLuint QT_OPACITY_ATTR
const QGLContext * context() const
Q_CORE_EXPORT void qDebug(const char *,...)
#define GL_FALSE
#define GL_TEXTURE0
Definition: glfunctions.h:61
unsigned char uchar
Definition: qglobal.h:994
QGLContextGroupResource< QGLGlyphTexture > m_textureResource
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
virtual void resizeTextureData(int width, int height)
#define GL_ALPHA
The QGLContext class encapsulates an OpenGL rendering context.
Definition: qgl.h:310
#define GL_RENDERBUFFER_EXT
The QGLShader class allows OpenGL shaders to be compiled.
uint workaround_brokenAlphaTexSubImage_init
Definition: qgl_p.h:441
Q_CORE_EXPORT void qWarning(const char *,...)
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
virtual int glyphPadding() const
static const char * data(const QByteArray &arr)
#define GL_TRIANGLE_FAN
QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
#define GL_FLOAT
const uchar * constBits() const
Returns a pointer to the first pixel data.
Definition: qimage.cpp:1985
int indexOf(char c, int from=0) const
Returns the index position of the first occurrence of the character ch in the byte array...
#define glActiveTexture
Definition: glfunctions.h:69
#define GL_BLEND
virtual bool link()
Links together the shaders that were added to this program with addShader().
uchar * bits()
Returns a pointer to the first pixel data.
Definition: qimage.cpp:1946
#define GL_TEXTURE_WRAP_T
GLuint current_fbo
Definition: qgl_p.h:456
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const Q_REQUIRED_RESULT
Returns a copy of the image in the given format.
Definition: qimage.cpp:3966
QString & append(QChar c)
Definition: qstring.cpp:1777
void setUniformValue(int location, GLfloat value)
Sets the uniform variable at location in the current context to value.
int maxTextureSize()
Definition: qgl.cpp:2775
QGLShaderProgram * m_blitProgram
#define GL_UNSIGNED_BYTE
#define ctx
Definition: qgl.cpp:6094
#define GL_VENDOR
unsigned int quint32
Definition: qglobal.h:938
static const GLuint QT_TEXTURE_COORDS_ATTR
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
bool addShader(QGLShader *shader)
Adds a compiled shader to this shader program.
static const char *const qglslMainWithTexCoordsVertexShader
#define GL_RGBA
QBasicAtomicInt qgltextureglyphcache_serial_number
#define glFramebufferRenderbuffer
void transferMode(EngineMode newMode)
virtual int maxTextureWidth() const
static const char *const qglslImageSrcFragmentShader
static const char *const qglslUntransformedPositionVertexShader
#define GL_TEXTURE_MAG_FILTER
static const GLuint QT_VERTEX_COORDS_ATTR
bool bind()
Binds this shader program to the active QGLContext and makes it the current shader program...
#define glFramebufferTexture2D
QGL2PaintEngineExPrivate * pex
void enableAttributeArray(int location)
Enables the vertex array at location in this shader program so that the value set by setAttributeArra...
The QGLShaderProgram class allows OpenGL shader programs to be linked and used.
unsigned int glyph_t
virtual void resizeTextureData(int width, int height)
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition: qimage.cpp:1886
int size() const
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
uint workaround_brokenFBOReadBack
Definition: qgl_p.h:432
void setContext(const QGLContext *context)
virtual int maxTextureHeight() const
#define GL_NEAREST