source: trunk/src/opengl/qpixmapdata_gl.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 22.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qpixmap.h"
43#include "qglframebufferobject.h"
44
45#include <private/qpaintengine_raster_p.h>
46
47#include "qpixmapdata_gl_p.h"
48
49#include <private/qgl_p.h>
50#include <private/qdrawhelper_p.h>
51#include <private/qimage_p.h>
52
53#include <private/qpaintengineex_opengl2_p.h>
54
55#include <qdesktopwidget.h>
56#include <qfile.h>
57#include <qimagereader.h>
58
59QT_BEGIN_NAMESPACE
60
61extern QGLWidget* qt_gl_share_widget();
62
63/*!
64 \class QGLFramebufferObjectPool
65 \since 4.6
66
67 \brief The QGLFramebufferObject class provides a pool of framebuffer
68 objects for offscreen rendering purposes.
69
70 When requesting an FBO of a given size and format, an FBO of the same
71 format and a size at least as big as the requested size will be returned.
72
73 \internal
74*/
75
76static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo)
77{
78 return qAbs(size.width() * size.height() - fbo->width() * fbo->height());
79}
80
81extern int qt_next_power_of_two(int v);
82
83static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
84{
85#ifdef QT_OPENGL_ES_2
86 QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height()));
87 if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height())
88 return rounded;
89#endif
90 return sz;
91}
92
93
94QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
95{
96 QGLFramebufferObject *chosen = 0;
97 QGLFramebufferObject *candidate = 0;
98 for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
99 QGLFramebufferObject *fbo = m_fbos.at(i);
100
101 if (strictSize) {
102 if (fbo->size() == requestSize && fbo->format() == requestFormat) {
103 chosen = fbo;
104 break;
105 } else {
106 continue;
107 }
108 }
109
110 if (fbo->format() == requestFormat) {
111 // choose the fbo with a matching format and the closest size
112 if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
113 candidate = fbo;
114 }
115
116 if (candidate) {
117 m_fbos.removeOne(candidate);
118
119 const QSize fboSize = candidate->size();
120 QSize sz = fboSize;
121
122 if (sz.width() < requestSize.width())
123 sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5)));
124 if (sz.height() < requestSize.height())
125 sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5)));
126
127 // wasting too much space?
128 if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4)
129 sz = requestSize;
130
131 if (sz != fboSize) {
132 delete candidate;
133 candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat);
134 }
135
136 chosen = candidate;
137 }
138 }
139
140 if (!chosen) {
141 if (strictSize)
142 chosen = new QGLFramebufferObject(requestSize, requestFormat);
143 else
144 chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
145 }
146
147 if (!chosen->isValid()) {
148 delete chosen;
149 chosen = 0;
150 }
151
152 return chosen;
153}
154
155void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
156{
157 if (fbo)
158 m_fbos << fbo;
159}
160
161
162QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const
163{
164 return data->paintEngine();
165}
166
167void QGLPixmapGLPaintDevice::beginPaint()
168{
169 if (!data->isValid())
170 return;
171
172 // QGLPaintDevice::beginPaint will store the current binding and replace
173 // it with m_thisFBO:
174 m_thisFBO = data->m_renderFbo->handle();
175 QGLPaintDevice::beginPaint();
176
177 Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2);
178
179 // QPixmap::fill() is deferred until now, where we actually need to do the fill:
180 if (data->needsFill()) {
181 const QColor &c = data->fillColor();
182 float alpha = c.alphaF();
183 glDisable(GL_SCISSOR_TEST);
184 glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
185 glClear(GL_COLOR_BUFFER_BIT);
186 }
187 else if (!data->isUninitialized()) {
188 // If the pixmap (GL Texture) has valid content (it has been
189 // uploaded from an image or rendered into before), we need to
190 // copy it from the texture to the render FBO.
191
192 glDisable(GL_DEPTH_TEST);
193 glDisable(GL_SCISSOR_TEST);
194 glDisable(GL_BLEND);
195
196#if !defined(QT_OPENGL_ES_2)
197 glMatrixMode(GL_MODELVIEW);
198 glLoadIdentity();
199
200 glMatrixMode(GL_PROJECTION);
201 glLoadIdentity();
202 glOrtho(0, data->width(), data->height(), 0, -999999, 999999);
203#endif
204
205 glViewport(0, 0, data->width(), data->height());
206
207 // Pass false to bind so it doesn't copy the FBO into the texture!
208 context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false));
209 }
210}
211
212void QGLPixmapGLPaintDevice::endPaint()
213{
214 if (!data->isValid())
215 return;
216
217 data->copyBackFromRenderFbo(false);
218
219 // Base's endPaint will restore the previous FBO binding
220 QGLPaintDevice::endPaint();
221
222 qgl_fbo_pool()->release(data->m_renderFbo);
223 data->m_renderFbo = 0;
224}
225
226QGLContext* QGLPixmapGLPaintDevice::context() const
227{
228 data->ensureCreated();
229 return data->m_ctx;
230}
231
232QSize QGLPixmapGLPaintDevice::size() const
233{
234 return data->size();
235}
236
237bool QGLPixmapGLPaintDevice::alphaRequested() const
238{
239 return data->m_hasAlpha;
240}
241
242void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d)
243{
244 data = d;
245}
246
247static int qt_gl_pixmap_serial = 0;
248
249QGLPixmapData::QGLPixmapData(PixelType type)
250 : QPixmapData(type, OpenGLClass)
251 , m_renderFbo(0)
252 , m_engine(0)
253 , m_ctx(0)
254 , m_dirty(false)
255 , m_hasFillColor(false)
256 , m_hasAlpha(false)
257{
258 setSerialNumber(++qt_gl_pixmap_serial);
259 m_glDevice.setPixmapData(this);
260}
261
262QGLPixmapData::~QGLPixmapData()
263{
264 QGLWidget *shareWidget = qt_gl_share_widget();
265 if (!shareWidget)
266 return;
267
268 delete m_engine;
269
270 if (m_texture.id) {
271 QGLShareContextScope ctx(shareWidget->context());
272 glDeleteTextures(1, &m_texture.id);
273 }
274}
275
276QPixmapData *QGLPixmapData::createCompatiblePixmapData() const
277{
278 return new QGLPixmapData(pixelType());
279}
280
281bool QGLPixmapData::isValid() const
282{
283 return w > 0 && h > 0;
284}
285
286bool QGLPixmapData::isValidContext(const QGLContext *ctx) const
287{
288 if (ctx == m_ctx)
289 return true;
290
291 const QGLContext *share_ctx = qt_gl_share_widget()->context();
292 return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx);
293}
294
295void QGLPixmapData::resize(int width, int height)
296{
297 if (width == w && height == h)
298 return;
299
300 if (width <= 0 || height <= 0) {
301 width = 0;
302 height = 0;
303 }
304
305 w = width;
306 h = height;
307 is_null = (w <= 0 || h <= 0);
308 d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
309
310 if (m_texture.id) {
311 QGLShareContextScope ctx(qt_gl_share_widget()->context());
312 glDeleteTextures(1, &m_texture.id);
313 m_texture.id = 0;
314 }
315
316 m_source = QImage();
317 m_dirty = isValid();
318 setSerialNumber(++qt_gl_pixmap_serial);
319}
320
321void QGLPixmapData::ensureCreated() const
322{
323 if (!m_dirty)
324 return;
325
326 m_dirty = false;
327
328 QGLShareContextScope ctx(qt_gl_share_widget()->context());
329 m_ctx = ctx;
330
331 const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB;
332#ifdef QT_OPENGL_ES_2
333 const GLenum external_format = internal_format;
334#else
335 const GLenum external_format = qt_gl_preferredTextureFormat();
336#endif
337 const GLenum target = GL_TEXTURE_2D;
338
339 if (!m_texture.id) {
340 glGenTextures(1, &m_texture.id);
341 glBindTexture(target, m_texture.id);
342 glTexImage2D(target, 0, internal_format, w, h, 0, external_format, GL_UNSIGNED_BYTE, 0);
343 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
344 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
345 }
346
347 if (!m_source.isNull()) {
348 if (external_format == GL_RGB) {
349 const QImage tx = m_source.convertToFormat(QImage::Format_RGB888).mirrored(false, true);
350
351 glBindTexture(target, m_texture.id);
352 glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
353 GL_UNSIGNED_BYTE, tx.bits());
354 } else {
355 const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format);
356
357 glBindTexture(target, m_texture.id);
358 glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
359 GL_UNSIGNED_BYTE, tx.bits());
360 }
361
362 if (useFramebufferObjects())
363 m_source = QImage();
364 }
365
366 m_texture.options &= ~QGLContext::MemoryManagedBindOption;
367}
368
369void QGLPixmapData::fromImage(const QImage &image,
370 Qt::ImageConversionFlags flags)
371{
372 if (image.size() == QSize(w, h))
373 setSerialNumber(++qt_gl_pixmap_serial);
374 resize(image.width(), image.height());
375
376 if (pixelType() == BitmapType) {
377 m_source = image.convertToFormat(QImage::Format_MonoLSB);
378
379 } else {
380 QImage::Format format = QImage::Format_RGB32;
381 if (qApp->desktop()->depth() == 16)
382 format = QImage::Format_RGB16;
383
384 if (image.hasAlphaChannel()
385 && ((flags & Qt::NoOpaqueDetection)
386 || const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels()))
387 format = QImage::Format_ARGB32_Premultiplied;;
388
389 m_source = image.convertToFormat(format);
390 }
391
392 m_dirty = true;
393 m_hasFillColor = false;
394
395 m_hasAlpha = m_source.hasAlphaChannel();
396 w = image.width();
397 h = image.height();
398 is_null = (w <= 0 || h <= 0);
399 d = m_source.depth();
400
401 if (m_texture.id) {
402 QGLShareContextScope ctx(qt_gl_share_widget()->context());
403 glDeleteTextures(1, &m_texture.id);
404 m_texture.id = 0;
405 }
406}
407
408bool QGLPixmapData::fromFile(const QString &filename, const char *format,
409 Qt::ImageConversionFlags flags)
410{
411 if (pixelType() == QPixmapData::BitmapType)
412 return QPixmapData::fromFile(filename, format, flags);
413 QFile file(filename);
414 if (!file.open(QIODevice::ReadOnly))
415 return false;
416 QByteArray data = file.peek(64);
417 bool alpha;
418 if (m_texture.canBindCompressedTexture
419 (data.constData(), data.size(), format, &alpha)) {
420 resize(0, 0);
421 data = file.readAll();
422 file.close();
423 QGLShareContextScope ctx(qt_gl_share_widget()->context());
424 QSize size = m_texture.bindCompressedTexture
425 (data.constData(), data.size(), format);
426 if (!size.isEmpty()) {
427 w = size.width();
428 h = size.height();
429 is_null = false;
430 d = 32;
431 m_hasAlpha = alpha;
432 m_source = QImage();
433 m_dirty = isValid();
434 return true;
435 }
436 return false;
437 }
438 fromImage(QImageReader(&file, format).read(), flags);
439 return !isNull();
440}
441
442bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format,
443 Qt::ImageConversionFlags flags)
444{
445 bool alpha;
446 const char *buf = reinterpret_cast<const char *>(buffer);
447 if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) {
448 resize(0, 0);
449 QGLShareContextScope ctx(qt_gl_share_widget()->context());
450 QSize size = m_texture.bindCompressedTexture(buf, int(len), format);
451 if (!size.isEmpty()) {
452 w = size.width();
453 h = size.height();
454 is_null = false;
455 d = 32;
456 m_hasAlpha = alpha;
457 m_source = QImage();
458 m_dirty = isValid();
459 return true;
460 }
461 }
462 return QPixmapData::fromData(buffer, len, format, flags);
463}
464
465bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
466{
467 Q_UNUSED(dx);
468 Q_UNUSED(dy);
469 Q_UNUSED(rect);
470 return false;
471}
472
473void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect)
474{
475 if (data->classId() != QPixmapData::OpenGLClass || !static_cast<const QGLPixmapData *>(data)->useFramebufferObjects()) {
476 QPixmapData::copy(data, rect);
477 return;
478 }
479
480 const QGLPixmapData *other = static_cast<const QGLPixmapData *>(data);
481 if (other->m_renderFbo) {
482 QGLShareContextScope ctx(qt_gl_share_widget()->context());
483
484 resize(rect.width(), rect.height());
485 m_hasAlpha = other->m_hasAlpha;
486 ensureCreated();
487
488 if (!ctx->d_ptr->fbo)
489 glGenFramebuffers(1, &ctx->d_ptr->fbo);
490
491 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
492 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
493 GL_TEXTURE_2D, m_texture.id, 0);
494
495 if (!other->m_renderFbo->isBound())
496 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, other->m_renderFbo->handle());
497
498 glDisable(GL_SCISSOR_TEST);
499 if (ctx->d_ptr->active_engine && ctx->d_ptr->active_engine->type() == QPaintEngine::OpenGL2)
500 static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine)->invalidateState();
501
502 glBlitFramebufferEXT(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(),
503 0, 0, w, h,
504 GL_COLOR_BUFFER_BIT,
505 GL_NEAREST);
506
507 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
508 } else {
509 QPixmapData::copy(data, rect);
510 }
511}
512
513void QGLPixmapData::fill(const QColor &color)
514{
515 if (!isValid())
516 return;
517
518 bool hasAlpha = color.alpha() != 255;
519 if (hasAlpha && !m_hasAlpha) {
520 if (m_texture.id) {
521 glDeleteTextures(1, &m_texture.id);
522 m_texture.id = 0;
523 m_dirty = true;
524 }
525 m_hasAlpha = color.alpha() != 255;
526 }
527
528 if (useFramebufferObjects()) {
529 m_source = QImage();
530 m_hasFillColor = true;
531 m_fillColor = color;
532 } else {
533
534 if (m_source.isNull()) {
535 m_fillColor = color;
536 m_hasFillColor = true;
537
538 } else if (m_source.depth() == 32) {
539 m_source.fill(PREMUL(color.rgba()));
540
541 } else if (m_source.depth() == 1) {
542 if (color == Qt::color1)
543 m_source.fill(1);
544 else
545 m_source.fill(0);
546 }
547 }
548}
549
550bool QGLPixmapData::hasAlphaChannel() const
551{
552 return m_hasAlpha;
553}
554
555QImage QGLPixmapData::fillImage(const QColor &color) const
556{
557 QImage img;
558 if (pixelType() == BitmapType) {
559 img = QImage(w, h, QImage::Format_MonoLSB);
560
561 img.setColorCount(2);
562 img.setColor(0, QColor(Qt::color0).rgba());
563 img.setColor(1, QColor(Qt::color1).rgba());
564
565 if (color == Qt::color1)
566 img.fill(1);
567 else
568 img.fill(0);
569 } else {
570 img = QImage(w, h,
571 m_hasAlpha
572 ? QImage::Format_ARGB32_Premultiplied
573 : QImage::Format_RGB32);
574 img.fill(PREMUL(color.rgba()));
575 }
576 return img;
577}
578
579extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
580
581QImage QGLPixmapData::toImage() const
582{
583 if (!isValid())
584 return QImage();
585
586 if (m_renderFbo) {
587 copyBackFromRenderFbo(true);
588 } else if (!m_source.isNull()) {
589 return m_source;
590 } else if (m_dirty || m_hasFillColor) {
591 return fillImage(m_fillColor);
592 } else {
593 ensureCreated();
594 }
595
596 QGLShareContextScope ctx(qt_gl_share_widget()->context());
597 glBindTexture(GL_TEXTURE_2D, m_texture.id);
598 return qt_gl_read_texture(QSize(w, h), true, true);
599}
600
601struct TextureBuffer
602{
603 QGLFramebufferObject *fbo;
604 QGL2PaintEngineEx *engine;
605};
606
607Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool)
608QGLFramebufferObjectPool* qgl_fbo_pool()
609{
610 return _qgl_fbo_pool();
611}
612
613void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
614{
615 if (!isValid())
616 return;
617
618 m_hasFillColor = false;
619
620 const QGLContext *share_ctx = qt_gl_share_widget()->context();
621 QGLShareContextScope ctx(share_ctx);
622
623 ensureCreated();
624
625 if (!ctx->d_ptr->fbo)
626 glGenFramebuffers(1, &ctx->d_ptr->fbo);
627
628 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
629 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
630 GL_TEXTURE_2D, m_texture.id, 0);
631
632 const int x0 = 0;
633 const int x1 = w;
634 const int y0 = 0;
635 const int y1 = h;
636
637 if (!m_renderFbo->isBound())
638 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
639
640 glDisable(GL_SCISSOR_TEST);
641
642 glBlitFramebufferEXT(x0, y0, x1, y1,
643 x0, y0, x1, y1,
644 GL_COLOR_BUFFER_BIT,
645 GL_NEAREST);
646
647 if (keepCurrentFboBound) {
648 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
649 } else {
650 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle());
651 ctx->d_ptr->current_fbo = m_renderFbo->handle();
652 }
653}
654
655bool QGLPixmapData::useFramebufferObjects() const
656{
657 return QGLFramebufferObject::hasOpenGLFramebufferObjects()
658 && QGLFramebufferObject::hasOpenGLFramebufferBlit()
659 && qt_gl_preferGL2Engine()
660 && (w * h > 32*32); // avoid overhead of FBOs for small pixmaps
661}
662
663QPaintEngine* QGLPixmapData::paintEngine() const
664{
665 if (!isValid())
666 return 0;
667
668 if (m_renderFbo)
669 return m_engine;
670
671 if (useFramebufferObjects()) {
672 extern QGLWidget* qt_gl_share_widget();
673
674 if (!QGLContext::currentContext())
675 qt_gl_share_widget()->makeCurrent();
676 QGLShareContextScope ctx(qt_gl_share_widget()->context());
677
678 QGLFramebufferObjectFormat format;
679 format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
680 format.setSamples(4);
681 format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB));
682
683 m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
684
685 if (m_renderFbo) {
686 if (!m_engine)
687 m_engine = new QGL2PaintEngineEx;
688 return m_engine;
689 }
690
691 qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine";
692 }
693
694 m_dirty = true;
695 if (m_source.size() != size())
696 m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied);
697 if (m_hasFillColor) {
698 m_source.fill(PREMUL(m_fillColor.rgba()));
699 m_hasFillColor = false;
700 }
701 return m_source.paintEngine();
702}
703
704extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format);
705
706// If copyBack is true, bind will copy the contents of the render
707// FBO to the texture (which is not bound to the texture, as it's
708// a multisample FBO).
709GLuint QGLPixmapData::bind(bool copyBack) const
710{
711 if (m_renderFbo && copyBack) {
712 copyBackFromRenderFbo(true);
713 } else {
714 ensureCreated();
715 }
716
717 GLuint id = m_texture.id;
718 glBindTexture(GL_TEXTURE_2D, id);
719
720 if (m_hasFillColor) {
721 if (!useFramebufferObjects()) {
722 m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
723 m_source.fill(PREMUL(m_fillColor.rgba()));
724 }
725
726 m_hasFillColor = false;
727
728 GLenum format = qt_gl_preferredTextureFormat();
729 QImage tx(w, h, QImage::Format_ARGB32_Premultiplied);
730 tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format));
731 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits());
732 }
733
734 return id;
735}
736
737QGLTexture* QGLPixmapData::texture() const
738{
739 return &m_texture;
740}
741
742Q_DECL_IMPORT extern int qt_defaultDpiX();
743Q_DECL_IMPORT extern int qt_defaultDpiY();
744
745int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
746{
747 if (w == 0)
748 return 0;
749
750 switch (metric) {
751 case QPaintDevice::PdmWidth:
752 return w;
753 case QPaintDevice::PdmHeight:
754 return h;
755 case QPaintDevice::PdmNumColors:
756 return 0;
757 case QPaintDevice::PdmDepth:
758 return d;
759 case QPaintDevice::PdmWidthMM:
760 return qRound(w * 25.4 / qt_defaultDpiX());
761 case QPaintDevice::PdmHeightMM:
762 return qRound(h * 25.4 / qt_defaultDpiY());
763 case QPaintDevice::PdmDpiX:
764 case QPaintDevice::PdmPhysicalDpiX:
765 return qt_defaultDpiX();
766 case QPaintDevice::PdmDpiY:
767 case QPaintDevice::PdmPhysicalDpiY:
768 return qt_defaultDpiY();
769 default:
770 qWarning("QGLPixmapData::metric(): Invalid metric");
771 return 0;
772 }
773}
774
775QGLPaintDevice *QGLPixmapData::glDevice() const
776{
777 return &m_glDevice;
778}
779
780QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.