Changeset 561 for trunk/src/opengl/qpixmapdata_gl.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/opengl/qpixmapdata_gl.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 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 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 41 41 42 42 #include "qpixmap.h" 43 #include "qglframebufferobject.h" 43 44 44 45 #include <private/qpaintengine_raster_p.h> … … 48 49 #include <private/qgl_p.h> 49 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> 50 58 51 59 QT_BEGIN_NAMESPACE … … 53 61 extern QGLWidget* qt_gl_share_widget(); 54 62 55 class QGLShareContextScope 56 { 57 public: 58 QGLShareContextScope(const QGLContext *ctx) 59 : m_oldContext(0) 60 , m_ctx(const_cast<QGLContext *>(ctx)) 61 { 62 const QGLContext *currentContext = QGLContext::currentContext(); 63 if (currentContext != ctx && !qgl_share_reg()->checkSharing(ctx, currentContext)) { 64 m_oldContext = const_cast<QGLContext *>(currentContext); 65 m_ctx->makeCurrent(); 66 } 67 } 68 69 operator QGLContext *() 70 { 71 return m_ctx; 72 } 73 74 QGLContext *operator->() 75 { 76 return m_ctx; 77 } 78 79 ~QGLShareContextScope() 80 { 81 if (m_oldContext) 82 m_oldContext->makeCurrent(); 83 } 84 85 private: 86 QGLContext *m_oldContext; 87 QGLContext *m_ctx; 88 }; 89 90 void qt_gl_convertFromGLImage(QImage *img) 91 { 92 const int w = img->width(); 93 const int h = img->height(); 94 95 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 96 uint *p = (uint*)img->bits(); 97 uint *end = p + w*h; 98 99 while (p < end) { 100 uint a = *p << 24; 101 *p = (*p >> 8) | a; 102 p++; 103 } 104 105 *img = img->mirrored(); 106 } else { 107 // mirror image 108 uint *data = (uint *)img->bits(); 109 110 const int mid = h/2; 111 112 for (int y = 0; y < mid; ++y) { 113 uint *p = data + y * w; 114 uint *end = p + w; 115 uint *q = data + (h - y - 1) * w; 116 117 while (p < end) 118 qSwap(*p++, *q++); 119 } 120 } 121 } 122 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 76 static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo) 77 { 78 return qAbs(size.width() * size.height() - fbo->width() * fbo->height()); 79 } 80 81 extern int qt_next_power_of_two(int v); 82 83 static 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 94 QGLFramebufferObject *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 155 void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) 156 { 157 if (fbo) 158 m_fbos << fbo; 159 } 160 161 162 QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const 163 { 164 return data->paintEngine(); 165 } 166 167 void 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 212 void 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 226 QGLContext* QGLPixmapGLPaintDevice::context() const 227 { 228 data->ensureCreated(); 229 return data->m_ctx; 230 } 231 232 QSize QGLPixmapGLPaintDevice::size() const 233 { 234 return data->size(); 235 } 236 237 void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) 238 { 239 data = d; 240 } 123 241 124 242 static int qt_gl_pixmap_serial = 0; … … 126 244 QGLPixmapData::QGLPixmapData(PixelType type) 127 245 : QPixmapData(type, OpenGLClass) 128 , m_ width(0)129 , m_ height(0)130 , m_ texture(0)246 , m_renderFbo(0) 247 , m_engine(0) 248 , m_ctx(0) 131 249 , m_dirty(false) 250 , m_hasFillColor(false) 251 , m_hasAlpha(false) 132 252 { 133 253 setSerialNumber(++qt_gl_pixmap_serial); 254 m_glDevice.setPixmapData(this); 134 255 } 135 256 136 257 QGLPixmapData::~QGLPixmapData() 137 258 { 138 if (m_texture && qt_gl_share_widget()) { 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 271 QPixmapData *QGLPixmapData::createCompatiblePixmapData() const 272 { 273 return new QGLPixmapData(pixelType()); 274 } 275 276 bool QGLPixmapData::isValid() const 277 { 278 return w > 0 && h > 0; 279 } 280 281 bool 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 290 void 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) { 139 306 QGLShareContextScope ctx(qt_gl_share_widget()->context()); 140 glDeleteTextures(1, &m_texture); 141 } 142 } 143 144 bool QGLPixmapData::isValid() const 145 { 146 return m_width > 0 && m_height > 0; 147 } 148 149 bool QGLPixmapData::isValidContext(const QGLContext *ctx) const 150 { 151 const QGLContext *share_ctx = qt_gl_share_widget()->context(); 152 return ctx == share_ctx || qgl_share_reg()->checkSharing(ctx, share_ctx); 153 } 154 155 void QGLPixmapData::resize(int width, int height) 156 { 157 if (width == m_width && height == m_height) 158 return; 159 160 m_width = width; 161 m_height = height; 307 glDeleteTextures(1, &m_texture.id); 308 m_texture.id = 0; 309 } 162 310 163 311 m_source = QImage(); … … 174 322 175 323 QGLShareContextScope ctx(qt_gl_share_widget()->context()); 176 177 const GLenum format = qt_gl_preferredTextureFormat(); 178 const GLenum target = qt_gl_preferredTextureTarget(); 179 180 if (!m_texture) 181 glGenTextures(1, &m_texture); 182 183 glBindTexture(target, m_texture); 184 185 if (m_source.isNull()) { 186 glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, GL_UNSIGNED_BYTE, 0); 187 } else { 188 const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format); 189 190 glBindTexture(target, m_texture); 191 glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, 192 GL_UNSIGNED_BYTE, tx.bits()); 193 194 m_source = QImage(); 195 } 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; 196 362 } 197 363 198 364 void QGLPixmapData::fromImage(const QImage &image, 199 Qt::ImageConversionFlags )200 { 201 if (image.size() == QSize( m_width, m_height))365 Qt::ImageConversionFlags /*flags*/) 366 { 367 if (image.size() == QSize(w, h)) 202 368 setSerialNumber(++qt_gl_pixmap_serial); 203 369 resize(image.width(), image.height()); 204 m_source = image; 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 205 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 401 bool 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 435 bool 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 458 bool 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 466 void 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); 206 475 } 207 476 … … 211 480 return; 212 481 213 if (!m_source.isNull()) { 214 m_source.fill(PREMUL(color.rgba())); 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; 215 496 } else { 216 // ## TODO: improve performance here 217 QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied); 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 514 bool QGLPixmapData::hasAlphaChannel() const 515 { 516 return m_hasAlpha; 517 } 518 519 QImage 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); 218 538 img.fill(PREMUL(color.rgba())); 219 220 fromImage(img, 0); 221 } 222 } 223 224 bool QGLPixmapData::hasAlphaChannel() const 225 { 226 return true; 227 } 539 } 540 return img; 541 } 542 543 extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha); 228 544 229 545 QImage QGLPixmapData::toImage() const … … 232 548 return QImage(); 233 549 234 if (!m_source.isNull()) 550 if (m_renderFbo) { 551 copyBackFromRenderFbo(true); 552 } else if (!m_source.isNull()) { 235 553 return m_source; 236 else if (m_dirty) 237 return QImage(m_width, m_height, QImage::Format_ARGB32_Premultiplied); 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 565 struct TextureBuffer 566 { 567 QGLFramebufferObject *fbo; 568 QGL2PaintEngineEx *engine; 569 }; 570 571 Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool) 572 QGLFramebufferObjectPool* qgl_fbo_pool() 573 { 574 return _qgl_fbo_pool(); 575 } 576 577 void 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); 238 586 239 587 ensureCreated(); 240 588 241 QGLShareContextScope ctx(qt_gl_share_widget()->context()); 242 QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied); 243 244 GLenum format = qt_gl_preferredTextureFormat(); 245 GLenum target = qt_gl_preferredTextureTarget(); 246 247 glBindTexture(target, m_texture); 248 #ifndef QT_OPENGL_ES 249 glGetTexImage(target, 0, format, GL_UNSIGNED_BYTE, img.bits()); 250 #else 251 // XXX - cannot download textures this way on OpenGL/ES. 252 #endif 253 254 qt_gl_convertFromGLImage(&img); 255 256 return img; 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 619 bool QGLPixmapData::useFramebufferObjects() 620 { 621 return QGLFramebufferObject::hasOpenGLFramebufferObjects() 622 && QGLFramebufferObject::hasOpenGLFramebufferBlit() 623 && qt_gl_preferGL2Engine(); 257 624 } 258 625 … … 262 629 return 0; 263 630 264 m_source = toImage(); 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 265 657 m_dirty = true; 266 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 } 267 664 return m_source.paintEngine(); 268 665 } 269 666 270 GLuint QGLPixmapData::bind() const 271 { 272 ensureCreated(); 273 glBindTexture(qt_gl_preferredTextureTarget(), m_texture); 274 return m_texture; 275 } 276 277 GLuint QGLPixmapData::textureId() const 278 { 279 ensureCreated(); 280 return m_texture; 667 extern 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). 672 GLuint 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 700 QGLTexture* QGLPixmapData::texture() const 701 { 702 return &m_texture; 281 703 } 282 704 … … 286 708 int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const 287 709 { 710 if (w == 0) 711 return 0; 712 288 713 switch (metric) { 289 714 case QPaintDevice::PdmWidth: 290 return m_width;715 return w; 291 716 case QPaintDevice::PdmHeight: 292 return m_height;717 return h; 293 718 case QPaintDevice::PdmNumColors: 294 719 return 0; 295 720 case QPaintDevice::PdmDepth: 296 return pixelType() == QPixmapData::PixmapType ? 32 : 1;721 return d; 297 722 case QPaintDevice::PdmWidthMM: 298 return qRound( m_width* 25.4 / qt_defaultDpiX());723 return qRound(w * 25.4 / qt_defaultDpiX()); 299 724 case QPaintDevice::PdmHeightMM: 300 return qRound( m_height* 25.4 / qt_defaultDpiY());725 return qRound(h * 25.4 / qt_defaultDpiY()); 301 726 case QPaintDevice::PdmDpiX: 302 727 case QPaintDevice::PdmPhysicalDpiX: … … 311 736 } 312 737 738 QGLPaintDevice *QGLPixmapData::glDevice() const 739 { 740 return &m_glDevice; 741 } 742 313 743 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.