/*
* Mesa 3-D graphics library
- * Version: 7.1
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved.
#include "texobj.h"
-/** Set this to 1 to debug/log glBlitFramebuffer() calls */
-#define DEBUG_BLIT 0
-
-
/**
* Notes:
*
static struct gl_framebuffer *
get_framebuffer_target(struct gl_context *ctx, GLenum target)
{
- bool have_fb_blit = _mesa_is_gles3(ctx) ||
- (ctx->Extensions.EXT_framebuffer_blit && _mesa_is_desktop_gl(ctx));
+ bool have_fb_blit = _mesa_is_gles3(ctx) || _mesa_is_desktop_gl(ctx);
switch (target) {
case GL_DRAW_FRAMEBUFFER:
return have_fb_blit ? ctx->DrawBuffer : NULL;
* If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
* the depth buffer attachment point.
*/
-struct gl_renderbuffer_attachment *
-_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
- GLenum attachment)
+static struct gl_renderbuffer_attachment *
+get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLenum attachment)
{
GLuint i;
* Remove any texture or renderbuffer attached to the given attachment
* point. Update reference counts, etc.
*/
-void
-_mesa_remove_attachment(struct gl_context *ctx,
- struct gl_renderbuffer_attachment *att)
+static void
+remove_attachment(struct gl_context *ctx,
+ struct gl_renderbuffer_attachment *att)
{
+ struct gl_renderbuffer *rb = att->Renderbuffer;
+
+ /* tell driver that we're done rendering to this texture. */
+ if (rb && rb->NeedsFinishRenderTexture)
+ ctx->Driver.FinishRenderTexture(ctx, rb);
+
if (att->Type == GL_TEXTURE) {
ASSERT(att->Texture);
- if (ctx->Driver.FinishRenderTexture) {
- /* tell driver that we're done rendering to this texture. */
- ctx->Driver.FinishRenderTexture(ctx, att);
- }
_mesa_reference_texobj(&att->Texture, NULL); /* unbind */
ASSERT(!att->Texture);
}
att->Complete = GL_TRUE;
}
+/**
+ * Verify a couple error conditions that will lead to an incomplete FBO and
+ * may cause problems for the driver's RenderTexture path.
+ */
+static bool
+driver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att)
+{
+ const struct gl_texture_image *const texImage =
+ att->Texture->Image[att->CubeMapFace][att->TextureLevel];
+
+ if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
+ return false;
+
+ if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY
+ && att->Zoffset >= texImage->Height)
+ || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY
+ && att->Zoffset >= texImage->Depth))
+ return false;
+
+ return true;
+}
+
/**
* Create a renderbuffer which will be set up by the driver to wrap the
* texture image slice.
struct gl_texture_image *texImage;
struct gl_renderbuffer *rb;
- texImage = _mesa_get_attachment_teximage(att);
- if (!texImage)
- return;
+ texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
rb = att->Renderbuffer;
if (!rb) {
* for clarity compared to user renderbuffers.
*/
rb->AllocStorage = NULL;
+
+ rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL;
}
- ctx->Driver.RenderTexture(ctx, fb, att);
+ if (!texImage)
+ return;
+
+ rb->_BaseFormat = texImage->_BaseFormat;
+ rb->Format = texImage->TexFormat;
+ rb->InternalFormat = texImage->InternalFormat;
+ rb->Width = texImage->Width2;
+ rb->Height = texImage->Height2;
+ rb->Depth = texImage->Depth2;
+ rb->NumSamples = texImage->NumSamples;
+ rb->TexImage = texImage;
+
+ if (driver_RenderTexture_is_safe(att))
+ ctx->Driver.RenderTexture(ctx, fb, att);
}
/**
* Bind a texture object to an attachment point.
* The previous binding, if any, will be removed first.
*/
-void
-_mesa_set_texture_attachment(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- struct gl_renderbuffer_attachment *att,
- struct gl_texture_object *texObj,
- GLenum texTarget, GLuint level, GLuint zoffset,
- GLboolean layered)
+static void
+set_texture_attachment(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ struct gl_renderbuffer_attachment *att,
+ struct gl_texture_object *texObj,
+ GLenum texTarget, GLuint level, GLuint zoffset,
+ GLboolean layered)
{
+ struct gl_renderbuffer *rb = att->Renderbuffer;
+
+ if (rb && rb->NeedsFinishRenderTexture)
+ ctx->Driver.FinishRenderTexture(ctx, rb);
+
if (att->Texture == texObj) {
/* re-attaching same texture */
ASSERT(att->Type == GL_TEXTURE);
- if (ctx->Driver.FinishRenderTexture)
- ctx->Driver.FinishRenderTexture(ctx, att);
}
else {
/* new attachment */
- if (ctx->Driver.FinishRenderTexture && att->Texture)
- ctx->Driver.FinishRenderTexture(ctx, att);
- _mesa_remove_attachment(ctx, att);
+ remove_attachment(ctx, att);
att->Type = GL_TEXTURE;
assert(!att->Texture);
_mesa_reference_texobj(&att->Texture, texObj);
* Bind a renderbuffer to an attachment point.
* The previous binding, if any, will be removed first.
*/
-void
-_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
- struct gl_renderbuffer_attachment *att,
- struct gl_renderbuffer *rb)
+static void
+set_renderbuffer_attachment(struct gl_context *ctx,
+ struct gl_renderbuffer_attachment *att,
+ struct gl_renderbuffer *rb)
{
/* XXX check if re-doing same attachment, exit early */
- _mesa_remove_attachment(ctx, att);
+ remove_attachment(ctx, att);
att->Type = GL_RENDERBUFFER_EXT;
att->Texture = NULL; /* just to be safe */
att->Complete = GL_FALSE;
_glthread_LOCK_MUTEX(fb->Mutex);
- att = _mesa_get_attachment(ctx, fb, attachment);
+ att = get_attachment(ctx, fb, attachment);
ASSERT(att);
if (rb) {
- _mesa_set_renderbuffer_attachment(ctx, att, rb);
+ set_renderbuffer_attachment(ctx, att, rb);
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
/* do stencil attachment here (depth already done above) */
- att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
+ att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
assert(att);
- _mesa_set_renderbuffer_attachment(ctx, att, rb);
+ set_renderbuffer_attachment(ctx, att, rb);
}
rb->AttachedAnytime = GL_TRUE;
}
else {
- _mesa_remove_attachment(ctx, att);
+ remove_attachment(ctx, att);
}
invalidate_framebuffer(fb);
default:
switch (rb->Format) {
/* XXX This list is likely incomplete. */
- case MESA_FORMAT_RGB9_E5_FLOAT:
+ case MESA_FORMAT_R9G9B9E5_FLOAT:
fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
return;
default:;
* For debug only.
*/
static void
-fbo_incomplete(const char *msg, int index)
+fbo_incomplete(struct gl_context *ctx, const char *msg, int index)
{
+ static GLuint msg_id;
+
+ _mesa_gl_debug(ctx, &msg_id,
+ MESA_DEBUG_TYPE_OTHER,
+ MESA_DEBUG_SEVERITY_MEDIUM,
+ "FBO incomplete: %s [%d]\n", msg, index);
+
if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
_mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
}
* Is the given base format a legal format for a color renderbuffer?
*/
static GLboolean
-is_format_color_renderable(const struct gl_context *ctx, gl_format format, GLenum internalFormat)
+is_format_color_renderable(const struct gl_context *ctx, mesa_format format, GLenum internalFormat)
{
const GLenum baseFormat =
_mesa_get_format_base_format(format);
break;
}
- if (format == MESA_FORMAT_ARGB2101010 && internalFormat != GL_RGB10_A2) {
+ if (format == MESA_FORMAT_B10G10R10A2_UNORM && internalFormat != GL_RGB10_A2) {
return GL_FALSE;
}
}
if (texImage->Width < 1 || texImage->Height < 1) {
att_incomplete("teximage width/height=0");
- printf("texobj = %u\n", texObj->Name);
- printf("level = %d\n", att->TextureLevel);
att->Complete = GL_FALSE;
return;
}
- if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
- att_incomplete("bad z offset");
- att->Complete = GL_FALSE;
- return;
+
+ switch (texObj->Target) {
+ case GL_TEXTURE_3D:
+ if (att->Zoffset >= texImage->Depth) {
+ att_incomplete("bad z offset");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
+ case GL_TEXTURE_1D_ARRAY:
+ if (att->Zoffset >= texImage->Height) {
+ att_incomplete("bad 1D-array layer");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ if (att->Zoffset >= texImage->Depth) {
+ att_incomplete("bad 2D-array layer");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ if (att->Zoffset >= texImage->Depth) {
+ att_incomplete("bad cube-array layer");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
}
baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
if (baseFormat == GL_DEPTH_COMPONENT) {
/* OK */
}
- else if (ctx->Extensions.EXT_packed_depth_stencil &&
- ctx->Extensions.ARB_depth_texture &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
+ else if (ctx->Extensions.ARB_depth_texture &&
+ baseFormat == GL_DEPTH_STENCIL) {
/* OK */
}
else {
}
else {
ASSERT(format == GL_STENCIL);
- if (ctx->Extensions.EXT_packed_depth_stencil &&
- ctx->Extensions.ARB_depth_texture &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
+ if (ctx->Extensions.ARB_depth_texture &&
+ baseFormat == GL_DEPTH_STENCIL) {
/* OK */
}
else {
if (baseFormat == GL_DEPTH_COMPONENT) {
/* OK */
}
- else if (ctx->Extensions.EXT_packed_depth_stencil &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
+ else if (baseFormat == GL_DEPTH_STENCIL) {
/* OK */
}
else {
}
else {
assert(format == GL_STENCIL);
- if (baseFormat == GL_STENCIL_INDEX) {
- /* OK */
- }
- else if (ctx->Extensions.EXT_packed_depth_stencil &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
+ if (baseFormat == GL_STENCIL_INDEX ||
+ baseFormat == GL_DEPTH_STENCIL) {
/* OK */
}
else {
GLint fixedSampleLocations = -1;
GLint i;
GLuint j;
- bool layer_count_valid = false;
- GLuint layer_count = 0, att_layer_count;
+ /* Covers max_layer_count, is_layered, and layer_tex_target */
+ bool layer_info_valid = false;
+ GLuint max_layer_count = 0, att_layer_count;
+ bool is_layered = false;
+ GLenum layer_tex_target = 0;
assert(_mesa_is_user_fbo(fb));
for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
struct gl_renderbuffer_attachment *att;
GLenum f;
- gl_format attFormat;
+ mesa_format attFormat;
+ GLenum att_tex_target = GL_NONE;
/*
* XXX for ARB_fbo, only check color buffers that are named by
test_attachment_completeness(ctx, GL_DEPTH, att);
if (!att->Complete) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
- fbo_incomplete("depth attachment incomplete", -1);
+ fbo_incomplete(ctx, "depth attachment incomplete", -1);
return;
}
}
test_attachment_completeness(ctx, GL_STENCIL, att);
if (!att->Complete) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
- fbo_incomplete("stencil attachment incomplete", -1);
+ fbo_incomplete(ctx, "stencil attachment incomplete", -1);
return;
}
}
test_attachment_completeness(ctx, GL_COLOR, att);
if (!att->Complete) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
- fbo_incomplete("color attachment incomplete", i);
+ fbo_incomplete(ctx, "color attachment incomplete", i);
return;
}
}
/* get width, height, format of the renderbuffer/texture
*/
if (att->Type == GL_TEXTURE) {
- const struct gl_texture_image *texImg =
- _mesa_get_attachment_teximage(att);
+ const struct gl_texture_image *texImg = att->Renderbuffer->TexImage;
+ att_tex_target = att->Texture->Target;
minWidth = MIN2(minWidth, texImg->Width);
maxWidth = MAX2(maxWidth, texImg->Width);
minHeight = MIN2(minHeight, texImg->Height);
if (!is_format_color_renderable(ctx, attFormat, texImg->InternalFormat) &&
!is_legal_depth_format(ctx, f)) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
- fbo_incomplete("texture attachment incomplete", -1);
+ fbo_incomplete(ctx, "texture attachment incomplete", -1);
return;
}
numSamples = texImg->NumSamples;
else if (numSamples != texImg->NumSamples) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- fbo_incomplete("inconsistent sample count", -1);
+ fbo_incomplete(ctx, "inconsistent sample count", -1);
return;
}
fixedSampleLocations = texImg->FixedSampleLocations;
else if (fixedSampleLocations != texImg->FixedSampleLocations) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- fbo_incomplete("inconsistent fixed sample locations", -1);
+ fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
return;
}
}
numSamples = att->Renderbuffer->NumSamples;
else if (numSamples != att->Renderbuffer->NumSamples) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- fbo_incomplete("inconsistent sample count", -1);
+ fbo_incomplete(ctx, "inconsistent sample count", -1);
return;
}
fixedSampleLocations = GL_TRUE;
else if (fixedSampleLocations != GL_TRUE) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- fbo_incomplete("inconsistent fixed sample locations", -1);
+ fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
return;
}
}
/* check that width, height, format are same */
if (minWidth != maxWidth || minHeight != maxHeight) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
- fbo_incomplete("width or height mismatch", -1);
+ fbo_incomplete(ctx, "width or height mismatch", -1);
return;
}
/* check that all color buffers are the same format */
if (intFormat != GL_NONE && f != intFormat) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
- fbo_incomplete("format mismatch", -1);
+ fbo_incomplete(ctx, "format mismatch", -1);
return;
}
}
if (att->Type == GL_RENDERBUFFER &&
att->Renderbuffer->Format == MESA_FORMAT_NONE) {
fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
- fbo_incomplete("unsupported renderbuffer format", i);
+ fbo_incomplete(ctx, "unsupported renderbuffer format", i);
return;
}
/* Check that layered rendering is consistent. */
- att_layer_count = att->Layered ? att->Renderbuffer->Depth : 0;
- if (!layer_count_valid) {
- layer_count = att_layer_count;
- layer_count_valid = true;
- } else if (layer_count != att_layer_count) {
- if (layer_count == 0 || att_layer_count == 0) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
- fbo_incomplete("framebuffer attachment layer mode is inconsistent", i);
- } else {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB;
- fbo_incomplete("framebuffer attachment layer count is inconsistent", i);
- }
+ if (att->Layered) {
+ if (att_tex_target == GL_TEXTURE_CUBE_MAP)
+ att_layer_count = 6;
+ else
+ att_layer_count = att->Renderbuffer->Depth;
+ } else {
+ att_layer_count = 0;
+ }
+ if (!layer_info_valid) {
+ is_layered = att->Layered;
+ max_layer_count = att_layer_count;
+ layer_tex_target = att_tex_target;
+ layer_info_valid = true;
+ } else if (max_layer_count > 0 && layer_tex_target != att_tex_target) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
+ fbo_incomplete(ctx, "layered framebuffer has mismatched targets", i);
+ return;
+ } else if (is_layered != att->Layered) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
+ fbo_incomplete(ctx, "framebuffer attachment layer mode is inconsistent", i);
return;
+ } else if (att_layer_count > max_layer_count) {
+ max_layer_count = att_layer_count;
}
}
- fb->Layered = layer_count > 0;
+ fb->MaxNumLayers = max_layer_count;
if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) {
/* 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]);
+ = 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);
+ fbo_incomplete(ctx, "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);
+ = 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);
+ fbo_incomplete(ctx, "missing readbuffer", -1);
return;
}
}
if (numImages == 0) {
fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
- fbo_incomplete("no attachments", -1);
+ fbo_incomplete(ctx, "no attachments", -1);
return;
}
if (ctx->Driver.ValidateFramebuffer) {
ctx->Driver.ValidateFramebuffer(ctx, fb);
if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- fbo_incomplete("driver marked FBO as incomplete", -1);
+ fbo_incomplete(ctx, "driver marked FBO as incomplete", -1);
}
}
}
-void GLAPIENTRY
-_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
+static void
+bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names)
{
struct gl_renderbuffer *newRb;
GET_CURRENT_CONTEXT(ctx);
/* ID was reserved, but no real renderbuffer object made yet */
newRb = NULL;
}
- else if (!newRb
- && _mesa_is_desktop_gl(ctx)
- && ctx->Extensions.ARB_framebuffer_object) {
+ else if (!newRb && !allow_user_names) {
/* All RB IDs must be Gen'd */
_mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
return;
_mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
}
+void GLAPIENTRY
+_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same
+ * entry point, but they allow the use of user-generated names.
+ */
+ bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx));
+}
+
+void GLAPIENTRY
+_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
+{
+ /* This function should not be in the dispatch table for core profile /
+ * OpenGL 3.1, so execution should never get here in those cases -- no
+ * need for an explicit test.
+ */
+ bind_renderbuffer(target, renderbuffer, true);
+}
+
/**
- * If the given renderbuffer is anywhere attached to the framebuffer, detach
- * the renderbuffer.
- * This is used when a renderbuffer object is deleted.
- * The spec calls for unbinding.
+ * Remove the specified renderbuffer or texture from any attachment point in
+ * the framebuffer.
+ *
+ * \returns
+ * \c true if the renderbuffer was detached from an attachment point. \c
+ * false otherwise.
*/
-static void
-detach_renderbuffer(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- struct gl_renderbuffer *rb)
+bool
+_mesa_detach_renderbuffer(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ const void *att)
{
- GLuint i;
+ unsigned i;
+ bool progress = false;
+
for (i = 0; i < BUFFER_COUNT; i++) {
- if (fb->Attachment[i].Renderbuffer == rb) {
- _mesa_remove_attachment(ctx, &fb->Attachment[i]);
+ if (fb->Attachment[i].Texture == att
+ || fb->Attachment[i].Renderbuffer == att) {
+ remove_attachment(ctx, &fb->Attachment[i]);
+ progress = true;
}
}
- invalidate_framebuffer(fb);
+
+ /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer
+ * Completeness," of the OpenGL 3.1 spec says:
+ *
+ * "Performing any of the following actions may change whether the
+ * framebuffer is considered complete or incomplete:
+ *
+ * ...
+ *
+ * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object
+ * containing an image that is attached to a framebuffer object
+ * that is bound to the framebuffer."
+ */
+ if (progress)
+ invalidate_framebuffer(fb);
+
+ return progress;
}
_mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
}
+ /* Section 4.4.2 (Attaching Images to Framebuffer Objects),
+ * subsection "Attaching Renderbuffer Images to a Framebuffer," of
+ * the OpenGL 3.1 spec says:
+ *
+ * "If a renderbuffer object is deleted while its image is
+ * attached to one or more attachment points in the currently
+ * bound framebuffer, then it is as if FramebufferRenderbuffer
+ * had been called, with a renderbuffer of 0, for each
+ * attachment point to which this image was attached in the
+ * currently bound framebuffer. In other words, this
+ * renderbuffer image is first detached from all attachment
+ * points in the currently bound framebuffer. Note that the
+ * renderbuffer image is specifically not detached from any
+ * non-bound framebuffers. Detaching the image from any
+ * non-bound framebuffers is the responsibility of the
+ * application.
+ */
if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
- detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
+ _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
}
if (_mesa_is_user_fbo(ctx->ReadBuffer)
&& ctx->ReadBuffer != ctx->DrawBuffer) {
- detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
+ _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
}
/* Remove from hash table immediately, to free the ID.
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
return GL_DEPTH_COMPONENT;
- case GL_DEPTH_STENCIL_EXT:
- return _mesa_is_desktop_gl(ctx)
- && ctx->Extensions.EXT_packed_depth_stencil
- ? GL_DEPTH_STENCIL_EXT : 0;
- case GL_DEPTH24_STENCIL8_EXT:
- return ctx->Extensions.EXT_packed_depth_stencil
- ? GL_DEPTH_STENCIL_EXT : 0;
+ case GL_DEPTH_STENCIL:
+ return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_STENCIL : 0;
+ case GL_DEPTH24_STENCIL8:
+ return GL_DEPTH_STENCIL;
case GL_DEPTH_COMPONENT32F:
return ctx->Version >= 30
|| (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_depth_buffer_float)
return ctx->API == API_OPENGL_COMPAT &&
ctx->Extensions.EXT_texture_snorm &&
ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
+ case GL_LUMINANCE_SNORM:
+ case GL_LUMINANCE8_SNORM:
+ case GL_LUMINANCE16_SNORM:
+ return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
+ ? GL_LUMINANCE : 0;
+ case GL_LUMINANCE_ALPHA_SNORM:
+ case GL_LUMINANCE8_ALPHA8_SNORM:
+ case GL_LUMINANCE16_ALPHA16_SNORM:
+ return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
+ ? GL_LUMINANCE_ALPHA : 0;
+ case GL_INTENSITY_SNORM:
+ case GL_INTENSITY8_SNORM:
+ case GL_INTENSITY16_SNORM:
+ return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
+ ? GL_INTENSITY : 0;
+
case GL_R16F:
case GL_R32F:
return ((_mesa_is_desktop_gl(ctx) &&
* we need to return zero.
*/
static GLint
-get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
+get_component_bits(GLenum pname, GLenum baseFormat, mesa_format format)
{
if (_mesa_base_format_has_channel(baseFormat, pname))
return _mesa_get_format_bits(format, pname);
for (i = 0; i < BUFFER_COUNT; i++) {
struct gl_renderbuffer_attachment *att = fb->Attachment + i;
- if (att->Texture && _mesa_get_attachment_teximage(att)) {
+ if (att->Texture && att->Renderbuffer->TexImage
+ && driver_RenderTexture_is_safe(att)) {
ctx->Driver.RenderTexture(ctx, fb, att);
}
}
GLuint i;
for (i = 0; i < BUFFER_COUNT; i++) {
struct gl_renderbuffer_attachment *att = fb->Attachment + i;
- if (att->Texture && att->Renderbuffer) {
- ctx->Driver.FinishRenderTexture(ctx, att);
+ struct gl_renderbuffer *rb = att->Renderbuffer;
+ if (rb && rb->NeedsFinishRenderTexture) {
+ ctx->Driver.FinishRenderTexture(ctx, rb);
}
}
}
}
-void GLAPIENTRY
-_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
+static void
+bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names)
{
struct gl_framebuffer *newDrawFb, *newReadFb;
struct gl_framebuffer *oldDrawFb, *oldReadFb;
GLboolean bindReadBuf, bindDrawBuf;
GET_CURRENT_CONTEXT(ctx);
-#ifdef DEBUG
- if (ctx->Extensions.ARB_framebuffer_object) {
- ASSERT(ctx->Extensions.EXT_framebuffer_object);
- ASSERT(ctx->Extensions.EXT_framebuffer_blit);
- }
-#endif
-
- if (!ctx->Extensions.EXT_framebuffer_object) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindFramebufferEXT(unsupported)");
- return;
- }
-
switch (target) {
case GL_DRAW_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
- return;
- }
bindDrawBuf = GL_TRUE;
bindReadBuf = GL_FALSE;
break;
case GL_READ_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
- return;
- }
bindDrawBuf = GL_FALSE;
bindReadBuf = GL_TRUE;
break;
/* ID was reserved, but no real framebuffer object made yet */
newDrawFb = NULL;
}
- else if (!newDrawFb
- && _mesa_is_desktop_gl(ctx)
- && ctx->Extensions.ARB_framebuffer_object) {
+ else if (!newDrawFb && !allow_user_names) {
/* All FBO IDs must be Gen'd */
_mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
return;
}
}
+void GLAPIENTRY
+_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry
+ * point, but they allow the use of user-generated names.
+ */
+ bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx));
+}
+
+void GLAPIENTRY
+_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
+{
+ /* This function should not be in the dispatch table for core profile /
+ * OpenGL 3.1, so execution should never get here in those cases -- no
+ * need for an explicit test.
+ */
+ bind_framebuffer(target, framebuffer, true);
+}
void GLAPIENTRY
_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
/* check if deleting currently bound framebuffer object */
- if (ctx->Extensions.EXT_framebuffer_blit) {
- /* separate draw/read binding points */
- if (fb == ctx->DrawBuffer) {
- /* bind default */
- ASSERT(fb->RefCount >= 2);
- _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
- }
- if (fb == ctx->ReadBuffer) {
- /* bind default */
- ASSERT(fb->RefCount >= 2);
- _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
- }
+ if (fb == ctx->DrawBuffer) {
+ /* bind default */
+ ASSERT(fb->RefCount >= 2);
+ _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
- else {
- /* only one binding point for read/draw buffers */
- if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
- /* bind default */
- ASSERT(fb->RefCount >= 2);
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
- }
+ if (fb == ctx->ReadBuffer) {
+ /* bind default */
+ ASSERT(fb->RefCount >= 2);
+ _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
/* remove from hash table immediately, to free the ID */
}
if (_mesa_is_winsys_fbo(buffer)) {
- /* The window system / default framebuffer is always complete */
- return GL_FRAMEBUFFER_COMPLETE_EXT;
+ /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */
+ if (buffer != &IncompleteFramebuffer) {
+ return GL_FRAMEBUFFER_COMPLETE_EXT;
+ } else {
+ return GL_FRAMEBUFFER_UNDEFINED;
+ }
}
/* No need to flush here */
/**
* Common code called by glFramebufferTexture1D/2D/3DEXT() and
* glFramebufferTextureLayerEXT().
- * Note: glFramebufferTextureLayerEXT() has no textarget parameter so we'll
- * get textarget=0 in that case.
+ *
+ * \param textarget is the textarget that was passed to the
+ * glFramebufferTexture...() function, or 0 if the corresponding function
+ * doesn't have a textarget parameter.
+ *
+ * \param layered is true if this function was called from
+ * glFramebufferTexture(), false otherwise.
*/
static void
framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
texObj = _mesa_lookup_texture(ctx, texture);
if (texObj != NULL) {
if (textarget == 0) {
- /* If textarget == 0 it means we're being called by
- * glFramebufferTextureLayer() and textarget is not used.
- * The only legal texture types for that function are 3D and
- * 1D/2D arrays textures.
- */
- err = (texObj->Target != GL_TEXTURE_3D) &&
- (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
- (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) &&
- (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) &&
- (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
+ if (layered) {
+ /* We're being called by glFramebufferTexture() and textarget
+ * is not used.
+ */
+ switch (texObj->Target) {
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_1D_ARRAY_EXT:
+ case GL_TEXTURE_2D_ARRAY_EXT:
+ case GL_TEXTURE_CUBE_MAP:
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ err = false;
+ break;
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_RECTANGLE:
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ /* These texture types are valid to pass to
+ * glFramebufferTexture(), but since they aren't layered, it
+ * is equivalent to calling glFramebufferTexture{1D,2D}().
+ */
+ err = false;
+ layered = false;
+ textarget = texObj->Target;
+ break;
+ default:
+ err = true;
+ break;
+ }
+ } else {
+ /* We're being called by glFramebufferTextureLayer() and
+ * textarget is not used. The only legal texture types for
+ * that function are 3D and 1D/2D arrays textures.
+ */
+ err = (texObj->Target != GL_TEXTURE_3D) &&
+ (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
+ (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) &&
+ (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) &&
+ (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
+ }
}
else {
/* Make sure textarget is consistent with the texture's type */
}
}
- att = _mesa_get_attachment(ctx, fb, attachment);
+ att = get_attachment(ctx, fb, attachment);
if (att == NULL) {
_mesa_error(ctx, GL_INVALID_ENUM,
"glFramebufferTexture%sEXT(attachment)", caller);
reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
BUFFER_DEPTH);
} else {
- _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
+ set_texture_attachment(ctx, fb, att, texObj, textarget,
level, zoffset, layered);
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
/* Above we created a new renderbuffer and attached it to the
texObj->_RenderToTexture = GL_TRUE;
}
else {
- _mesa_remove_attachment(ctx, att);
+ remove_attachment(ctx, att);
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
assert(att == &fb->Attachment[BUFFER_DEPTH]);
- _mesa_remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
+ remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
}
}
{
GET_CURRENT_CONTEXT(ctx);
- if (ctx->Version >= 32 || ctx->Extensions.ARB_geometry_shader4) {
+ if (_mesa_has_geometry_shaders(ctx)) {
framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
level, 0, GL_TRUE);
} else {
return;
}
- att = _mesa_get_attachment(ctx, fb, attachment);
+ att = get_attachment(ctx, fb, attachment);
if (att == NULL) {
_mesa_error(ctx, GL_INVALID_ENUM,
"glFramebufferRenderbufferEXT(invalid attachment %s)",
}
else {
/* user-created framebuffer FBO */
- att = _mesa_get_attachment(ctx, buffer, attachment);
+ att = get_attachment(ctx, buffer, attachment);
}
if (att == NULL) {
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
/* the depth and stencil attachments must point to the same buffer */
const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
- depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
- stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
+ depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
+ stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
- gl_format format = att->Renderbuffer->Format;
+ mesa_format format = att->Renderbuffer->Format;
/* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES
* 3.0.1 spec says:
return;
}
- if (format == MESA_FORMAT_S8) {
+ if (format == MESA_FORMAT_S_UINT8) {
/* special cases */
*params = GL_INDEX;
}
- else if (format == MESA_FORMAT_Z32_FLOAT_X24S8) {
+ else if (format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) {
/* depends on the attachment parameter */
if (attachment == GL_STENCIL_ATTACHMENT) {
*params = GL_INDEX;
" invalid FBO attachment structure");
}
return;
+ case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
+ if (!_mesa_has_geometry_shaders(ctx)) {
+ goto invalid_pname_enum;
+ } else if (att->Type == GL_TEXTURE) {
+ *params = att->Layered;
+ } else if (att->Type == GL_NONE) {
+ _mesa_error(ctx, err,
+ "glGetFramebufferAttachmentParameteriv(pname)");
+ } else {
+ goto invalid_pname_enum;
+ }
+ return;
default:
goto invalid_pname_enum;
}
}
-void GLAPIENTRY
-_mesa_GenerateMipmap(GLenum target)
-{
- struct gl_texture_image *srcImage;
- struct gl_texture_object *texObj;
- GLboolean error;
-
- GET_CURRENT_CONTEXT(ctx);
-
- FLUSH_VERTICES(ctx, 0);
-
- switch (target) {
- case GL_TEXTURE_1D:
- error = _mesa_is_gles(ctx);
- break;
- case GL_TEXTURE_2D:
- error = GL_FALSE;
- break;
- case GL_TEXTURE_3D:
- error = ctx->API == API_OPENGLES;
- break;
- case GL_TEXTURE_CUBE_MAP:
- error = !ctx->Extensions.ARB_texture_cube_map;
- break;
- case GL_TEXTURE_1D_ARRAY:
- error = _mesa_is_gles(ctx) || !ctx->Extensions.EXT_texture_array;
- break;
- case GL_TEXTURE_2D_ARRAY:
- error = (_mesa_is_gles(ctx) && ctx->Version < 30)
- || !ctx->Extensions.EXT_texture_array;
- break;
- default:
- error = GL_TRUE;
- }
-
- if (error) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target=%s)",
- _mesa_lookup_enum_by_nr(target));
- return;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- if (texObj->BaseLevel >= texObj->MaxLevel) {
- /* nothing to do */
- return;
- }
-
- if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
- !_mesa_cube_complete(texObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGenerateMipmap(incomplete cube map)");
- return;
- }
-
- _mesa_lock_texture(ctx, texObj);
-
- srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel);
- if (!srcImage) {
- _mesa_unlock_texture(ctx, texObj);
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGenerateMipmap(zero size base image)");
- return;
- }
-
- if (_mesa_is_enum_format_integer(srcImage->InternalFormat) ||
- _mesa_is_depthstencil_format(srcImage->InternalFormat) ||
- _mesa_is_stencil_format(srcImage->InternalFormat)) {
- _mesa_unlock_texture(ctx, texObj);
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGenerateMipmap(invalid internal format)");
- return;
- }
-
- if (target == GL_TEXTURE_CUBE_MAP) {
- GLuint face;
- for (face = 0; face < 6; face++)
- ctx->Driver.GenerateMipmap(ctx,
- GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
- texObj);
- }
- else {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
- _mesa_unlock_texture(ctx, texObj);
-}
-
-
-static const struct gl_renderbuffer_attachment *
-find_attachment(const struct gl_framebuffer *fb,
- const struct gl_renderbuffer *rb)
-{
- GLuint i;
- for (i = 0; i < Elements(fb->Attachment); i++) {
- if (fb->Attachment[i].Renderbuffer == rb)
- return &fb->Attachment[i];
- }
- return NULL;
-}
-
-
-/**
- * Helper function for checking if the datatypes of color buffers are
- * compatible for glBlitFramebuffer. From the 3.1 spec, page 198:
- *
- * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
- * and any of the following conditions hold:
- * - The read buffer contains fixed-point or floating-point values and any
- * draw buffer contains neither fixed-point nor floating-point values.
- * - The read buffer contains unsigned integer values and any draw buffer
- * does not contain unsigned integer values.
- * - The read buffer contains signed integer values and any draw buffer
- * does not contain signed integer values."
- */
-static GLboolean
-compatible_color_datatypes(gl_format srcFormat, gl_format dstFormat)
-{
- GLenum srcType = _mesa_get_format_datatype(srcFormat);
- GLenum dstType = _mesa_get_format_datatype(dstFormat);
-
- if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
- assert(srcType == GL_UNSIGNED_NORMALIZED ||
- srcType == GL_SIGNED_NORMALIZED ||
- srcType == GL_FLOAT);
- /* Boil any of those types down to GL_FLOAT */
- srcType = GL_FLOAT;
- }
-
- if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
- assert(dstType == GL_UNSIGNED_NORMALIZED ||
- dstType == GL_SIGNED_NORMALIZED ||
- dstType == GL_FLOAT);
- /* Boil any of those types down to GL_FLOAT */
- dstType = GL_FLOAT;
- }
-
- return srcType == dstType;
-}
-
-
-static GLboolean
-compatible_resolve_formats(const struct gl_renderbuffer *readRb,
- const struct gl_renderbuffer *drawRb)
-{
- GLenum readFormat, drawFormat;
-
- /* The simple case where we know the backing Mesa formats are the same.
- */
- if (_mesa_get_srgb_format_linear(readRb->Format) ==
- _mesa_get_srgb_format_linear(drawRb->Format)) {
- return GL_TRUE;
- }
-
- /* The Mesa formats are different, so we must check whether the internal
- * formats are compatible.
- *
- * Under some circumstances, the user may request e.g. two GL_RGBA8
- * textures and get two entirely different Mesa formats like RGBA8888 and
- * ARGB8888. Drivers behaving like that should be able to cope with
- * non-matching formats by themselves, because it's not the user's fault.
- *
- * Blits between linear and sRGB formats are also allowed.
- */
- readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat);
- drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat);
- readFormat = _mesa_get_linear_internalformat(readFormat);
- drawFormat = _mesa_get_linear_internalformat(drawFormat);
-
- if (readFormat == drawFormat) {
- return GL_TRUE;
- }
-
- return GL_FALSE;
-}
-
-
-/**
- * Blit rectangular region, optionally from one framebuffer to another.
- *
- * Note, if the src buffer is multisampled and the dest is not, this is
- * when the samples must be resolved to a single color.
- */
-void GLAPIENTRY
-_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
- GLbitfield mask, GLenum filter)
-{
- const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
- GL_DEPTH_BUFFER_BIT |
- GL_STENCIL_BUFFER_BIT);
- const struct gl_framebuffer *readFb, *drawFb;
- GET_CURRENT_CONTEXT(ctx);
-
- FLUSH_VERTICES(ctx, 0);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx,
- "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
- srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1,
- mask, _mesa_lookup_enum_by_nr(filter));
-
- if (ctx->NewState) {
- _mesa_update_state(ctx);
- }
-
- readFb = ctx->ReadBuffer;
- drawFb = ctx->DrawBuffer;
-
- if (!readFb || !drawFb) {
- /* This will normally never happen but someday we may want to
- * support MakeCurrent() with no drawables.
- */
- return;
- }
-
- /* check for complete framebuffers */
- if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
- readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "glBlitFramebufferEXT(incomplete draw/read buffers)");
- return;
- }
-
- if (filter != GL_NEAREST && filter != GL_LINEAR) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
- return;
- }
-
- if (mask & ~legalMaskBits) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
- return;
- }
-
- /* depth/stencil must be blitted with nearest filtering */
- if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
- && filter != GL_NEAREST) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
- return;
- }
-
- /* get color read/draw renderbuffers */
- if (mask & GL_COLOR_BUFFER_BIT) {
- const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers;
- const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
- const struct gl_renderbuffer *colorDrawRb = NULL;
- GLuint i;
-
- /* From the EXT_framebuffer_object spec:
- *
- * "If a buffer is specified in <mask> and does not exist in both
- * the read and draw framebuffers, the corresponding bit is silently
- * ignored."
- */
- if (!colorReadRb || numColorDrawBuffers == 0) {
- mask &= ~GL_COLOR_BUFFER_BIT;
- }
- else {
- for (i = 0; i < numColorDrawBuffers; i++) {
- colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
- if (!colorDrawRb)
- continue;
-
- /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
- * ES 3.0.1 spec says:
- *
- * "If the source and destination buffers are identical, an
- * INVALID_OPERATION error is generated. Different mipmap
- * levels of a texture, different layers of a three-
- * dimensional texture or two-dimensional array texture, and
- * different faces of a cube map texture do not constitute
- * identical buffers."
- */
- if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebuffer(source and destination color "
- "buffer cannot be the same)");
- return;
- }
-
- if (!compatible_color_datatypes(colorReadRb->Format,
- colorDrawRb->Format)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(color buffer datatypes mismatch)");
- return;
- }
- /* extra checks for multisample copies... */
- if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
- /* color formats must match */
- if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
- return;
- }
- }
- }
- if (filter == GL_LINEAR) {
- /* 3.1 spec, page 199:
- * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
- * if filter is LINEAR and read buffer contains integer data."
- */
- GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
- if (type == GL_INT || type == GL_UNSIGNED_INT) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(integer color type)");
- return;
- }
- }
- }
- }
-
- if (mask & GL_STENCIL_BUFFER_BIT) {
- struct gl_renderbuffer *readRb =
- readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
- struct gl_renderbuffer *drawRb =
- drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
-
- /* From the EXT_framebuffer_object spec:
- *
- * "If a buffer is specified in <mask> and does not exist in both
- * the read and draw framebuffers, the corresponding bit is silently
- * ignored."
- */
- if ((readRb == NULL) || (drawRb == NULL)) {
- mask &= ~GL_STENCIL_BUFFER_BIT;
- }
- else {
- int read_z_bits, draw_z_bits;
-
- if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebuffer(source and destination stencil "
- "buffer cannot be the same)");
- return;
- }
-
- if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
- _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
- /* There is no need to check the stencil datatype here, because
- * there is only one: GL_UNSIGNED_INT.
- */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebuffer(stencil attachment format mismatch)");
- return;
- }
-
- read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
- draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
-
- /* If both buffers also have depth data, the depth formats must match
- * as well. If one doesn't have depth, it's not blitted, so we should
- * ignore the depth format check.
- */
- if (read_z_bits > 0 && draw_z_bits > 0 &&
- (read_z_bits != draw_z_bits ||
- _mesa_get_format_datatype(readRb->Format) !=
- _mesa_get_format_datatype(drawRb->Format))) {
-
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
- "(stencil attachment depth format mismatch)");
- return;
- }
- }
- }
-
- if (mask & GL_DEPTH_BUFFER_BIT) {
- struct gl_renderbuffer *readRb =
- readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
- struct gl_renderbuffer *drawRb =
- drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
-
- /* From the EXT_framebuffer_object spec:
- *
- * "If a buffer is specified in <mask> and does not exist in both
- * the read and draw framebuffers, the corresponding bit is silently
- * ignored."
- */
- if ((readRb == NULL) || (drawRb == NULL)) {
- mask &= ~GL_DEPTH_BUFFER_BIT;
- }
- else {
- int read_s_bit, draw_s_bit;
-
- if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebuffer(source and destination depth "
- "buffer cannot be the same)");
- return;
- }
-
- if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
- _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
- (_mesa_get_format_datatype(readRb->Format) !=
- _mesa_get_format_datatype(drawRb->Format))) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebuffer(depth attachment format mismatch)");
- return;
- }
-
- read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
- draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
-
- /* If both buffers also have stencil data, the stencil formats must
- * match as well. If one doesn't have stencil, it's not blitted, so
- * we should ignore the stencil format check.
- */
- if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
- "(depth attachment stencil bits mismatch)");
- return;
- }
- }
- }
-
-
- if (_mesa_is_gles3(ctx)) {
- /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
- * 3.0.1 spec says:
- *
- * "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
- * an INVALID_OPERATION error is generated."
- */
- if (drawFb->Visual.samples > 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebuffer(destination samples must be 0)");
- return;
- }
-
- /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
- * 3.0.1 spec says:
- *
- * "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
- * no copy is performed and an INVALID_OPERATION error is generated
- * if the formats of the read and draw framebuffers are not
- * identical or if the source and destination rectangles are not
- * defined with the same (X0, Y0) and (X1, Y1) bounds."
- *
- * The format check was made above because desktop OpenGL has the same
- * requirement.
- */
- if (readFb->Visual.samples > 0
- && (srcX0 != dstX0 || srcY0 != dstY0
- || srcX1 != dstX1 || srcY1 != dstY1)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebuffer(bad src/dst multisample region)");
- return;
- }
- } else {
- if (readFb->Visual.samples > 0 &&
- drawFb->Visual.samples > 0 &&
- readFb->Visual.samples != drawFb->Visual.samples) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(mismatched samples)");
- return;
- }
-
- /* extra checks for multisample copies... */
- if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
- /* src and dest region sizes must be the same */
- if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
- abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(bad src/dst multisample region sizes)");
- return;
- }
- }
- }
-
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
- return;
- }
-
- /* Debug code */
- if (DEBUG_BLIT) {
- const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
- const struct gl_renderbuffer *colorDrawRb = NULL;
- GLuint i = 0;
-
- printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
- " 0x%x, 0x%x)\n",
- srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1,
- mask, filter);
- if (colorReadRb) {
- const struct gl_renderbuffer_attachment *att;
-
- att = find_attachment(readFb, colorReadRb);
- printf(" Src FBO %u RB %u (%dx%d) ",
- readFb->Name, colorReadRb->Name,
- colorReadRb->Width, colorReadRb->Height);
- if (att && att->Texture) {
- printf("Tex %u tgt 0x%x level %u face %u",
- att->Texture->Name,
- att->Texture->Target,
- att->TextureLevel,
- att->CubeMapFace);
- }
- printf("\n");
-
- /* Print all active color render buffers */
- for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
- colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
- if (!colorDrawRb)
- continue;
-
- att = find_attachment(drawFb, colorDrawRb);
- printf(" Dst FBO %u RB %u (%dx%d) ",
- drawFb->Name, colorDrawRb->Name,
- colorDrawRb->Width, colorDrawRb->Height);
- if (att && att->Texture) {
- printf("Tex %u tgt 0x%x level %u face %u",
- att->Texture->Name,
- att->Texture->Target,
- att->TextureLevel,
- att->CubeMapFace);
- }
- printf("\n");
- }
- }
- }
-
- if (!mask ||
- (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
- (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
- return;
- }
-
- ASSERT(ctx->Driver.BlitFramebuffer);
- ctx->Driver.BlitFramebuffer(ctx,
- srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1,
- mask, filter);
-}
-
-
static void
invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments,
const GLenum *attachments, GLint x, GLint y,
"%s(attachment >= max. color attachments)", name);
return;
}
+ break;
}
default:
goto invalid_enum;