Changeset 561 for trunk/src/opengl/qglframebufferobject.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/qglframebufferobject.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 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 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 41 41 42 42 #include "qglframebufferobject.h" 43 43 44 44 45 #include <qdebug.h> 45 46 #include <private/qgl_p.h> 47 48 49 50 51 46 52 #include <private/qpaintengine_opengl_p.h> 53 54 47 55 #include <qglframebufferobject.h> 48 56 #include <qlibrary.h> 49 57 #include <qimage.h> 50 58 59 60 61 62 51 63 QT_BEGIN_NAMESPACE 52 64 53 65 extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); 54 66 55 #define QGL_FUNC_CONTEXT QGLContext *ctx = d_ptr->ctx; 56 67 #define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context(); 68 #define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context(); 69 70 #ifndef QT_NO_DEBUG 71 #define QT_RESET_GLERROR() \ 72 { \ 73 while (glGetError() != GL_NO_ERROR) {} \ 74 } 57 75 #define QT_CHECK_GLERROR() \ 58 76 { \ … … 63 81 } \ 64 82 } 65 66 class QGLFramebufferObjectPrivate 67 { 68 public: 69 QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), bound(false), ctx(0) {} 70 ~QGLFramebufferObjectPrivate() {} 71 72 void init(const QSize& sz, QGLFramebufferObject::Attachment attachment, 73 GLenum internal_format, GLenum texture_target); 74 bool checkFramebufferStatus() const; 75 GLuint texture; 76 GLuint fbo; 77 GLuint depth_stencil_buffer; 78 GLenum target; 79 QSize size; 80 uint valid : 1; 81 uint bound : 1; 82 QGLFramebufferObject::Attachment fbo_attachment; 83 QGLContext *ctx; // for Windows extension ptrs 84 }; 83 #else 84 #define QT_RESET_GLERROR() {} 85 #define QT_CHECK_GLERROR() {} 86 #endif 87 88 /*! 89 \class QGLFramebufferObjectFormat 90 \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL 91 framebuffer object. 92 93 \since 4.6 94 95 \ingroup painting-3D 96 97 A framebuffer object has several characteristics: 98 \list 99 \i \link setSamples() Number of samples per pixels.\endlink 100 \i \link setAttachment() Depth and/or stencil attachments.\endlink 101 \i \link setTextureTarget() Texture target.\endlink 102 \i \link setInternalTextureFormat() Internal texture format.\endlink 103 \endlist 104 105 Note that the desired attachments or number of samples per pixels might not 106 be supported by the hardware driver. Call QGLFramebufferObject::format() 107 after creating a QGLFramebufferObject to find the exact format that was 108 used to create the frame buffer object. 109 110 \sa QGLFramebufferObject 111 */ 112 113 /*! 114 \internal 115 */ 116 void QGLFramebufferObjectFormat::detach() 117 { 118 if (d->ref != 1) { 119 QGLFramebufferObjectFormatPrivate *newd 120 = new QGLFramebufferObjectFormatPrivate(d); 121 if (!d->ref.deref()) 122 delete d; 123 d = newd; 124 } 125 } 126 127 /*! 128 Creates a QGLFramebufferObjectFormat object for specifying 129 the format of an OpenGL framebuffer object. 130 131 By default the format specifies a non-multisample framebuffer object with no 132 attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8. 133 On OpenGL/ES systems, the default internal format is \c GL_RGBA. 134 135 \sa samples(), attachment(), target(), internalTextureFormat() 136 */ 137 138 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat() 139 { 140 d = new QGLFramebufferObjectFormatPrivate; 141 } 142 143 /*! 144 Constructs a copy of \a other. 145 */ 146 147 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other) 148 { 149 d = other.d; 150 d->ref.ref(); 151 } 152 153 /*! 154 Assigns \a other to this object. 155 */ 156 157 QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other) 158 { 159 if (d != other.d) { 160 other.d->ref.ref(); 161 if (!d->ref.deref()) 162 delete d; 163 d = other.d; 164 } 165 return *this; 166 } 167 168 /*! 169 Destroys the QGLFramebufferObjectFormat. 170 */ 171 QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat() 172 { 173 if (!d->ref.deref()) 174 delete d; 175 } 176 177 /*! 178 Sets the number of samples per pixel for a multisample framebuffer object 179 to \a samples. The default sample count of 0 represents a regular 180 non-multisample framebuffer object. 181 182 If the desired amount of samples per pixel is not supported by the hardware 183 then the maximum number of samples per pixel will be used. Note that 184 multisample framebuffer objects can not be bound as textures. Also, the 185 \c{GL_EXT_framebuffer_multisample} extension is required to create a 186 framebuffer with more than one sample per pixel. 187 188 \sa samples() 189 */ 190 void QGLFramebufferObjectFormat::setSamples(int samples) 191 { 192 detach(); 193 d->samples = samples; 194 } 195 196 /*! 197 Returns the number of samples per pixel if a framebuffer object 198 is a multisample framebuffer object. Otherwise, returns 0. 199 The default value is 0. 200 201 \sa setSamples() 202 */ 203 int QGLFramebufferObjectFormat::samples() const 204 { 205 return d->samples; 206 } 207 208 /*! 209 Sets the attachment configuration of a framebuffer object to \a attachment. 210 211 \sa attachment() 212 */ 213 void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment) 214 { 215 detach(); 216 d->attachment = attachment; 217 } 218 219 /*! 220 Returns the configuration of the depth and stencil buffers attached to 221 a framebuffer object. The default is QGLFramebufferObject::NoAttachment. 222 223 \sa setAttachment() 224 */ 225 QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const 226 { 227 return d->attachment; 228 } 229 230 /*! 231 Sets the texture target of the texture attached to a framebuffer object to 232 \a target. Ignored for multisample framebuffer objects. 233 234 \sa textureTarget(), samples() 235 */ 236 void QGLFramebufferObjectFormat::setTextureTarget(GLenum target) 237 { 238 detach(); 239 d->target = target; 240 } 241 242 /*! 243 Returns the texture target of the texture attached to a framebuffer object. 244 Ignored for multisample framebuffer objects. The default is 245 \c GL_TEXTURE_2D. 246 247 \sa setTextureTarget(), samples() 248 */ 249 GLenum QGLFramebufferObjectFormat::textureTarget() const 250 { 251 return d->target; 252 } 253 254 /*! 255 Sets the internal format of a framebuffer object's texture or 256 multisample framebuffer object's color buffer to 257 \a internalTextureFormat. 258 259 \sa internalTextureFormat() 260 */ 261 void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat) 262 { 263 detach(); 264 d->internal_format = internalTextureFormat; 265 } 266 267 /*! 268 Returns the internal format of a framebuffer object's texture or 269 multisample framebuffer object's color buffer. The default is 270 \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on 271 OpenGL/ES systems. 272 273 \sa setInternalTextureFormat() 274 */ 275 GLenum QGLFramebufferObjectFormat::internalTextureFormat() const 276 { 277 return d->internal_format; 278 } 279 280 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS 281 /*! \internal */ 282 void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target) 283 { 284 detach(); 285 d->target = target; 286 } 287 288 /*! \internal */ 289 void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum internalTextureFormat) 290 { 291 detach(); 292 d->internal_format = internalTextureFormat; 293 } 294 #endif 295 296 /*! 297 Returns true if all the options of this framebuffer object format 298 are the same as \a other; otherwise returns false. 299 */ 300 bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const 301 { 302 if (d == other.d) 303 return true; 304 else 305 return d->equals(other.d); 306 } 307 308 /*! 309 Returns false if all the options of this framebuffer object format 310 are the same as \a other; otherwise returns true. 311 */ 312 bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const 313 { 314 return !(*this == other); 315 } 316 317 void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f, 318 QGLFramebufferObject::Attachment attachment) 319 { 320 fbo = f; 321 m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed 322 323 // The context that the fbo was created in may not have depth 324 // and stencil buffers, but the fbo itself might. 325 fboFormat = QGLContext::currentContext()->format(); 326 if (attachment == QGLFramebufferObject::CombinedDepthStencil) { 327 fboFormat.setDepth(true); 328 fboFormat.setStencil(true); 329 } else if (attachment == QGLFramebufferObject::Depth) { 330 fboFormat.setDepth(true); 331 } 332 } 333 334 QGLContext *QGLFBOGLPaintDevice::context() const 335 { 336 QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context()); 337 QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); 338 339 if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext)) 340 return currentContext; 341 else 342 return fboContext; 343 } 85 344 86 345 bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const 87 346 { 88 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 347 QGL_FUNCP_CONTEXT; 348 if (!ctx) 349 return false; // Context no longer exists. 350 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); 89 351 switch(status) { 90 352 case GL_NO_ERROR: … … 118 380 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer."); 119 381 break; 382 383 384 120 385 default: 121 386 qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status; … … 125 390 } 126 391 127 void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment, 128 GLenum texture_target, GLenum internal_format) 129 { 130 ctx = const_cast<QGLContext *>(QGLContext::currentContext()); 392 void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, 393 QGLFramebufferObject::Attachment attachment, 394 GLenum texture_target, GLenum internal_format, GLint samples) 395 { 396 QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); 397 fbo_guard.setContext(ctx); 398 131 399 bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); 132 400 if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx))) … … 137 405 // texture dimensions 138 406 139 while (glGetError() != GL_NO_ERROR) {} // reset error state 140 glGenFramebuffersEXT(1, &fbo); 141 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); 407 QT_RESET_GLERROR(); // reset error state 408 GLuint fbo = 0; 409 glGenFramebuffers(1, &fbo); 410 glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo); 411 fbo_guard.setId(fbo); 412 413 glDevice.setFBO(q, attachment); 142 414 143 415 QT_CHECK_GLERROR(); 144 416 // init texture 145 glGenTextures(1, &texture); 146 glBindTexture(target, texture); 147 glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, 148 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 417 if (samples == 0) { 418 glGenTextures(1, &texture); 419 glBindTexture(target, texture); 420 glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, 421 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 149 422 #ifndef QT_OPENGL_ES 150 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);151 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);152 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);153 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);423 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 424 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 425 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 426 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 154 427 #else 155 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 156 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 157 glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 158 glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 159 #endif 160 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 161 target, texture, 0); 162 163 QT_CHECK_GLERROR(); 164 valid = checkFramebufferStatus(); 428 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 429 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 430 glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 431 glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 432 #endif 433 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 434 target, texture, 0); 435 436 QT_CHECK_GLERROR(); 437 valid = checkFramebufferStatus(); 438 glBindTexture(target, 0); 439 440 color_buffer = 0; 441 } else { 442 GLint maxSamples; 443 glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples); 444 445 samples = qBound(1, int(samples), int(maxSamples)); 446 447 glGenRenderbuffers(1, &color_buffer); 448 glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer); 449 if (glRenderbufferStorageMultisampleEXT) { 450 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, 451 internal_format, size.width(), size.height()); 452 } else { 453 samples = 0; 454 glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format, 455 size.width(), size.height()); 456 } 457 458 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 459 GL_RENDERBUFFER_EXT, color_buffer); 460 461 QT_CHECK_GLERROR(); 462 valid = checkFramebufferStatus(); 463 464 if (valid) 465 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples); 466 } 165 467 166 468 if (attachment == QGLFramebufferObject::CombinedDepthStencil 167 469 && (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) { 168 470 // depth and stencil buffer needs another extension 169 glGenRenderbuffersEXT(1, &depth_stencil_buffer); 170 Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer)); 171 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer); 172 Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer)); 173 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); 471 glGenRenderbuffers(1, &depth_stencil_buffer); 472 Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer)); 473 glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer); 474 Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer)); 475 if (samples != 0 && glRenderbufferStorageMultisampleEXT) 476 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, 477 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); 478 else 479 glRenderbufferStorage(GL_RENDERBUFFER_EXT, 480 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); 481 174 482 GLint i = 0; 175 glGetRenderbufferParameteriv EXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);176 glFramebufferRenderbuffer EXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,483 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); 484 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 177 485 GL_RENDERBUFFER_EXT, depth_stencil_buffer); 178 glFramebufferRenderbuffer EXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,486 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, 179 487 GL_RENDERBUFFER_EXT, depth_stencil_buffer); 180 488 fbo_attachment = QGLFramebufferObject::CombinedDepthStencil; 489 181 490 valid = checkFramebufferStatus(); 182 491 if (!valid) 183 glDeleteRenderbuffers EXT(1, &depth_stencil_buffer);492 glDeleteRenderbuffers(1, &depth_stencil_buffer); 184 493 } else if (attachment == QGLFramebufferObject::Depth 185 494 || attachment == QGLFramebufferObject::CombinedDepthStencil) 186 495 { 187 glGenRenderbuffersEXT(1, &depth_stencil_buffer); 188 Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer)); 189 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer); 190 Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer)); 496 glGenRenderbuffers(1, &depth_stencil_buffer); 497 Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer)); 498 glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer); 499 Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer)); 500 if (samples != 0 && glRenderbufferStorageMultisampleEXT) { 191 501 #ifdef QT_OPENGL_ES 192 502 #define GL_DEPTH_COMPONENT16 0x81A5 193 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height()); 503 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, 504 GL_DEPTH_COMPONENT16, size.width(), size.height()); 194 505 #else 195 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height()); 196 #endif 506 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, 507 GL_DEPTH_COMPONENT, size.width(), size.height()); 508 #endif 509 } else { 510 #ifdef QT_OPENGL_ES 511 #define GL_DEPTH_COMPONENT16 0x81A5 512 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height()); 513 #else 514 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height()); 515 #endif 516 } 197 517 GLint i = 0; 198 glGetRenderbufferParameteriv EXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);199 glFramebufferRenderbuffer EXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,518 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); 519 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 200 520 GL_RENDERBUFFER_EXT, depth_stencil_buffer); 201 521 fbo_attachment = QGLFramebufferObject::Depth; 202 522 valid = checkFramebufferStatus(); 203 523 if (!valid) 204 glDeleteRenderbuffers EXT(1, &depth_stencil_buffer);524 glDeleteRenderbuffers(1, &depth_stencil_buffer); 205 525 } else { 206 526 fbo_attachment = QGLFramebufferObject::NoAttachment; 207 527 } 208 528 209 glBindFramebuffer EXT(GL_FRAMEBUFFER_EXT, 0);529 glBindFramebuffer); 210 530 if (!valid) { 211 glDeleteTextures(1, &texture); 212 glDeleteFramebuffersEXT(1, &fbo); 531 if (color_buffer) 532 glDeleteRenderbuffers(1, &color_buffer); 533 else 534 glDeleteTextures(1, &texture); 535 glDeleteFramebuffers(1, &fbo); 536 fbo_guard.setId(0); 213 537 } 214 538 QT_CHECK_GLERROR(); 539 540 541 542 543 215 544 } 216 545 … … 220 549 \since 4.2 221 550 222 \ingroup multimedia551 \ingroup 223 552 224 553 The QGLFramebufferObject class encapsulates an OpenGL framebuffer … … 260 589 \endlist 261 590 262 Note that primitives drawn to a QGLFramebufferObject with QPainter 263 will only be antialiased if the QPainter::HighQualityAntialiasing 264 render hint is set. This is because there is currently no support 265 for the \c{GL_EXT_framebuffer_multisample} extension, which is 266 required to do multisample based antialiasing. Also note that the 267 QPainter::HighQualityAntialiasing render hint requires the 268 \c{GL_ARB_fragment_program} extension to work in OpenGL. 591 When using a QPainter to paint to a QGLFramebufferObject you should take 592 care that the QGLFramebufferObject is created with the CombinedDepthStencil 593 attachment for QPainter to be able to render correctly. 594 Note that you need to create a QGLFramebufferObject with more than one 595 sample per pixel for primitives to be antialiased when drawing using a 596 QPainter. To create a multisample framebuffer object you should use one of 597 the constructors that take a QGLFramebufferObject parameter, and set the 598 QGLFramebufferObject::samples() property to a non-zero value. 599 600 When painting to a QGLFramebufferObject using QPainter, the state of 601 the current GL context will be altered by the paint engine to reflect 602 its needs. Applications should not rely upon the GL state being reset 603 to its original conditions, particularly the current shader program, 604 GL viewport, texture units, and drawing modes. 605 606 For multisample framebuffer objects a color render buffer is created, 607 otherwise a texture with the specified texture target is created. 608 The color render buffer or texture will have the specified internal 609 format, and will be bound to the \c GL_COLOR_ATTACHMENT0 610 attachment in the framebuffer object. 611 612 If you want to use a framebuffer object with multisampling enabled 613 as a texture, you first need to copy from it to a regular framebuffer 614 object using QGLContext::blitFramebuffer(). 269 615 270 616 \sa {Framebuffer Object Example} … … 308 654 can be toggled using one of the overloaded constructors. 309 655 310 The default internal texture format is \c GL_RGBA8. 656 The default internal texture format is \c GL_RGBA8 for desktop 657 OpenGL, and \c GL_RGBA for OpenGL/ES. 311 658 312 659 It is important that you have a current GL context set when … … 317 664 */ 318 665 319 #ifndef QT_OPENGL_ES320 #define DEFAULT_FORMAT GL_RGBA8321 #else322 #define DEFAULT_FORMAT GL_RGBA323 #endif324 325 666 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target) 326 667 : d_ptr(new QGLFramebufferObjectPrivate) 327 668 { 328 669 Q_D(QGLFramebufferObject); 329 d->init( size, NoAttachment, target, DEFAULT_FORMAT);670 d->init(size, NoAttachment, target, DEFAULT_FORMAT); 330 671 } 331 672 … … 336 677 { 337 678 Q_D(QGLFramebufferObject); 338 d->init( size, NoAttachment, target, DEFAULT_FORMAT);679 d->init(size, NoAttachment, target, DEFAULT_FORMAT); 339 680 } 340 681 #endif … … 351 692 { 352 693 Q_D(QGLFramebufferObject); 353 d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); 694 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); 695 } 696 697 /*! \overload 698 699 Constructs an OpenGL framebuffer object of the given \a size based on the 700 supplied \a format. 701 */ 702 703 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format) 704 : d_ptr(new QGLFramebufferObjectPrivate) 705 { 706 Q_D(QGLFramebufferObject); 707 d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(), 708 format.samples()); 709 } 710 711 /*! \overload 712 713 Constructs an OpenGL framebuffer object of the given \a width and \a height 714 based on the supplied \a format. 715 */ 716 717 QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format) 718 : d_ptr(new QGLFramebufferObjectPrivate) 719 { 720 Q_D(QGLFramebufferObject); 721 d->init(this, QSize(width, height), format.attachment(), format.textureTarget(), 722 format.internalTextureFormat(), format.samples()); 354 723 } 355 724 … … 360 729 { 361 730 Q_D(QGLFramebufferObject); 362 d->init( QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);731 d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); 363 732 } 364 733 #endif … … 372 741 configuration, \a target the texture target and \a internal_format 373 742 the internal texture format. The default texture target is \c 374 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8. 743 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 744 for desktop OpenGL and \c GL_RGBA for OpenGL/ES. 375 745 376 746 \sa size(), texture(), attachment() … … 381 751 { 382 752 Q_D(QGLFramebufferObject); 383 d->init( QSize(width, height), attachment, target, internal_format);753 d->init(QSize(width, height), attachment, target, internal_format); 384 754 } 385 755 … … 391 761 { 392 762 Q_D(QGLFramebufferObject); 393 d->init( QSize(width, height), attachment, target, internal_format);763 d->init(QSize(width, height), attachment, target, internal_format); 394 764 } 395 765 #endif … … 403 773 configuration, \a target the texture target and \a internal_format 404 774 the internal texture format. The default texture target is \c 405 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8. 775 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 776 for desktop OpenGL and \c GL_RGBA for OpenGL/ES. 406 777 407 778 \sa size(), texture(), attachment() … … 412 783 { 413 784 Q_D(QGLFramebufferObject); 414 d->init( size, attachment, target, internal_format);785 d->init(size, attachment, target, internal_format); 415 786 } 416 787 … … 422 793 { 423 794 Q_D(QGLFramebufferObject); 424 d->init( size, attachment, target, internal_format);795 d->init(size, attachment, target, internal_format); 425 796 } 426 797 #endif … … 436 807 QGL_FUNC_CONTEXT; 437 808 438 if (isValid() 439 && (d->ctx == QGLContext::currentContext() 440 || qgl_share_reg()->checkSharing(d->ctx, QGLContext::currentContext()))) 441 { 442 glDeleteTextures(1, &d->texture); 809 delete d->engine; 810 811 if (isValid() && ctx) { 812 QGLShareContextScope scope(ctx); 813 if (d->texture) 814 glDeleteTextures(1, &d->texture); 815 if (d->color_buffer) 816 glDeleteRenderbuffers(1, &d->color_buffer); 443 817 if (d->depth_stencil_buffer) 444 glDeleteRenderbuffers EXT(1, &d->depth_stencil_buffer);445 glDeleteFramebuffersEXT(1, &d->fbo);446 }447 delete d_ptr;818 glDeleteRenderbuffers(1, &d->depth_stencil_buffer); 819 ); 820 821 448 822 } 449 823 … … 455 829 The framebuffer can become invalid if the initialization process 456 830 fails, the user attaches an invalid buffer to the framebuffer 457 object, or a non-power of 2width/height is specified as the831 object, or a non-power of width/height is specified as the 458 832 texture size if the texture target is \c{GL_TEXTURE_2D}. 833 834 835 836 837 838 839 840 459 841 */ 460 842 bool QGLFramebufferObject::isValid() const 461 843 { 462 844 Q_D(const QGLFramebufferObject); 463 return d->valid ;845 return d->valid; 464 846 } 465 847 … … 470 852 framebuffer to this framebuffer object. 471 853 Returns true upon success, false otherwise. 854 855 472 856 */ 473 857 bool QGLFramebufferObject::bind() … … 477 861 Q_D(QGLFramebufferObject); 478 862 QGL_FUNC_CONTEXT; 479 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->fbo); 480 d->bound = d->valid = d->checkFramebufferStatus(); 863 if (!ctx) 864 return false; // Context no longer exists. 865 const QGLContext *current = QGLContext::currentContext(); 866 #ifdef QT_DEBUG 867 if (!current || 868 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx)) 869 { 870 qWarning("QGLFramebufferObject::bind() called from incompatible context"); 871 } 872 #endif 873 glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo()); 874 d->valid = d->checkFramebufferStatus(); 875 if (d->valid && current) 876 current->d_ptr->current_fbo = d->fbo(); 481 877 return d->valid; 482 878 } … … 488 884 framebuffer. 489 885 Returns true upon success, false otherwise. 886 887 490 888 */ 491 889 bool QGLFramebufferObject::release() … … 493 891 if (!isValid()) 494 892 return false; 495 Q_D(QGLFramebufferObject);496 893 QGL_FUNC_CONTEXT; 497 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 498 d->valid = d->checkFramebufferStatus(); 499 d->bound = false; 500 return d->valid; 894 if (!ctx) 895 return false; // Context no longer exists. 896 897 const QGLContext *current = QGLContext::currentContext(); 898 899 #ifdef QT_DEBUG 900 if (!current || 901 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx)) 902 { 903 qWarning("QGLFramebufferObject::release() called from incompatible context"); 904 } 905 #endif 906 907 if (current) { 908 current->d_ptr->current_fbo = current->d_ptr->default_fbo; 909 glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo); 910 } 911 912 return true; 501 913 } 502 914 … … 507 919 rendering target in this framebuffer object. This texture id can 508 920 be bound as a normal texture in your own GL code. 921 922 923 509 924 */ 510 925 GLuint QGLFramebufferObject::texture() const … … 524 939 Q_D(const QGLFramebufferObject); 525 940 return d->size; 941 942 943 944 945 946 947 948 949 526 950 } 527 951 … … 537 961 return QImage(); 538 962 539 const_cast<QGLFramebufferObject *>(this)->bind(); 540 QImage image = qt_gl_read_framebuffer(d->size, d->ctx->format().alpha(), true); 541 const_cast<QGLFramebufferObject *>(this)->release(); 963 // qt_gl_read_framebuffer doesn't work on a multisample FBO 964 if (format().samples() != 0) { 965 QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat()); 966 967 QRect rect(QPoint(0, 0), size()); 968 blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect); 969 970 return temp.toImage(); 971 } 972 973 bool wasBound = isBound(); 974 if (!wasBound) 975 const_cast<QGLFramebufferObject *>(this)->bind(); 976 QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true); 977 if (!wasBound) 978 const_cast<QGLFramebufferObject *>(this)->release(); 542 979 543 980 return image; 544 981 } 545 982 546 #if !defined(QT_OPENGL_ES_2) 547 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine) 983 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) 984 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine) 985 #endif 986 987 #ifndef QT_OPENGL_ES_2 988 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine) 548 989 #endif 549 990 … … 551 992 QPaintEngine *QGLFramebufferObject::paintEngine() const 552 993 { 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 553 1013 #if !defined(QT_OPENGL_ES_2) 554 return qt_buffer_paintengine(); 555 #else 556 return 0; 1014 QPaintEngine *engine = qt_buffer_engine(); 1015 if (engine->isActive() && engine->paintDevice() != this) { 1016 d->engine = new QOpenGLPaintEngine; 1017 return d->engine; 1018 } 1019 return engine; 557 1020 #endif 558 1021 } … … 566 1029 bool QGLFramebufferObject::hasOpenGLFramebufferObjects() 567 1030 { 568 QGL Widget dmy; // needed to detect and init the QGLExtensions object1031 QGL 569 1032 return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); 570 1033 } … … 583 1046 void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) 584 1047 { 585 Q_D(QGLFramebufferObject); 586 d->ctx->drawTexture(target, textureId, textureTarget); 1048 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget); 587 1049 } 588 1050 … … 591 1053 void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget) 592 1054 { 593 Q_D(QGLFramebufferObject); 594 d->ctx->drawTexture(target, textureId, textureTarget); 1055 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget); 595 1056 } 596 1057 #endif … … 608 1069 void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) 609 1070 { 610 Q_D(QGLFramebufferObject); 611 d->ctx->drawTexture(point, textureId, textureTarget); 1071 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget); 612 1072 } 613 1073 … … 616 1076 void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget) 617 1077 { 618 Q_D(QGLFramebufferObject);619 d->ctx->drawTexture(point, textureId, textureTarget); 620 } 621 #endif 622 623 extern int qt_defaultDpi ();1078 t); 1079 } 1080 #endif 1081 1082 extern int qt_defaultDpiX(); 1083 extern int qt_defaultDpi(); 624 1084 625 1085 /*! \reimp */ … … 628 1088 Q_D(const QGLFramebufferObject); 629 1089 630 float dpmx = qt_defaultDpi ()*100./2.54;631 float dpmy = qt_defaultDpi ()*100./2.54;1090 float dpmx = qt_defaultDpi()*100./2.54; 1091 float dpmy = qt_defaultDpi()*100./2.54; 632 1092 int w = d->size.width(); 633 1093 int h = d->size.height(); … … 652 1112 653 1113 case PdmDpiX: 654 return (int)(dpmx * 0.0254);1114 return (dpmx * 0.0254); 655 1115 656 1116 case PdmDpiY: 657 return (int)(dpmy * 0.0254);1117 return (dpmy * 0.0254); 658 1118 659 1119 case PdmPhysicalDpiX: 660 return (int)(dpmx * 0.0254);1120 return (dpmx * 0.0254); 661 1121 662 1122 case PdmPhysicalDpiY: 663 return (int)(dpmy * 0.0254);1123 return (dpmy * 0.0254); 664 1124 665 1125 default: … … 682 1142 { 683 1143 Q_D(const QGLFramebufferObject); 684 return d->fbo ;1144 return d->fbo; 685 1145 } 686 1146 687 1147 /*! \fn int QGLFramebufferObject::devType() const 688 689 \reimp 1148 \internal 690 1149 */ 691 1150 … … 714 1173 { 715 1174 Q_D(const QGLFramebufferObject); 716 return d->bound; 1175 const QGLContext *current = QGLContext::currentContext(); 1176 return current ? current->d_ptr->current_fbo == d->fbo() : false; 1177 } 1178 1179 /*! 1180 \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit() 1181 1182 \since 4.6 1183 1184 Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension 1185 is present on this system; otherwise returns false. 1186 1187 \sa blitFramebuffer() 1188 */ 1189 bool QGLFramebufferObject::hasOpenGLFramebufferBlit() 1190 { 1191 QGLExtensions::init(); 1192 return (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit); 1193 } 1194 1195 /*! 1196 \since 4.6 1197 1198 Blits from the \a sourceRect rectangle in the \a source framebuffer 1199 object to the \a targetRect rectangle in the \a target framebuffer object. 1200 1201 If \a source or \a target is 0, the default framebuffer will be used 1202 instead of a framebuffer object as source or target respectively. 1203 1204 The \a buffers parameter should be a mask consisting of any combination of 1205 \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and 1206 \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both 1207 in the source and target buffers is ignored. 1208 1209 The \a sourceRect and \a targetRect rectangles may have different sizes; 1210 in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or 1211 \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to 1212 \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest 1213 interpolation should be used when scaling is performed. 1214 1215 If \a source equals \a target a copy is performed within the same buffer. 1216 Results are undefined if the source and target rectangles overlap and 1217 have different sizes. The sizes must also be the same if any of the 1218 framebuffer objects are multisample framebuffers. 1219 1220 Note that the scissor test will restrict the blit area if enabled. 1221 1222 This function will have no effect unless hasOpenGLFramebufferBlit() returns 1223 true. 1224 1225 \sa hasOpenGLFramebufferBlit() 1226 */ 1227 void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect, 1228 QGLFramebufferObject *source, const QRect &sourceRect, 1229 GLbitfield buffers, 1230 GLenum filter) 1231 { 1232 if (!(QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)) 1233 return; 1234 1235 const QGLContext *ctx = QGLContext::currentContext(); 1236 if (!ctx) 1237 return; 1238 1239 const int height = ctx->device()->height(); 1240 1241 const int sh = source ? source->height() : height; 1242 const int th = target ? target->height() : height; 1243 1244 const int sx0 = sourceRect.left(); 1245 const int sx1 = sourceRect.left() + sourceRect.width(); 1246 const int sy0 = sh - (sourceRect.top() + sourceRect.height()); 1247 const int sy1 = sh - sourceRect.top(); 1248 1249 const int tx0 = targetRect.left(); 1250 const int tx1 = targetRect.left() + targetRect.width(); 1251 const int ty0 = th - (targetRect.top() + targetRect.height()); 1252 const int ty1 = th - targetRect.top(); 1253 1254 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0); 1255 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0); 1256 1257 glBlitFramebufferEXT(sx0, sy0, sx1, sy1, 1258 tx0, ty0, tx1, ty1, 1259 buffers, filter); 1260 1261 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); 717 1262 } 718 1263
Note:
See TracChangeset
for help on using the changeset viewer.