void RenderTarget::CheckCompleteness() const { const GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { throw fbo_incomplete(status); } }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct brw_context *brw = brw_context(ctx); struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; DBG("%s() on fb %p (%s)\n", __FUNCTION__, fb, (fb == ctx->DrawBuffer ? "drawbuffer" : (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); if (depthRb) depth_mt = depthRb->mt; if (stencilRb) { stencil_mt = stencilRb->mt; if (stencil_mt->stencil_mt) stencil_mt = stencil_mt->stencil_mt; } if (depth_mt && stencil_mt) { if (depth_mt == stencil_mt) { /* For true packed depth/stencil (not faked on prefers-separate-stencil * hardware) we need to be sure they're the same level/layer, since * we'll be emitting a single packet describing the packed setup. */ if (depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { fbo_incomplete(fb, "FBO incomplete: depth image level/layer %d/%d != " "stencil image %d/%d\n", depthRb->mt_level, depthRb->mt_layer, stencilRb->mt_level, stencilRb->mt_layer); } } else { if (!brw->has_separate_stencil) { fbo_incomplete(fb, "FBO incomplete: separate stencil " "unsupported\n"); } if (stencil_mt->format != MESA_FORMAT_S8) { fbo_incomplete(fb, "FBO incomplete: separate stencil is %s " "instead of S8\n", _mesa_get_format_name(stencil_mt->format)); } if (brw->gen < 7 && !intel_renderbuffer_has_hiz(depthRb)) { /* Before Gen7, separate depth and stencil buffers can be used * only if HiZ is enabled. From the Sandybridge PRM, Volume 2, * Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable: * [DevSNB]: This field must be set to the same value (enabled * or disabled) as Hierarchical Depth Buffer Enable. */ fbo_incomplete(fb, "FBO incomplete: separate stencil " "without HiZ\n"); } } } for (i = 0; i < Elements(fb->Attachment); i++) { struct gl_renderbuffer *rb; struct intel_renderbuffer *irb; if (fb->Attachment[i].Type == GL_NONE) continue; /* A supported attachment will have a Renderbuffer set either * from being a Renderbuffer or being a texture that got the * intel_wrap_texture() treatment. */ rb = fb->Attachment[i].Renderbuffer; if (rb == NULL) { fbo_incomplete(fb, "FBO incomplete: attachment without " "renderbuffer\n"); continue; } if (fb->Attachment[i].Type == GL_TEXTURE) { if (rb->TexImage->Border) { fbo_incomplete(fb, "FBO incomplete: texture with border\n"); continue; } } irb = intel_renderbuffer(rb); if (irb == NULL) { fbo_incomplete(fb, "FBO incomplete: software rendering " "renderbuffer\n"); continue; } if (!brw_render_target_supported(brw, rb)) { fbo_incomplete(fb, "FBO incomplete: Unsupported HW " "texture/renderbuffer format attached: %s\n", _mesa_get_format_name(intel_rb_format(irb))); } } }
/** * Test if the given framebuffer object is complete and update its * Status field with the results. * Also update the framebuffer's Width and Height fields if the * framebuffer is complete. */ void _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) { GLuint numImages, width = 0, height = 0; GLenum intFormat = GL_NONE; GLuint w = 0, h = 0; GLint i; GLuint j; assert(fb->Name != 0); numImages = 0; fb->Width = 0; fb->Height = 0; /* Start at -2 to more easily loop over all attachment points */ for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { struct gl_renderbuffer_attachment *att; GLenum f; if (i == -2) { att = &fb->Attachment[BUFFER_DEPTH]; test_attachment_completeness(ctx, GL_DEPTH, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; fbo_incomplete("depth attachment incomplete", -1); return; } } else if (i == -1) { att = &fb->Attachment[BUFFER_STENCIL]; test_attachment_completeness(ctx, GL_STENCIL, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; fbo_incomplete("stencil attachment incomplete", -1); return; } } else { att = &fb->Attachment[BUFFER_COLOR0 + i]; test_attachment_completeness(ctx, GL_COLOR, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; fbo_incomplete("color attachment incomplete", i); return; } } if (att->Type == GL_TEXTURE) { const struct gl_texture_image *texImg = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; w = texImg->Width; h = texImg->Height; f = texImg->_BaseFormat; numImages++; if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT && f != GL_DEPTH_STENCIL_EXT) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; fbo_incomplete("texture attachment incomplete", -1); return; } } else if (att->Type == GL_RENDERBUFFER_EXT) { w = att->Renderbuffer->Width; h = att->Renderbuffer->Height; f = att->Renderbuffer->InternalFormat; numImages++; } else { assert(att->Type == GL_NONE); continue; } if (numImages == 1) { /* set required width, height and format */ width = w; height = h; if (i >= 0) intFormat = f; } else { /* check that width, height, format are same */ if (w != width || h != height) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; fbo_incomplete("width or height mismatch", -1); return; } if (intFormat != GL_NONE && f != intFormat) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; fbo_incomplete("format mismatch", -1); return; } } } #ifndef FEATURE_OES_framebuffer_object /* Check that all DrawBuffers are present */ for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { if (fb->ColorDrawBuffer[j] != GL_NONE) { const struct gl_renderbuffer_attachment *att = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; fbo_incomplete("missing drawbuffer", j); return; } } } /* Check that the ReadBuffer is present */ if (fb->ColorReadBuffer != GL_NONE) { const struct gl_renderbuffer_attachment *att = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; fbo_incomplete("missing readbuffer", -1); return; } } #endif if (numImages == 0) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; fbo_incomplete("no attachments", -1); return; } /* * If we get here, the framebuffer is complete! */ fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; fb->Width = w; fb->Height = h; }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; DBG("%s() on fb %p (%s)\n", __FUNCTION__, fb, (fb == ctx->DrawBuffer ? "drawbuffer" : (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); if (depthRb) depth_mt = depthRb->mt; if (stencilRb) stencil_mt = stencilRb->mt; if (depth_mt && stencil_mt) { /* Make sure that the depth and stencil buffers are actually the same * slice of the same miptree, since we only support packed * depth/stencil. */ if (depth_mt == stencil_mt) { if (depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { fbo_incomplete(fb, "FBO incomplete: depth image level/layer %d/%d != " "stencil image %d/%d\n", depthRb->mt_level, depthRb->mt_layer, stencilRb->mt_level, stencilRb->mt_layer); } } else { fbo_incomplete(fb, "FBO incomplete: separate stencil unsupported\n"); } } for (i = 0; i < Elements(fb->Attachment); i++) { struct gl_renderbuffer *rb; struct intel_renderbuffer *irb; if (fb->Attachment[i].Type == GL_NONE) continue; /* A supported attachment will have a Renderbuffer set either * from being a Renderbuffer or being a texture that got the * intel_wrap_texture() treatment. */ rb = fb->Attachment[i].Renderbuffer; if (rb == NULL) { fbo_incomplete(fb, "FBO incomplete: attachment without " "renderbuffer\n"); continue; } if (fb->Attachment[i].Type == GL_TEXTURE) { if (rb->TexImage->Border) { fbo_incomplete(fb, "FBO incomplete: texture with border\n"); continue; } } irb = intel_renderbuffer(rb); if (irb == NULL) { fbo_incomplete(fb, "FBO incomplete: software rendering " "renderbuffer\n"); continue; } if (!intel->vtbl.render_target_supported(intel, rb)) { fbo_incomplete(fb, "FBO incomplete: Unsupported HW " "texture/renderbuffer format attached: %s\n", _mesa_get_format_name(intel_rb_format(irb))); } } }