source: trunk/src/opengl/qpixmapdata_gl.cpp@ 624

Last change on this file since 624 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 20.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 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
237void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d)
238{
239 data = d;
240}
241
242static int qt_gl_pixmap_serial = 0;
243
244QGLPixmapData::QGLPixmapData(PixelType type)
245 : QPixmapData(type, OpenGLClass)
246 , m_renderFbo(0)
247 , m_engine(0)
248 , m_ctx(0)
249 , m_dirty(false)
250 , m_hasFillColor(false)
251 , m_hasAlpha(false)
252{
253 setSerialNumber(++qt_gl_pixmap_serial);
254 m_glDevice.setPixmapData(this);
255}
256
257QGLPixmapData::~QGLPixmapData()
258{
259 QGLWidget *shareWidget = qt_gl_share_widget();
260 if (!shareWidget)
261 return;
262
263 delete m_engine;
264
265 if (m_texture.id) {
266 QGLShareContextScope ctx(shareWidget->context());
267 glDeleteTextures(1, &m_texture.id);
268 }
269}
270
271QPixmapData *QGLPixmapData::createCompatiblePixmapData() const
272{
273 return new QGLPixmapData(pixelType());
274}
275
276bool QGLPixmapData::isValid() const
277{
278 return w > 0 && h > 0;
279}
280
281bool QGLPixmapData::isValidContext(const QGLContext *ctx) const
282{
283 if (ctx == m_ctx)
284 return true;
285
286 const QGLContext *share_ctx = qt_gl_share_widget()->context();
287 return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx);
288}
289
290void QGLPixmapData::resize(int width, int height)
291{
292 if (width == w && height == h)
293 return;
294
295 if (width <= 0 || height <= 0) {
296 width = 0;
297 height = 0;
298 }
299
300 w = width;
301 h = height;
302 is_null = (w <= 0 || h <= 0);
303 d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
304
305 if (m_texture.id) {
306 QGLShareContextScope ctx(qt_gl_share_widget()->context());
307 glDeleteTextures(1, &m_texture.id);
308 m_texture.id = 0;
309 }
310
311 m_source = QImage();
312 m_dirty = isValid();
313 setSerialNumber(++qt_gl_pixmap_serial);
314}
315
316void QGLPixmapData::ensureCreated() const
317{
318 if (!m_dirty)
319 return;
320
321 m_dirty = false;
322
323 QGLShareContextScope ctx(qt_gl_share_widget()->context());
324 m_ctx = ctx;
325
326 const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB;
327#ifdef QT_OPENGL_ES_2
328 const GLenum external_format = internal_format;
329#else
330 const GLenum external_format = qt_gl_preferredTextureFormat();
331#endif
332 const GLenum target = GL_TEXTURE_2D;
333
334 if (!m_texture.id) {
335 glGenTextures(1, &m_texture.id);
336 glBindTexture(target, m_texture.id);
337 glTexImage2D(target, 0, internal_format, w, h, 0, external_format, GL_UNSIGNED_BYTE, 0);
338 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
339 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
340 }
341
342 if (!m_source.isNull()) {
343 if (external_format == GL_RGB) {
344 const QImage tx = m_source.convertToFormat(QImage::Format_RGB888);
345
346 glBindTexture(target, m_texture.id);
347 glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
348 GL_UNSIGNED_BYTE, tx.bits());
349 } else {
350 const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format);
351
352 glBindTexture(target, m_texture.id);
353 glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
354 GL_UNSIGNED_BYTE, tx.bits());
355 }
356
357 if (useFramebufferObjects())
358 m_source = QImage();
359 }
360
361 m_texture.options &= ~QGLContext::MemoryManagedBindOption;
362}
363
364void QGLPixmapData::fromImage(const QImage &image,
365 Qt::ImageConversionFlags /*flags*/)
366{
367 if (image.size() == QSize(w, h))
368 setSerialNumber(++qt_gl_pixmap_serial);
369 resize(image.width(), image.height());
370
371 if (pixelType() == BitmapType) {
372 m_source = image.convertToFormat(QImage::Format_MonoLSB);
373
374 } else {
375 QImage::Format format = QImage::Format_RGB32;
376 if (qApp->desktop()->depth() == 16)
377 format = QImage::Format_RGB16;
378
379 if (image.hasAlphaChannel() && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels())
380 format = QImage::Format_ARGB32_Premultiplied;;
381
382 m_source = image.convertToFormat(format);
383 }
384
385 m_dirty = true;
386 m_hasFillColor = false;
387
388 m_hasAlpha = m_source.hasAlphaChannel();
389 w = image.width();
390 h = image.height();
391 is_null = (w <= 0 || h <= 0);
392 d = m_source.depth();
393
394 if (m_texture.id) {
395 QGLShareContextScope ctx(qt_gl_share_widget()->context());
396 glDeleteTextures(1, &m_texture.id);
397 m_texture.id = 0;
398 }
399}
400
401bool QGLPixmapData::fromFile(const QString &filename, const char *format,
402 Qt::ImageConversionFlags flags)
403{
404 if (pixelType() == QPixmapData::BitmapType)
405 return QPixmapData::fromFile(filename, format, flags);
406 QFile file(filename);
407 if (!file.open(QIODevice::ReadOnly))
408 return false;
409 QByteArray data = file.peek(64);
410 bool alpha;
411 if (m_texture.canBindCompressedTexture
412 (data.constData(), data.size(), format, &alpha)) {
413 resize(0, 0);
414 data = file.readAll();
415 file.close();
416 QGLShareContextScope ctx(qt_gl_share_widget()->context());
417 QSize size = m_texture.bindCompressedTexture
418 (data.constData(), data.size(), format);
419 if (!size.isEmpty()) {
420 w = size.width();
421 h = size.height();
422 is_null = false;
423 d = 32;
424 m_hasAlpha = alpha;
425 m_source = QImage();
426 m_dirty = isValid();
427 return true;
428 }
429 return false;
430 }
431 fromImage(QImageReader(&file, format).read(), flags);
432 return !isNull();
433}
434
435bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format,
436 Qt::ImageConversionFlags flags)
437{
438 bool alpha;
439 const char *buf = reinterpret_cast<const char *>(buffer);
440 if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) {
441 resize(0, 0);
442 QGLShareContextScope ctx(qt_gl_share_widget()->context());
443 QSize size = m_texture.bindCompressedTexture(buf, int(len), format);
444 if (!size.isEmpty()) {
445 w = size.width();
446 h = size.height();
447 is_null = false;
448 d = 32;
449 m_hasAlpha = alpha;
450 m_source = QImage();
451 m_dirty = isValid();
452 return true;
453 }
454 }
455 return QPixmapData::fromData(buffer, len, format, flags);
456}
457
458bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
459{
460 Q_UNUSED(dx);
461 Q_UNUSED(dy);
462 Q_UNUSED(rect);
463 return false;
464}
465
466void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect)
467{
468 if (data->classId() != QPixmapData::OpenGLClass) {
469 QPixmapData::copy(data, rect);
470 return;
471 }
472
473 // can be optimized to do a framebuffer blit or similar ...
474 QPixmapData::copy(data, rect);
475}
476
477void QGLPixmapData::fill(const QColor &color)
478{
479 if (!isValid())
480 return;
481
482 bool hasAlpha = color.alpha() != 255;
483 if (hasAlpha && !m_hasAlpha) {
484 if (m_texture.id) {
485 glDeleteTextures(1, &m_texture.id);
486 m_texture.id = 0;
487 m_dirty = true;
488 }
489 m_hasAlpha = color.alpha() != 255;
490 }
491
492 if (useFramebufferObjects()) {
493 m_source = QImage();
494 m_hasFillColor = true;
495 m_fillColor = color;
496 } else {
497
498 if (m_source.isNull()) {
499 m_fillColor = color;
500 m_hasFillColor = true;
501
502 } else if (m_source.depth() == 32) {
503 m_source.fill(PREMUL(color.rgba()));
504
505 } else if (m_source.depth() == 1) {
506 if (color == Qt::color1)
507 m_source.fill(1);
508 else
509 m_source.fill(0);
510 }
511 }
512}
513
514bool QGLPixmapData::hasAlphaChannel() const
515{
516 return m_hasAlpha;
517}
518
519QImage QGLPixmapData::fillImage(const QColor &color) const
520{
521 QImage img;
522 if (pixelType() == BitmapType) {
523 img = QImage(w, h, QImage::Format_MonoLSB);
524
525 img.setColorCount(2);
526 img.setColor(0, QColor(Qt::color0).rgba());
527 img.setColor(1, QColor(Qt::color1).rgba());
528
529 if (color == Qt::color1)
530 img.fill(1);
531 else
532 img.fill(0);
533 } else {
534 img = QImage(w, h,
535 m_hasAlpha
536 ? QImage::Format_ARGB32_Premultiplied
537 : QImage::Format_RGB32);
538 img.fill(PREMUL(color.rgba()));
539 }
540 return img;
541}
542
543extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
544
545QImage QGLPixmapData::toImage() const
546{
547 if (!isValid())
548 return QImage();
549
550 if (m_renderFbo) {
551 copyBackFromRenderFbo(true);
552 } else if (!m_source.isNull()) {
553 return m_source;
554 } else if (m_dirty || m_hasFillColor) {
555 return fillImage(m_fillColor);
556 } else {
557 ensureCreated();
558 }
559
560 QGLShareContextScope ctx(qt_gl_share_widget()->context());
561 glBindTexture(GL_TEXTURE_2D, m_texture.id);
562 return qt_gl_read_texture(QSize(w, h), true, true);
563}
564
565struct TextureBuffer
566{
567 QGLFramebufferObject *fbo;
568 QGL2PaintEngineEx *engine;
569};
570
571Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool)
572QGLFramebufferObjectPool* qgl_fbo_pool()
573{
574 return _qgl_fbo_pool();
575}
576
577void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
578{
579 if (!isValid())
580 return;
581
582 m_hasFillColor = false;
583
584 const QGLContext *share_ctx = qt_gl_share_widget()->context();
585 QGLShareContextScope ctx(share_ctx);
586
587 ensureCreated();
588
589 if (!ctx->d_ptr->fbo)
590 glGenFramebuffers(1, &ctx->d_ptr->fbo);
591
592 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
593 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
594 GL_TEXTURE_2D, m_texture.id, 0);
595
596 const int x0 = 0;
597 const int x1 = w;
598 const int y0 = 0;
599 const int y1 = h;
600
601 if (!m_renderFbo->isBound())
602 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
603
604 glDisable(GL_SCISSOR_TEST);
605
606 glBlitFramebufferEXT(x0, y0, x1, y1,
607 x0, y0, x1, y1,
608 GL_COLOR_BUFFER_BIT,
609 GL_NEAREST);
610
611 if (keepCurrentFboBound) {
612 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
613 } else {
614 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle());
615 ctx->d_ptr->current_fbo = m_renderFbo->handle();
616 }
617}
618
619bool QGLPixmapData::useFramebufferObjects()
620{
621 return QGLFramebufferObject::hasOpenGLFramebufferObjects()
622 && QGLFramebufferObject::hasOpenGLFramebufferBlit()
623 && qt_gl_preferGL2Engine();
624}
625
626QPaintEngine* QGLPixmapData::paintEngine() const
627{
628 if (!isValid())
629 return 0;
630
631 if (m_renderFbo)
632 return m_engine;
633
634 if (useFramebufferObjects()) {
635 extern QGLWidget* qt_gl_share_widget();
636
637 if (!QGLContext::currentContext())
638 qt_gl_share_widget()->makeCurrent();
639 QGLShareContextScope ctx(qt_gl_share_widget()->context());
640
641 QGLFramebufferObjectFormat format;
642 format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
643 format.setSamples(4);
644 format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB));
645
646 m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
647
648 if (m_renderFbo) {
649 if (!m_engine)
650 m_engine = new QGL2PaintEngineEx;
651 return m_engine;
652 }
653
654 qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine";
655 }
656
657 m_dirty = true;
658 if (m_source.size() != size())
659 m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied);
660 if (m_hasFillColor) {
661 m_source.fill(PREMUL(m_fillColor.rgba()));
662 m_hasFillColor = false;
663 }
664 return m_source.paintEngine();
665}
666
667extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format);
668
669// If copyBack is true, bind will copy the contents of the render
670// FBO to the texture (which is not bound to the texture, as it's
671// a multisample FBO).
672GLuint QGLPixmapData::bind(bool copyBack) const
673{
674 if (m_renderFbo && copyBack) {
675 copyBackFromRenderFbo(true);
676 } else {
677 ensureCreated();
678 }
679
680 GLuint id = m_texture.id;
681 glBindTexture(GL_TEXTURE_2D, id);
682
683 if (m_hasFillColor) {
684 if (!useFramebufferObjects()) {
685 m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
686 m_source.fill(PREMUL(m_fillColor.rgba()));
687 }
688
689 m_hasFillColor = false;
690
691 GLenum format = qt_gl_preferredTextureFormat();
692 QImage tx(w, h, QImage::Format_ARGB32_Premultiplied);
693 tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format));
694 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits());
695 }
696
697 return id;
698}
699
700QGLTexture* QGLPixmapData::texture() const
701{
702 return &m_texture;
703}
704
705extern int qt_defaultDpiX();
706extern int qt_defaultDpiY();
707
708int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
709{
710 if (w == 0)
711 return 0;
712
713 switch (metric) {
714 case QPaintDevice::PdmWidth:
715 return w;
716 case QPaintDevice::PdmHeight:
717 return h;
718 case QPaintDevice::PdmNumColors:
719 return 0;
720 case QPaintDevice::PdmDepth:
721 return d;
722 case QPaintDevice::PdmWidthMM:
723 return qRound(w * 25.4 / qt_defaultDpiX());
724 case QPaintDevice::PdmHeightMM:
725 return qRound(h * 25.4 / qt_defaultDpiY());
726 case QPaintDevice::PdmDpiX:
727 case QPaintDevice::PdmPhysicalDpiX:
728 return qt_defaultDpiX();
729 case QPaintDevice::PdmDpiY:
730 case QPaintDevice::PdmPhysicalDpiY:
731 return qt_defaultDpiY();
732 default:
733 qWarning("QGLPixmapData::metric(): Invalid metric");
734 return 0;
735 }
736}
737
738QGLPaintDevice *QGLPixmapData::glDevice() const
739{
740 return &m_glDevice;
741}
742
743QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.