1 // 2 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer 8 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. 9 10 #include "libGLESv2/Framebuffer.h" 11 #include "libGLESv2/main.h" 12 #include "libGLESv2/formatutils.h" 13 #include "libGLESv2/Texture.h" 14 #include "libGLESv2/Context.h" 15 #include "libGLESv2/Renderbuffer.h" 16 #include "libGLESv2/FramebufferAttachment.h" 17 #include "libGLESv2/renderer/Renderer.h" 18 #include "libGLESv2/renderer/RenderTarget.h" 19 #include "libGLESv2/renderer/d3d/TextureD3D.h" 20 21 #include "common/utilities.h" 22 23 namespace rx 24 { 25 RenderTarget *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment) 26 { 27 if (attachment->isTexture()) 28 { 29 gl::Texture *texture = attachment->getTexture(); 30 ASSERT(texture); 31 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); 32 const gl::ImageIndex *index = attachment->getTextureImageIndex(); 33 ASSERT(index); 34 return textureD3D->getRenderTarget(*index); 35 } 36 37 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); 38 ASSERT(renderbuffer); 39 40 // TODO: cast to RenderbufferD3D 41 return renderbuffer->getStorage()->getRenderTarget(); 42 } 43 44 // Note: RenderTarget serials should ideally be in the RenderTargets themselves. 45 unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment) 46 { 47 if (attachment->isTexture()) 48 { 49 gl::Texture *texture = attachment->getTexture(); 50 ASSERT(texture); 51 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); 52 const gl::ImageIndex *index = attachment->getTextureImageIndex(); 53 ASSERT(index); 54 return textureD3D->getRenderTargetSerial(*index); 55 } 56 57 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); 58 ASSERT(renderbuffer); 59 60 // TODO: cast to RenderbufferD3D 61 return renderbuffer->getStorage()->getSerial(); 62 } 63 64 } 65 66 namespace gl 67 { 68 69 Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id) 70 : mRenderer(renderer), 71 mId(id), 72 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT), 73 mDepthbuffer(NULL), 74 mStencilbuffer(NULL) 75 { 76 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 77 { 78 mColorbuffers[colorAttachment] = NULL; 79 mDrawBufferStates[colorAttachment] = GL_NONE; 80 } 81 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; 82 } 83 84 Framebuffer::~Framebuffer() 85 { 86 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 87 { 88 SafeDelete(mColorbuffers[colorAttachment]); 89 } 90 SafeDelete(mDepthbuffer); 91 SafeDelete(mStencilbuffer); 92 } 93 94 FramebufferAttachment *Framebuffer::createAttachment(GLenum binding, GLenum type, GLuint handle, GLint level, GLint layer) const 95 { 96 if (handle == 0) 97 { 98 return NULL; 99 } 100 101 gl::Context *context = gl::getContext(); 102 103 switch (type) 104 { 105 case GL_NONE: 106 return NULL; 107 108 case GL_RENDERBUFFER: 109 return new RenderbufferAttachment(binding, context->getRenderbuffer(handle)); 110 111 case GL_TEXTURE_2D: 112 { 113 Texture *texture = context->getTexture(handle); 114 if (texture && texture->getTarget() == GL_TEXTURE_2D) 115 { 116 return new TextureAttachment(binding, texture, ImageIndex::Make2D(level)); 117 } 118 else 119 { 120 return NULL; 121 } 122 } 123 124 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 125 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 126 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 127 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 128 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 129 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 130 { 131 Texture *texture = context->getTexture(handle); 132 if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP) 133 { 134 return new TextureAttachment(binding, texture, ImageIndex::MakeCube(type, level)); 135 } 136 else 137 { 138 return NULL; 139 } 140 } 141 142 case GL_TEXTURE_3D: 143 { 144 Texture *texture = context->getTexture(handle); 145 if (texture && texture->getTarget() == GL_TEXTURE_3D) 146 { 147 return new TextureAttachment(binding, texture, ImageIndex::Make3D(level, layer)); 148 } 149 else 150 { 151 return NULL; 152 } 153 } 154 155 case GL_TEXTURE_2D_ARRAY: 156 { 157 Texture *texture = context->getTexture(handle); 158 if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY) 159 { 160 return new TextureAttachment(binding, texture, ImageIndex::Make2DArray(level, layer)); 161 } 162 else 163 { 164 return NULL; 165 } 166 } 167 168 default: 169 UNREACHABLE(); 170 return NULL; 171 } 172 } 173 174 void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer) 175 { 176 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); 177 SafeDelete(mColorbuffers[colorAttachment]); 178 GLenum binding = colorAttachment + GL_COLOR_ATTACHMENT0; 179 mColorbuffers[colorAttachment] = createAttachment(binding, type, colorbuffer, level, layer); 180 } 181 182 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer) 183 { 184 SafeDelete(mDepthbuffer); 185 mDepthbuffer = createAttachment(GL_DEPTH_ATTACHMENT, type, depthbuffer, level, layer); 186 } 187 188 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer) 189 { 190 SafeDelete(mStencilbuffer); 191 mStencilbuffer = createAttachment(GL_STENCIL_ATTACHMENT, type, stencilbuffer, level, layer); 192 } 193 194 void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer) 195 { 196 FramebufferAttachment *attachment = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer); 197 198 SafeDelete(mDepthbuffer); 199 SafeDelete(mStencilbuffer); 200 201 // ensure this is a legitimate depth+stencil format 202 if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0) 203 { 204 mDepthbuffer = attachment; 205 206 // Make a new attachment object to ensure we do not double-delete 207 // See angle issue 686 208 mStencilbuffer = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer); 209 } 210 } 211 212 void Framebuffer::detachTexture(GLuint textureId) 213 { 214 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 215 { 216 FramebufferAttachment *attachment = mColorbuffers[colorAttachment]; 217 218 if (attachment && attachment->isTextureWithId(textureId)) 219 { 220 SafeDelete(mColorbuffers[colorAttachment]); 221 } 222 } 223 224 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId)) 225 { 226 SafeDelete(mDepthbuffer); 227 } 228 229 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId)) 230 { 231 SafeDelete(mStencilbuffer); 232 } 233 } 234 235 void Framebuffer::detachRenderbuffer(GLuint renderbufferId) 236 { 237 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 238 { 239 FramebufferAttachment *attachment = mColorbuffers[colorAttachment]; 240 241 if (attachment && attachment->isRenderbufferWithId(renderbufferId)) 242 { 243 SafeDelete(mColorbuffers[colorAttachment]); 244 } 245 } 246 247 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId)) 248 { 249 SafeDelete(mDepthbuffer); 250 } 251 252 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId)) 253 { 254 SafeDelete(mStencilbuffer); 255 } 256 } 257 258 FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const 259 { 260 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); 261 return mColorbuffers[colorAttachment]; 262 } 263 264 FramebufferAttachment *Framebuffer::getDepthbuffer() const 265 { 266 return mDepthbuffer; 267 } 268 269 FramebufferAttachment *Framebuffer::getStencilbuffer() const 270 { 271 return mStencilbuffer; 272 } 273 274 FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const 275 { 276 return (hasValidDepthStencil() ? mDepthbuffer : NULL); 277 } 278 279 FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const 280 { 281 FramebufferAttachment *depthstencilbuffer = mDepthbuffer; 282 283 if (!depthstencilbuffer) 284 { 285 depthstencilbuffer = mStencilbuffer; 286 } 287 288 return depthstencilbuffer; 289 } 290 291 FramebufferAttachment *Framebuffer::getReadColorbuffer() const 292 { 293 // Will require more logic if glReadBuffers is supported 294 return mColorbuffers[0]; 295 } 296 297 GLenum Framebuffer::getReadColorbufferType() const 298 { 299 // Will require more logic if glReadBuffers is supported 300 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE); 301 } 302 303 FramebufferAttachment *Framebuffer::getFirstColorbuffer() const 304 { 305 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 306 { 307 if (mColorbuffers[colorAttachment]) 308 { 309 return mColorbuffers[colorAttachment]; 310 } 311 } 312 313 return NULL; 314 } 315 316 FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const 317 { 318 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) 319 { 320 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0); 321 } 322 else 323 { 324 switch (attachment) 325 { 326 case GL_DEPTH_ATTACHMENT: 327 return getDepthbuffer(); 328 case GL_STENCIL_ATTACHMENT: 329 return getStencilbuffer(); 330 case GL_DEPTH_STENCIL_ATTACHMENT: 331 return getDepthStencilBuffer(); 332 default: 333 UNREACHABLE(); 334 return NULL; 335 } 336 } 337 } 338 339 GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const 340 { 341 return mDrawBufferStates[colorAttachment]; 342 } 343 344 void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer) 345 { 346 mDrawBufferStates[colorAttachment] = drawBuffer; 347 } 348 349 bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const 350 { 351 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE); 352 } 353 354 bool Framebuffer::hasEnabledColorAttachment() const 355 { 356 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 357 { 358 if (isEnabledColorAttachment(colorAttachment)) 359 { 360 return true; 361 } 362 } 363 364 return false; 365 } 366 367 bool Framebuffer::hasStencil() const 368 { 369 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0); 370 } 371 372 bool Framebuffer::usingExtendedDrawBuffers() const 373 { 374 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 375 { 376 if (isEnabledColorAttachment(colorAttachment)) 377 { 378 return true; 379 } 380 } 381 382 return false; 383 } 384 385 GLenum Framebuffer::completeness() const 386 { 387 int width = 0; 388 int height = 0; 389 unsigned int colorbufferSize = 0; 390 int samples = -1; 391 bool missingAttachment = true; 392 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 393 394 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 395 { 396 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment]; 397 398 if (colorbuffer) 399 { 400 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) 401 { 402 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 403 } 404 405 GLenum internalformat = colorbuffer->getInternalFormat(); 406 // TODO(geofflang): use context's texture caps 407 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); 408 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); 409 if (colorbuffer->isTexture()) 410 { 411 if (!formatCaps.renderable) 412 { 413 return GL_FRAMEBUFFER_UNSUPPORTED; 414 } 415 416 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) 417 { 418 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 419 } 420 } 421 else 422 { 423 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) 424 { 425 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 426 } 427 } 428 429 if (!missingAttachment) 430 { 431 // all color attachments must have the same width and height 432 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height) 433 { 434 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 435 } 436 437 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that 438 // all color attachments have the same number of samples for the FBO to be complete. 439 if (colorbuffer->getSamples() != samples) 440 { 441 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; 442 } 443 444 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes 445 // in GLES 3.0, there is no such restriction 446 if (clientVersion < 3) 447 { 448 if (formatInfo.pixelBytes != colorbufferSize) 449 { 450 return GL_FRAMEBUFFER_UNSUPPORTED; 451 } 452 } 453 454 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness 455 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++) 456 { 457 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment]; 458 459 if (previousAttachment && 460 (colorbuffer->id() == previousAttachment->id() && 461 colorbuffer->type() == previousAttachment->type())) 462 { 463 return GL_FRAMEBUFFER_UNSUPPORTED; 464 } 465 } 466 } 467 else 468 { 469 width = colorbuffer->getWidth(); 470 height = colorbuffer->getHeight(); 471 samples = colorbuffer->getSamples(); 472 colorbufferSize = formatInfo.pixelBytes; 473 missingAttachment = false; 474 } 475 } 476 } 477 478 if (mDepthbuffer) 479 { 480 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0) 481 { 482 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 483 } 484 485 GLenum internalformat = mDepthbuffer->getInternalFormat(); 486 // TODO(geofflang): use context's texture caps 487 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); 488 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); 489 if (mDepthbuffer->isTexture()) 490 { 491 // depth texture attachments require OES/ANGLE_depth_texture 492 // TODO(geofflang): use context's extensions 493 if (!mRenderer->getRendererExtensions().depthTextures) 494 { 495 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 496 } 497 498 if (!formatCaps.renderable) 499 { 500 return GL_FRAMEBUFFER_UNSUPPORTED; 501 } 502 503 if (formatInfo.depthBits == 0) 504 { 505 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 506 } 507 } 508 else 509 { 510 if (!formatCaps.renderable || formatInfo.depthBits == 0) 511 { 512 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 513 } 514 } 515 516 if (missingAttachment) 517 { 518 width = mDepthbuffer->getWidth(); 519 height = mDepthbuffer->getHeight(); 520 samples = mDepthbuffer->getSamples(); 521 missingAttachment = false; 522 } 523 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight()) 524 { 525 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 526 } 527 else if (samples != mDepthbuffer->getSamples()) 528 { 529 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; 530 } 531 } 532 533 if (mStencilbuffer) 534 { 535 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0) 536 { 537 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 538 } 539 540 GLenum internalformat = mStencilbuffer->getInternalFormat(); 541 // TODO(geofflang): use context's texture caps 542 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); 543 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); 544 if (mStencilbuffer->isTexture()) 545 { 546 // texture stencil attachments come along as part 547 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture 548 // TODO(geofflang): use context's extensions 549 if (!mRenderer->getRendererExtensions().depthTextures) 550 { 551 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 552 } 553 554 if (!formatCaps.renderable) 555 { 556 return GL_FRAMEBUFFER_UNSUPPORTED; 557 } 558 559 if (formatInfo.stencilBits == 0) 560 { 561 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 562 } 563 } 564 else 565 { 566 if (!formatCaps.renderable || formatInfo.stencilBits == 0) 567 { 568 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 569 } 570 } 571 572 if (missingAttachment) 573 { 574 width = mStencilbuffer->getWidth(); 575 height = mStencilbuffer->getHeight(); 576 samples = mStencilbuffer->getSamples(); 577 missingAttachment = false; 578 } 579 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight()) 580 { 581 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 582 } 583 else if (samples != mStencilbuffer->getSamples()) 584 { 585 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; 586 } 587 } 588 589 // if we have both a depth and stencil buffer, they must refer to the same object 590 // since we only support packed_depth_stencil and not separate depth and stencil 591 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil()) 592 { 593 return GL_FRAMEBUFFER_UNSUPPORTED; 594 } 595 596 // we need to have at least one attachment to be complete 597 if (missingAttachment) 598 { 599 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; 600 } 601 602 return GL_FRAMEBUFFER_COMPLETE; 603 } 604 605 void Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments) 606 { 607 GLuint maxDimension = caps.maxRenderbufferSize; 608 invalidateSub(caps, numAttachments, attachments, 0, 0, maxDimension, maxDimension); 609 } 610 611 void Framebuffer::invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments, 612 GLint x, GLint y, GLsizei width, GLsizei height) 613 { 614 ASSERT(completeness() == GL_FRAMEBUFFER_COMPLETE); 615 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex) 616 { 617 GLenum attachmentTarget = attachments[attachIndex]; 618 619 gl::FramebufferAttachment *attachment = 620 (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() : 621 getAttachment(attachmentTarget); 622 623 if (attachment) 624 { 625 rx::RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment); 626 if (renderTarget) 627 { 628 renderTarget->invalidate(x, y, width, height); 629 } 630 } 631 } 632 } 633 634 DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) 635 : Framebuffer(renderer, 0) 636 { 637 Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer); 638 mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer); 639 640 GLenum depthStencilActualFormat = depthStencil->getActualFormat(); 641 const gl::InternalFormat &depthStencilFormatInfo = GetInternalFormatInfo(depthStencilActualFormat); 642 643 if (depthStencilFormatInfo.depthBits != 0 || depthStencilFormatInfo.stencilBits != 0) 644 { 645 Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil); 646 647 // Make a new attachment objects to ensure we do not double-delete 648 // See angle issue 686 649 mDepthbuffer = (depthStencilFormatInfo.depthBits != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL); 650 mStencilbuffer = (depthStencilFormatInfo.stencilBits != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL); 651 } 652 else 653 { 654 // This method transfers ownership, so delete the unused storage if we don't keep it. 655 SafeDelete(depthStencil); 656 } 657 658 mDrawBufferStates[0] = GL_BACK; 659 mReadBufferState = GL_BACK; 660 } 661 662 int Framebuffer::getSamples() const 663 { 664 if (completeness() == GL_FRAMEBUFFER_COMPLETE) 665 { 666 // for a complete framebuffer, all attachments must have the same sample count 667 // in this case return the first nonzero sample size 668 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 669 { 670 if (mColorbuffers[colorAttachment]) 671 { 672 return mColorbuffers[colorAttachment]->getSamples(); 673 } 674 } 675 } 676 677 return 0; 678 } 679 680 bool Framebuffer::hasValidDepthStencil() const 681 { 682 // A valid depth-stencil attachment has the same resource bound to both the 683 // depth and stencil attachment points. 684 return (mDepthbuffer && mStencilbuffer && 685 mDepthbuffer->type() == mStencilbuffer->type() && 686 mDepthbuffer->id() == mStencilbuffer->id()); 687 } 688 689 ColorbufferInfo Framebuffer::getColorbuffersForRender() const 690 { 691 ColorbufferInfo colorbuffersForRender; 692 693 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment) 694 { 695 GLenum drawBufferState = mDrawBufferStates[colorAttachment]; 696 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment]; 697 698 if (colorbuffer != NULL && drawBufferState != GL_NONE) 699 { 700 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment)); 701 colorbuffersForRender.push_back(colorbuffer); 702 } 703 #if (ANGLE_MRT_PERF_WORKAROUND == ANGLE_WORKAROUND_DISABLED) 704 else 705 { 706 colorbuffersForRender.push_back(NULL); 707 } 708 #endif 709 } 710 711 return colorbuffersForRender; 712 } 713 714 GLenum DefaultFramebuffer::completeness() const 715 { 716 // The default framebuffer *must* always be complete, though it may not be 717 // subject to the same rules as application FBOs. ie, it could have 0x0 size. 718 return GL_FRAMEBUFFER_COMPLETE; 719 } 720 721 FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const 722 { 723 switch (attachment) 724 { 725 case GL_COLOR: 726 case GL_BACK: 727 return getColorbuffer(0); 728 case GL_DEPTH: 729 return getDepthbuffer(); 730 case GL_STENCIL: 731 return getStencilbuffer(); 732 case GL_DEPTH_STENCIL: 733 return getDepthStencilBuffer(); 734 default: 735 UNREACHABLE(); 736 return NULL; 737 } 738 } 739 740 } 741