FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const { if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) { return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0); } else { switch (attachment) { case GL_DEPTH_ATTACHMENT: return getDepthbuffer(); case GL_STENCIL_ATTACHMENT: return getStencilbuffer(); case GL_DEPTH_STENCIL_ATTACHMENT: return getDepthStencilBuffer(); default: UNREACHABLE(); return NULL; } } }
GLenum Framebuffer::completeness() const { int width = 0; int height = 0; int colorbufferSize = 0; int samples = -1; bool missingAttachment = true; for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { if (mColorbufferTypes[colorAttachment] != GL_NONE) { const Renderbuffer *colorbuffer = getColorbuffer(colorAttachment); if (!colorbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (mColorbufferTypes[colorAttachment] == GL_RENDERBUFFER) { if (!gl::IsColorRenderable(colorbuffer->getInternalFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else if (IsInternalTextureTarget(mColorbufferTypes[colorAttachment])) { GLint internalformat = colorbuffer->getInternalFormat(); GLenum format = gl::ExtractFormat(internalformat); if (IsCompressed(format) || format == GL_ALPHA || format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { return GL_FRAMEBUFFER_UNSUPPORTED; } bool filtering, renderable; if ((gl::IsFloat32Format(internalformat) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || (gl::IsFloat16Format(internalformat) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) { return GL_FRAMEBUFFER_UNSUPPORTED; } if (gl::IsDepthTexture(internalformat) || gl::IsStencilTexture(internalformat)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else { UNREACHABLE(); return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (!missingAttachment) { // all color attachments must have the same width and height if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that // all color attachments have the same number of samples for the FBO to be complete. if (colorbuffer->getSamples() != samples) { return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; } // all color attachments attachments must have the same number of bitplanes if (gl::ComputePixelSize(colorbuffer->getInternalFormat()) != colorbufferSize) { return GL_FRAMEBUFFER_UNSUPPORTED; } // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++) { if (mColorbufferPointers[colorAttachment].get() == mColorbufferPointers[previousColorAttachment].get()) { return GL_FRAMEBUFFER_UNSUPPORTED; } } } else { width = colorbuffer->getWidth(); height = colorbuffer->getHeight(); samples = colorbuffer->getSamples(); colorbufferSize = gl::ComputePixelSize(colorbuffer->getInternalFormat()); missingAttachment = false; } } } const Renderbuffer *depthbuffer = NULL; const Renderbuffer *stencilbuffer = NULL; if (mDepthbufferType != GL_NONE) { depthbuffer = getDepthbuffer(); if (!depthbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (mDepthbufferType == GL_RENDERBUFFER) { if (!gl::IsDepthRenderable(depthbuffer->getInternalFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else if (IsInternalTextureTarget(mDepthbufferType)) { GLint internalformat = depthbuffer->getInternalFormat(); // depth texture attachments require OES/ANGLE_depth_texture if (!mRenderer->getDepthTextureSupport()) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (!gl::IsDepthTexture(internalformat)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else { UNREACHABLE(); return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (missingAttachment) { width = depthbuffer->getWidth(); height = depthbuffer->getHeight(); samples = depthbuffer->getSamples(); missingAttachment = false; } else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } else if (samples != depthbuffer->getSamples()) { return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; } } if (mStencilbufferType != GL_NONE) { stencilbuffer = getStencilbuffer(); if (!stencilbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (mStencilbufferType == GL_RENDERBUFFER) { if (!gl::IsStencilRenderable(stencilbuffer->getInternalFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else if (IsInternalTextureTarget(mStencilbufferType)) { GLint internalformat = stencilbuffer->getInternalFormat(); // texture stencil attachments come along as part // of OES_packed_depth_stencil + OES/ANGLE_depth_texture if (!mRenderer->getDepthTextureSupport()) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (!gl::IsStencilTexture(internalformat)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else { UNREACHABLE(); return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (missingAttachment) { width = stencilbuffer->getWidth(); height = stencilbuffer->getHeight(); samples = stencilbuffer->getSamples(); missingAttachment = false; } else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } else if (samples != stencilbuffer->getSamples()) { return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; } } // if we have both a depth and stencil buffer, they must refer to the same object // since we only support packed_depth_stencil and not separate depth and stencil if (depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer)) { return GL_FRAMEBUFFER_UNSUPPORTED; } // we need to have at least one attachment to be complete if (missingAttachment) { return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; } return GL_FRAMEBUFFER_COMPLETE; }
GLenum Framebuffer::completeness() { int width = 0; int height = 0; int samples = -1; if (mColorbufferType != GL_NONE) { Colorbuffer *colorbuffer = getColorbuffer(); if (!colorbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (IsTextureTarget(mColorbufferType)) { if (IsCompressed(colorbuffer->getFormat())) { return GL_FRAMEBUFFER_UNSUPPORTED; } } width = colorbuffer->getWidth(); height = colorbuffer->getHeight(); samples = colorbuffer->getSamples(); } else { return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; } DepthStencilbuffer *depthbuffer = NULL; DepthStencilbuffer *stencilbuffer = NULL; if (mDepthbufferType != GL_NONE) { depthbuffer = getDepthbuffer(); if (!depthbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (width == 0) { width = depthbuffer->getWidth(); height = depthbuffer->getHeight(); } else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } if (samples == -1) { samples = depthbuffer->getSamples(); } else if (samples != depthbuffer->getSamples()) { return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; } if (IsTextureTarget(mDepthbufferType)) { if (IsCompressed(depthbuffer->getFormat())) { return GL_FRAMEBUFFER_UNSUPPORTED; } } } if (mStencilbufferType != GL_NONE) { stencilbuffer = getStencilbuffer(); if (!stencilbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (width == 0) { width = stencilbuffer->getWidth(); height = stencilbuffer->getHeight(); } else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } if (samples == -1) { samples = stencilbuffer->getSamples(); } else if (samples != stencilbuffer->getSamples()) { return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; } if (IsTextureTarget(mStencilbufferType)) { if (IsCompressed(stencilbuffer->getFormat())) { return GL_FRAMEBUFFER_UNSUPPORTED; } } } if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER) { if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES || stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES || depthbuffer->getSerial() != stencilbuffer->getSerial()) { return GL_FRAMEBUFFER_UNSUPPORTED; } } return GL_FRAMEBUFFER_COMPLETE; }
GLenum Framebuffer::completeness(int &width, int &height, int &samples) { width = -1; height = -1; samples = -1; if(mColorbufferType != GL_NONE_OES) { Renderbuffer *colorbuffer = getColorbuffer(); if(!colorbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(mColorbufferType == GL_RENDERBUFFER_OES) { if(!IsColorRenderable(colorbuffer->getFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } } else if(IsTextureTarget(mColorbufferType)) { GLenum format = colorbuffer->getFormat(); if(!IsColorRenderable(format)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(IsDepthTexture(format) || IsStencilTexture(format)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } } else { UNREACHABLE(mColorbufferType); return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } width = colorbuffer->getWidth(); height = colorbuffer->getHeight(); samples = colorbuffer->getSamples(); } Renderbuffer *depthbuffer = nullptr; Renderbuffer *stencilbuffer = nullptr; if(mDepthbufferType != GL_NONE_OES) { depthbuffer = getDepthbuffer(); if(!depthbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(mDepthbufferType == GL_RENDERBUFFER_OES) { if(!es1::IsDepthRenderable(depthbuffer->getFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } } else if(IsTextureTarget(mDepthbufferType)) { if(!es1::IsDepthTexture(depthbuffer->getFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } } else { UNREACHABLE(mDepthbufferType); return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(width == -1 || height == -1) { width = depthbuffer->getWidth(); height = depthbuffer->getHeight(); samples = depthbuffer->getSamples(); } else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES; } else if(samples != depthbuffer->getSamples()) { UNREACHABLE(0); } } if(mStencilbufferType != GL_NONE_OES) { stencilbuffer = getStencilbuffer(); if(!stencilbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(mStencilbufferType == GL_RENDERBUFFER_OES) { if(!es1::IsStencilRenderable(stencilbuffer->getFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } } else if(IsTextureTarget(mStencilbufferType)) { GLenum internalformat = stencilbuffer->getFormat(); if(!es1::IsStencilTexture(internalformat)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } } else { UNREACHABLE(mStencilbufferType); return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; } if(width == -1 || height == -1) { width = stencilbuffer->getWidth(); height = stencilbuffer->getHeight(); samples = stencilbuffer->getSamples(); } else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES; } else if(samples != stencilbuffer->getSamples()) { UNREACHABLE(0); return GL_FRAMEBUFFER_UNSUPPORTED_OES; // GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_OES; } } // We need to have at least one attachment to be complete if(width == -1 || height == -1) { return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES; } return GL_FRAMEBUFFER_COMPLETE_OES; }