40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include "qtextureglyphcache_gl_p.h" |
42 #include "qtextureglyphcache_gl_p.h" |
43 #include "qpaintengineex_opengl2_p.h" |
43 #include "qpaintengineex_opengl2_p.h" |
44 |
44 |
|
45 #if defined QT_OPENGL_ES_2 && !defined(QT_NO_EGL) |
|
46 #include "private/qeglcontext_p.h" |
|
47 #endif |
|
48 |
45 QT_BEGIN_NAMESPACE |
49 QT_BEGIN_NAMESPACE |
46 |
50 |
47 #ifdef Q_WS_WIN |
51 #ifdef Q_WS_WIN |
48 extern Q_GUI_EXPORT bool qt_cleartype_enabled; |
52 extern Q_GUI_EXPORT bool qt_cleartype_enabled; |
49 #endif |
53 #endif |
50 |
54 |
51 QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) |
55 QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) |
52 : QTextureGlyphCache(type, matrix) |
56 : QImageTextureGlyphCache(type, matrix) |
53 , ctx(context) |
57 , ctx(context) |
54 , m_width(0) |
58 , m_width(0) |
55 , m_height(0) |
59 , m_height(0) |
56 { |
60 { |
57 glGenFramebuffers(1, &m_fbo); |
61 // broken FBO readback is a bug in the SGX 1.3 and 1.4 drivers for the N900 where |
|
62 // copying between FBO's is broken if the texture is either GL_ALPHA or POT. The |
|
63 // workaround is to use a system-memory copy of the glyph cache for this device. |
|
64 // Switching to NPOT and GL_RGBA would both cost a lot more graphics memory and |
|
65 // be slower, so that is not desireable. |
|
66 if (!ctx->d_ptr->workaround_brokenFBOReadBack) |
|
67 glGenFramebuffers(1, &m_fbo); |
|
68 |
58 connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), |
69 connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), |
59 SLOT(contextDestroyed(const QGLContext*))); |
70 SLOT(contextDestroyed(const QGLContext*))); |
60 } |
71 } |
61 |
72 |
62 QGLTextureGlyphCache::~QGLTextureGlyphCache() |
73 QGLTextureGlyphCache::~QGLTextureGlyphCache() |
63 { |
74 { |
64 if (ctx) { |
75 if (ctx) { |
65 QGLShareContextScope scope(ctx); |
76 QGLShareContextScope scope(ctx); |
66 glDeleteFramebuffers(1, &m_fbo); |
77 |
|
78 if (!ctx->d_ptr->workaround_brokenFBOReadBack) |
|
79 glDeleteFramebuffers(1, &m_fbo); |
67 |
80 |
68 if (m_width || m_height) |
81 if (m_width || m_height) |
69 glDeleteTextures(1, &m_texture); |
82 glDeleteTextures(1, &m_texture); |
70 } |
83 } |
71 } |
84 } |
72 |
85 |
73 void QGLTextureGlyphCache::createTextureData(int width, int height) |
86 void QGLTextureGlyphCache::createTextureData(int width, int height) |
74 { |
87 { |
|
88 // create in QImageTextureGlyphCache baseclass is meant to be called |
|
89 // only to create the initial image and does not preserve the content, |
|
90 // so we don't call when this function is called from resize. |
|
91 if (ctx->d_ptr->workaround_brokenFBOReadBack && image().isNull()) |
|
92 QImageTextureGlyphCache::createTextureData(width, height); |
|
93 |
|
94 // Make the lower glyph texture size 16 x 16. |
|
95 if (width < 16) |
|
96 width = 16; |
|
97 if (height < 16) |
|
98 height = 16; |
|
99 |
75 glGenTextures(1, &m_texture); |
100 glGenTextures(1, &m_texture); |
76 glBindTexture(GL_TEXTURE_2D, m_texture); |
101 glBindTexture(GL_TEXTURE_2D, m_texture); |
77 |
102 |
78 m_width = width; |
103 m_width = width; |
79 m_height = height; |
104 m_height = height; |
91 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
116 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
92 } |
117 } |
93 |
118 |
94 void QGLTextureGlyphCache::resizeTextureData(int width, int height) |
119 void QGLTextureGlyphCache::resizeTextureData(int width, int height) |
95 { |
120 { |
|
121 int oldWidth = m_width; |
|
122 int oldHeight = m_height; |
|
123 |
|
124 // Make the lower glyph texture size 16 x 16. |
|
125 if (width < 16) |
|
126 width = 16; |
|
127 if (height < 16) |
|
128 height = 16; |
|
129 |
|
130 GLuint oldTexture = m_texture; |
|
131 createTextureData(width, height); |
|
132 |
|
133 if (ctx->d_ptr->workaround_brokenFBOReadBack) { |
|
134 QImageTextureGlyphCache::resizeTextureData(width, height); |
|
135 Q_ASSERT(image().depth() == 8); |
|
136 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits()); |
|
137 glDeleteTextures(1, &oldTexture); |
|
138 return; |
|
139 } |
|
140 |
96 // ### the QTextureGlyphCache API needs to be reworked to allow |
141 // ### the QTextureGlyphCache API needs to be reworked to allow |
97 // ### resizeTextureData to fail |
142 // ### resizeTextureData to fail |
98 |
|
99 int oldWidth = m_width; |
|
100 int oldHeight = m_height; |
|
101 |
|
102 GLuint oldTexture = m_texture; |
|
103 createTextureData(width, height); |
|
104 |
143 |
105 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); |
144 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); |
106 |
145 |
107 GLuint tmp_texture; |
146 GLuint tmp_texture; |
108 glGenTextures(1, &tmp_texture); |
147 glGenTextures(1, &tmp_texture); |
157 |
196 |
158 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
197 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
159 |
198 |
160 glBindTexture(GL_TEXTURE_2D, m_texture); |
199 glBindTexture(GL_TEXTURE_2D, m_texture); |
161 |
200 |
162 #ifdef QT_OPENGL_ES_2 |
|
163 QDataBuffer<uchar> buffer(4*oldWidth*oldHeight); |
|
164 buffer.resize(4*oldWidth*oldHeight); |
|
165 glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); |
|
166 |
|
167 // do an in-place conversion from GL_RGBA to GL_ALPHA |
|
168 for (int i=0; i<oldWidth*oldHeight; ++i) |
|
169 buffer.data()[i] = buffer.at(4*i + 3); |
|
170 |
|
171 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, |
|
172 GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data()); |
|
173 #else |
|
174 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); |
201 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); |
175 #endif |
|
176 |
202 |
177 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, |
203 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, |
178 GL_RENDERBUFFER_EXT, 0); |
204 GL_RENDERBUFFER_EXT, 0); |
179 glDeleteTextures(1, &tmp_texture); |
205 glDeleteTextures(1, &tmp_texture); |
180 glDeleteTextures(1, &oldTexture); |
206 glDeleteTextures(1, &oldTexture); |
185 pex->updateClipScissorTest(); |
211 pex->updateClipScissorTest(); |
186 } |
212 } |
187 |
213 |
188 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) |
214 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) |
189 { |
215 { |
|
216 if (ctx->d_ptr->workaround_brokenFBOReadBack) { |
|
217 QImageTextureGlyphCache::fillTexture(c, glyph); |
|
218 |
|
219 glBindTexture(GL_TEXTURE_2D, m_texture); |
|
220 const QImage &texture = image(); |
|
221 const uchar *bits = texture.constBits(); |
|
222 bits += c.y * texture.bytesPerLine() + c.x; |
|
223 for (int i=0; i<c.h; ++i) { |
|
224 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits); |
|
225 bits += texture.bytesPerLine(); |
|
226 } |
|
227 |
|
228 return; |
|
229 } |
|
230 |
190 QImage mask = textureMapForGlyph(glyph); |
231 QImage mask = textureMapForGlyph(glyph); |
191 const int maskWidth = mask.width(); |
232 const int maskWidth = mask.width(); |
192 const int maskHeight = mask.height(); |
233 const int maskHeight = mask.height(); |
193 |
234 |
194 if (mask.format() == QImage::Format_Mono) { |
235 if (mask.format() == QImage::Format_Mono) { |
233 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); |
274 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); |
234 #endif |
275 #endif |
235 } |
276 } |
236 } |
277 } |
237 |
278 |
238 int QGLTextureGlyphCache::glyphMargin() const |
|
239 { |
|
240 #if defined(Q_WS_MAC) |
|
241 return 2; |
|
242 #elif defined (Q_WS_X11) |
|
243 return 0; |
|
244 #else |
|
245 return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; |
|
246 #endif |
|
247 } |
|
248 |
|
249 int QGLTextureGlyphCache::glyphPadding() const |
279 int QGLTextureGlyphCache::glyphPadding() const |
250 { |
280 { |
251 return 1; |
281 return 1; |
252 } |
282 } |
253 |
283 |