}
+/**
+ * A convenience function for direct state access that throws
+ * GL_INVALID_OPERATION if the renderbuffer doesn't exist.
+ */
+struct gl_renderbuffer *
+_mesa_lookup_renderbuffer_err(struct gl_context *ctx, GLuint id,
+ const char *func)
+{
+ struct gl_renderbuffer *rb;
+
+ rb = _mesa_lookup_renderbuffer(ctx, id);
+ if (!rb || rb == &DummyRenderbuffer) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(non-existent renderbuffer %u)", func, id);
+ return NULL;
+ }
+
+ return rb;
+}
+
+
/**
* Helper routine for getting a gl_framebuffer.
*/
}
+/**
+ * A convenience function for direct state access that throws
+ * GL_INVALID_OPERATION if the framebuffer doesn't exist.
+ */
+struct gl_framebuffer *
+_mesa_lookup_framebuffer_err(struct gl_context *ctx, GLuint id,
+ const char *func)
+{
+ struct gl_framebuffer *fb;
+
+ fb = _mesa_lookup_framebuffer(ctx, id);
+ if (!fb || fb == &DummyFramebuffer) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(non-existent framebuffer %u)", func, id);
+ return NULL;
+ }
+
+ return fb;
+}
+
+
/**
* Mark the given framebuffer as invalid. This will force the
* test for framebuffer completeness to be done before the framebuffer
const struct gl_texture_image *const texImage =
att->Texture->Image[att->CubeMapFace][att->TextureLevel];
- if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
+ if (!texImage ||
+ texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
return false;
if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY
struct gl_framebuffer *fb,
struct gl_renderbuffer_attachment *att,
struct gl_texture_object *texObj,
- GLenum texTarget, GLuint level, GLuint zoffset,
+ GLenum texTarget, GLuint level, GLuint layer,
GLboolean layered)
{
struct gl_renderbuffer *rb = att->Renderbuffer;
/* always update these fields */
att->TextureLevel = level;
att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
- att->Zoffset = zoffset;
+ att->Zoffset = layer;
att->Layered = layered;
att->Complete = GL_FALSE;
* Attach a renderbuffer object to a framebuffer object.
*/
void
-_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- GLenum attachment, struct gl_renderbuffer *rb)
+_mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ GLenum attachment,
+ struct gl_renderbuffer *rb)
{
struct gl_renderbuffer_attachment *att;
break;
}
- baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
+ baseFormat = texImage->_BaseFormat;
if (format == GL_COLOR) {
if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
}
}
else if (att->Type == GL_RENDERBUFFER_EXT) {
- const GLenum baseFormat =
- _mesa_get_format_base_format(att->Renderbuffer->Format);
+ const GLenum baseFormat = att->Renderbuffer->_BaseFormat;
assert(att->Renderbuffer);
if (!att->Renderbuffer->InternalFormat ||
fb->Height = 0;
fb->_AllColorBuffersFixedPoint = GL_TRUE;
fb->_HasSNormOrFloatColorBuffer = GL_FALSE;
+ fb->_HasAttachments = true;
/* Start at -2 to more easily loop over all attachment points.
* -2: depth buffer
} else if (att_layer_count > max_layer_count) {
max_layer_count = att_layer_count;
}
+
+ /*
+ * The extension GL_ARB_framebuffer_no_attachments places additional
+ * requirement on each attachment. Those additional requirements are
+ * tighter that those of previous versions of GL. In interest of better
+ * compatibility, we will not enforce these restrictions. For the record
+ * those additional restrictions are quoted below:
+ *
+ * "The width and height of image are greater than zero and less than or
+ * equal to the values of the implementation-dependent limits
+ * MAX_FRAMEBUFFER_WIDTH and MAX_FRAMEBUFFER_HEIGHT, respectively."
+ *
+ * "If <image> is a three-dimensional texture or a one- or two-dimensional
+ * array texture and the attachment is layered, the depth or layer count
+ * of the texture is less than or equal to the implementation-dependent
+ * limit MAX_FRAMEBUFFER_LAYERS."
+ *
+ * "If image has multiple samples, its sample count is less than or equal
+ * to the value of the implementation-dependent limit
+ * MAX_FRAMEBUFFER_SAMPLES."
+ *
+ * The same requirements are also in place for GL 4.5,
+ * Section 9.4.1 "Framebuffer Attachment Completeness", pg 310-311
+ */
}
fb->MaxNumLayers = max_layer_count;
if (numImages == 0) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
- fbo_incomplete(ctx, "no attachments", -1);
- return;
+ fb->_HasAttachments = false;
+
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
+ fbo_incomplete(ctx, "no attachments", -1);
+ return;
+ }
+
+ if (fb->DefaultGeometry.Width == 0 || fb->DefaultGeometry.Height == 0) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
+ fbo_incomplete(ctx, "no attachments and default width or height is 0", -1);
+ return;
+ }
}
if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) {
ctx->Driver.ValidateFramebuffer(ctx, fb);
if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
fbo_incomplete(ctx, "driver marked FBO as incomplete", -1);
+ return;
}
}
- if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
- /*
- * Note that if ARB_framebuffer_object is supported and the attached
- * renderbuffers/textures are different sizes, the framebuffer
- * width/height will be set to the smallest width/height.
- */
+ /*
+ * Note that if ARB_framebuffer_object is supported and the attached
+ * renderbuffers/textures are different sizes, the framebuffer
+ * width/height will be set to the smallest width/height.
+ */
+ if (numImages != 0) {
fb->Width = minWidth;
fb->Height = minHeight;
-
- /* finally, update the visual info for the framebuffer */
- _mesa_update_framebuffer_visual(ctx, fb);
}
+
+ /* finally, update the visual info for the framebuffer */
+ _mesa_update_framebuffer_visual(ctx, fb);
}
static struct gl_renderbuffer *
-allocate_renderbuffer(struct gl_context *ctx, GLuint renderbuffer,
- const char *func)
+allocate_renderbuffer_locked(struct gl_context *ctx, GLuint renderbuffer,
+ const char *func)
{
struct gl_renderbuffer *newRb;
return NULL;
}
assert(newRb->AllocStorage);
- mtx_lock(&ctx->Shared->Mutex);
- _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
+ _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffer, newRb);
newRb->RefCount = 1; /* referenced by hash table */
- mtx_unlock(&ctx->Shared->Mutex);
return newRb;
}
}
if (!newRb) {
- newRb = allocate_renderbuffer(ctx, renderbuffer, "glBindRenderbufferEXT");
+ _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
+ newRb = allocate_renderbuffer_locked(ctx, renderbuffer,
+ "glBindRenderbufferEXT");
+ _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
}
}
else {
bind_renderbuffer(target, renderbuffer, true);
}
+/**
+ * ARB_framebuffer_no_attachment - Application passes requested param's
+ * here. NOTE: NumSamples requested need not be _NumSamples which is
+ * what the hw supports.
+ */
+static void
+framebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLenum pname, GLint param, const char *func)
+{
+ switch (pname) {
+ case GL_FRAMEBUFFER_DEFAULT_WIDTH:
+ if (param < 0 || param > ctx->Const.MaxFramebufferWidth)
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
+ else
+ fb->DefaultGeometry.Width = param;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
+ if (param < 0 || param > ctx->Const.MaxFramebufferHeight)
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
+ else
+ fb->DefaultGeometry.Height = param;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_LAYERS:
+ /*
+ * According to the OpenGL ES 3.1 specification section 9.2.1, the
+ * GL_FRAMEBUFFER_DEFAULT_LAYERS parameter name is not supported.
+ */
+ if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
+ break;
+ }
+ if (param < 0 || param > ctx->Const.MaxFramebufferLayers)
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
+ else
+ fb->DefaultGeometry.Layers = param;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
+ if (param < 0 || param > ctx->Const.MaxFramebufferSamples)
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
+ else
+ fb->DefaultGeometry.NumSamples = param;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
+ fb->DefaultGeometry.FixedSampleLocations = param;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(pname=0x%x)", func, pname);
+ }
+
+ invalidate_framebuffer(fb);
+ ctx->NewState |= _NEW_BUFFERS;
+}
+
+void GLAPIENTRY
+_mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferParameteriv not supported "
+ "(ARB_framebuffer_no_attachments not implemented)");
+ return;
+ }
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferParameteri(target=0x%x)", target);
+ return;
+ }
+
+ /* check framebuffer binding */
+ if (_mesa_is_winsys_fbo(fb)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferParameteri");
+ return;
+ }
+
+ framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri");
+}
+
+static void
+get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLenum pname, GLint *params, const char *func)
+{
+ switch (pname) {
+ case GL_FRAMEBUFFER_DEFAULT_WIDTH:
+ *params = fb->DefaultGeometry.Width;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
+ *params = fb->DefaultGeometry.Height;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_LAYERS:
+ /*
+ * According to the OpenGL ES 3.1 specification section 9.2.3, the
+ * GL_FRAMEBUFFER_LAYERS parameter name is not supported.
+ */
+ if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
+ break;
+ }
+ *params = fb->DefaultGeometry.Layers;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
+ *params = fb->DefaultGeometry.NumSamples;
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
+ *params = fb->DefaultGeometry.FixedSampleLocations;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(pname=0x%x)", func, pname);
+ }
+}
+
+void GLAPIENTRY
+_mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetFramebufferParameteriv not supported "
+ "(ARB_framebuffer_no_attachments not implemented)");
+ return;
+ }
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferParameteriv(target=0x%x)", target);
+ return;
+ }
+
+ /* check framebuffer binding */
+ if (_mesa_is_winsys_fbo(fb)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetFramebufferParameteriv");
+ return;
+ }
+
+ get_framebuffer_parameteriv(ctx, fb, pname, params,
+ "glGetFramebufferParameteriv");
+}
+
/**
* Remove the specified renderbuffer or texture from any attachment point in
if (!renderbuffers)
return;
+ _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
+
first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
for (i = 0; i < n; i++) {
renderbuffers[i] = name;
if (dsa) {
- allocate_renderbuffer(ctx, name, func);
+ allocate_renderbuffer_locked(ctx, name, func);
} else {
/* insert a dummy renderbuffer into the hash table */
- mtx_lock(&ctx->Shared->Mutex);
- _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
- mtx_unlock(&ctx->Shared->Mutex);
+ _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, name,
+ &DummyRenderbuffer);
}
}
+
+ _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
}
/** sentinal value, see below */
#define NO_SAMPLES 1000
+void
+_mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLsizei width,
+ GLsizei height, GLsizei samples)
+{
+ const GLenum baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
+
+ assert(baseFormat != 0);
+ assert(width >= 0 && width <= (GLsizei) ctx->Const.MaxRenderbufferSize);
+ assert(height >= 0 && height <= (GLsizei) ctx->Const.MaxRenderbufferSize);
+ assert(samples != NO_SAMPLES);
+ if (samples != 0) {
+ assert(samples > 0);
+ assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER,
+ internalFormat, samples) == GL_NO_ERROR);
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ if (rb->InternalFormat == internalFormat &&
+ rb->Width == (GLuint) width &&
+ rb->Height == (GLuint) height &&
+ rb->NumSamples == samples) {
+ /* no change in allocation needed */
+ return;
+ }
+
+ /* These MUST get set by the AllocStorage func */
+ rb->Format = MESA_FORMAT_NONE;
+ rb->NumSamples = samples;
+
+ /* Now allocate the storage */
+ assert(rb->AllocStorage);
+ if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
+ /* No error - check/set fields now */
+ /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */
+ assert(rb->Width == (GLuint) width);
+ assert(rb->Height == (GLuint) height);
+ rb->InternalFormat = internalFormat;
+ rb->_BaseFormat = baseFormat;
+ assert(rb->_BaseFormat != 0);
+ }
+ else {
+ /* Probably ran out of memory - clear the fields */
+ rb->Width = 0;
+ rb->Height = 0;
+ rb->Format = MESA_FORMAT_NONE;
+ rb->InternalFormat = GL_NONE;
+ rb->_BaseFormat = GL_NONE;
+ rb->NumSamples = 0;
+ }
+
+ /* Invalidate the framebuffers the renderbuffer is attached in. */
+ if (rb->AttachedAnytime) {
+ _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
+ }
+}
/**
* Helper function used by renderbuffer_storage_direct() and
baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
if (baseFormat == 0) {
_mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)",
- func, _mesa_lookup_enum_by_nr(internalFormat));
+ func, _mesa_enum_to_string(internalFormat));
return;
}
*/
sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER,
internalFormat, samples);
+
+ /* Section 2.5 (GL Errors) of OpenGL 3.0 specification, page 16:
+ *
+ * "If a negative number is provided where an argument of type sizei or
+ * sizeiptr is specified, the error INVALID VALUE is generated."
+ */
+ if (samples < 0) {
+ sample_count_error = GL_INVALID_VALUE;
+ }
+
if (sample_count_error != GL_NO_ERROR) {
- _mesa_error(ctx, sample_count_error, "%s(samples)", func);
+ _mesa_error(ctx, sample_count_error, "%s(samples=%d)", func, samples);
return;
}
}
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- if (rb->InternalFormat == internalFormat &&
- rb->Width == (GLuint) width &&
- rb->Height == (GLuint) height &&
- rb->NumSamples == samples) {
- /* no change in allocation needed */
- return;
- }
-
- /* These MUST get set by the AllocStorage func */
- rb->Format = MESA_FORMAT_NONE;
- rb->NumSamples = samples;
-
- /* Now allocate the storage */
- assert(rb->AllocStorage);
- if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
- /* No error - check/set fields now */
- /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */
- assert(rb->Width == (GLuint) width);
- assert(rb->Height == (GLuint) height);
- rb->InternalFormat = internalFormat;
- rb->_BaseFormat = baseFormat;
- assert(rb->_BaseFormat != 0);
- }
- else {
- /* Probably ran out of memory - clear the fields */
- rb->Width = 0;
- rb->Height = 0;
- rb->Format = MESA_FORMAT_NONE;
- rb->InternalFormat = GL_NONE;
- rb->_BaseFormat = GL_NONE;
- rb->NumSamples = 0;
- }
-
- /* Invalidate the framebuffers the renderbuffer is attached in. */
- if (rb->AttachedAnytime) {
- _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
- }
+ _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples);
}
/**
if (samples == NO_SAMPLES)
_mesa_debug(ctx, "%s(%u, %s, %d, %d)\n",
func, renderbuffer,
- _mesa_lookup_enum_by_nr(internalFormat),
+ _mesa_enum_to_string(internalFormat),
width, height);
else
_mesa_debug(ctx, "%s(%u, %s, %d, %d, %d)\n",
func, renderbuffer,
- _mesa_lookup_enum_by_nr(internalFormat),
+ _mesa_enum_to_string(internalFormat),
width, height, samples);
}
if (samples == NO_SAMPLES)
_mesa_debug(ctx, "%s(%s, %s, %d, %d)\n",
func,
- _mesa_lookup_enum_by_nr(target),
- _mesa_lookup_enum_by_nr(internalFormat),
+ _mesa_enum_to_string(target),
+ _mesa_enum_to_string(internalFormat),
width, height);
else
_mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n",
func,
- _mesa_lookup_enum_by_nr(target),
- _mesa_lookup_enum_by_nr(internalFormat),
+ _mesa_enum_to_string(target),
+ _mesa_enum_to_string(internalFormat),
width, height, samples);
}
/* fallthrough */
default:
_mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func,
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
return;
}
}
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);
newReadFb = ctx->WinSysReadBuffer;
}
- assert(newDrawFb);
- assert(newDrawFb != &DummyFramebuffer);
+ _mesa_bind_framebuffers(ctx,
+ bindDrawBuf ? newDrawFb : ctx->DrawBuffer,
+ bindReadBuf ? newReadFb : ctx->ReadBuffer);
+}
- /* save pointers to current/old framebuffers */
- oldDrawFb = ctx->DrawBuffer;
- oldReadFb = ctx->ReadBuffer;
+void
+_mesa_bind_framebuffers(struct gl_context *ctx,
+ struct gl_framebuffer *newDrawFb,
+ struct gl_framebuffer *newReadFb)
+{
+ struct gl_framebuffer *const oldDrawFb = ctx->DrawBuffer;
+ struct gl_framebuffer *const oldReadFb = ctx->ReadBuffer;
+ const bool bindDrawBuf = oldDrawFb != newDrawFb;
+ const bool bindReadBuf = oldReadFb != newReadFb;
- /* check if really changing bindings */
- if (oldDrawFb == newDrawFb)
- bindDrawBuf = GL_FALSE;
- if (oldReadFb == newReadFb)
- bindReadBuf = GL_FALSE;
+ assert(newDrawFb);
+ assert(newDrawFb != &DummyFramebuffer);
/*
* OK, now bind the new Draw/Read framebuffers, if they're changing.
}
if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
- ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
+ /* The few classic drivers that actually hook this function really only
+ * want to know if the draw framebuffer changed.
+ */
+ ctx->Driver.BindFramebuffer(ctx,
+ bindDrawBuf ? GL_FRAMEBUFFER : GL_READ_FRAMEBUFFER,
+ newDrawFb, newReadFb);
}
}
}
-void GLAPIENTRY
-_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers)
+/**
+ * This is the implementation for glGenFramebuffers and glCreateFramebuffers.
+ * It is not exposed to the rest of Mesa to encourage the use of
+ * nameless buffers in driver internals.
+ */
+static void
+create_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa)
{
GET_CURRENT_CONTEXT(ctx);
GLuint first;
GLint i;
+ struct gl_framebuffer *fb;
+
+ const char *func = dsa ? "glCreateFramebuffers" : "glGenFramebuffers";
if (n < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
return;
}
if (!framebuffers)
return;
+ _mesa_HashLockMutex(ctx->Shared->FrameBuffers);
+
first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
for (i = 0; i < n; i++) {
GLuint name = first + i;
framebuffers[i] = name;
- /* insert dummy placeholder into hash table */
- mtx_lock(&ctx->Shared->Mutex);
- _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
- mtx_unlock(&ctx->Shared->Mutex);
+
+ if (dsa) {
+ fb = ctx->Driver.NewFramebuffer(ctx, framebuffers[i]);
+ if (!fb) {
+ _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
+ return;
+ }
+ }
+ else
+ fb = &DummyFramebuffer;
+
+ _mesa_HashInsertLocked(ctx->Shared->FrameBuffers, name, fb);
}
+
+ _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers);
}
-GLenum GLAPIENTRY
-_mesa_CheckFramebufferStatus(GLenum target)
+void GLAPIENTRY
+_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers)
{
- struct gl_framebuffer *buffer;
- GET_CURRENT_CONTEXT(ctx);
+ create_framebuffers(n, framebuffers, false);
+}
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n",
- _mesa_lookup_enum_by_nr(target));
+void GLAPIENTRY
+_mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers)
+{
+ create_framebuffers(n, framebuffers, true);
+}
- buffer = get_framebuffer_target(ctx, target);
- if (!buffer) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
- return 0;
- }
+
+GLenum
+_mesa_check_framebuffer_status(struct gl_context *ctx,
+ struct gl_framebuffer *buffer)
+{
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
if (_mesa_is_winsys_fbo(buffer)) {
/* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */
}
+GLenum GLAPIENTRY
+_mesa_CheckFramebufferStatus(GLenum target)
+{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n",
+ _mesa_enum_to_string(target));
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glCheckFramebufferStatus(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return 0;
+ }
+
+ return _mesa_check_framebuffer_status(ctx, fb);
+}
+
+
+GLenum GLAPIENTRY
+_mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target)
+{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* Validate the target (for conformance's sake) and grab a reference to the
+ * default framebuffer in case framebuffer = 0.
+ * Section 9.4 Framebuffer Completeness of the OpenGL 4.5 core spec
+ * (30.10.2014, PDF page 336) says:
+ * "If framebuffer is zero, then the status of the default read or
+ * draw framebuffer (as determined by target) is returned."
+ */
+ switch (target) {
+ case GL_DRAW_FRAMEBUFFER:
+ case GL_FRAMEBUFFER:
+ fb = ctx->WinSysDrawBuffer;
+ break;
+ case GL_READ_FRAMEBUFFER:
+ fb = ctx->WinSysReadBuffer;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glCheckNamedFramebufferStatus(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return 0;
+ }
+
+ if (framebuffer) {
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glCheckNamedFramebufferStatus");
+ if (!fb)
+ return 0;
+ }
+
+ return _mesa_check_framebuffer_status(ctx, fb);
+}
+
+
/**
* Replicate the src attachment point. Used by framebuffer_texture() when
* the same texture is attached at GL_DEPTH_ATTACHMENT and
dst_att->Complete = src_att->Complete;
dst_att->TextureLevel = src_att->TextureLevel;
dst_att->Zoffset = src_att->Zoffset;
+ dst_att->Layered = src_att->Layered;
}
/**
- * Common code called by glFramebufferTexture1D/2D/3D() and
- * glFramebufferTextureLayer().
+ * Common code called by gl*FramebufferTexture*() to retrieve the correct
+ * texture object pointer.
*
- * \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 texObj where the pointer to the texture object is returned. Note
+ * that a successful call may return texObj = NULL.
*
- * \param layered is true if this function was called from
- * glFramebufferTexture(), false otherwise.
+ * \return true if no errors, false if errors
*/
-static void
-framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
- GLenum attachment, GLenum textarget, GLuint texture,
- GLint level, GLuint zoffset, GLboolean layered)
+static bool
+get_texture_for_framebuffer(struct gl_context *ctx, GLuint texture,
+ bool layered, const char *caller,
+ struct gl_texture_object **texObj)
{
- struct gl_renderbuffer_attachment *att;
- struct gl_texture_object *texObj = NULL;
- struct gl_framebuffer *fb;
- GLenum maxLevelsTarget;
+ *texObj = NULL; /* This will get returned if texture = 0. */
- fb = get_framebuffer_target(ctx, target);
- if (!fb) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture%s(target=0x%x)", caller, target);
- return;
+ if (!texture)
+ return true;
+
+ *texObj = _mesa_lookup_texture(ctx, texture);
+ if (*texObj == NULL || (*texObj)->Target == 0) {
+ /* Can't render to a non-existent texture object.
+ *
+ * The OpenGL 4.5 core spec (02.02.2015) in Section 9.2 Binding and
+ * Managing Framebuffer Objects specifies a different error
+ * depending upon the calling function (PDF pages 325-328).
+ * *FramebufferTexture (where layered = GL_TRUE) throws invalid
+ * value, while the other commands throw invalid operation (where
+ * layered = GL_FALSE).
+ */
+ const GLenum error = layered ? GL_INVALID_VALUE :
+ GL_INVALID_OPERATION;
+ _mesa_error(ctx, error,
+ "%s(non-existent texture %u)", caller, texture);
+ return false;
}
- /* check framebuffer binding */
- if (_mesa_is_winsys_fbo(fb)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture%s", caller);
- return;
+ return true;
+}
+
+
+/**
+ * Common code called by gl*FramebufferTexture() to verify the texture target
+ * and decide whether or not the attachment should truly be considered
+ * layered.
+ *
+ * \param layered true if attachment should be considered layered, false if
+ * not
+ *
+ * \return true if no errors, false if errors
+ */
+static bool
+check_layered_texture_target(struct gl_context *ctx, GLenum target,
+ const char *caller, GLboolean *layered)
+{
+ *layered = GL_TRUE;
+
+ switch (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:
+ return true;
+ 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}().
+ */
+ *layered = GL_FALSE;
+ return true;
}
- /* The textarget, level, and zoffset parameters are only validated if
- * texture is non-zero.
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(invalid texture target %s)", caller,
+ _mesa_enum_to_string(target));
+ return false;
+}
+
+
+/**
+ * Common code called by gl*FramebufferTextureLayer() to verify the texture
+ * target.
+ *
+ * \return true if no errors, false if errors
+ */
+static bool
+check_texture_target(struct gl_context *ctx, GLenum target,
+ const char *caller)
+{
+ /* We're being called by glFramebufferTextureLayer().
+ * The only legal texture types for that function are 3D,
+ * cube-map, and 1D/2D/cube-map array textures.
+ *
+ * We don't need to check for GL_ARB_texture_cube_map_array because the
+ * application wouldn't have been able to create a texture with a
+ * GL_TEXTURE_CUBE_MAP_ARRAY target if the extension were not enabled.
*/
- if (texture) {
- GLboolean err = GL_TRUE;
-
- texObj = _mesa_lookup_texture(ctx, texture);
- if (texObj != NULL) {
- if (textarget == 0) {
- 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 */
- err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
- ? !_mesa_is_cube_face(textarget)
- : (texObj->Target != textarget);
- }
+ switch (target) {
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ return true;
+ case GL_TEXTURE_CUBE_MAP:
+ /* We don't need to check the extension (GL_ARB_direct_state_access) or
+ * GL version (4.5) for GL_TEXTURE_CUBE_MAP because DSA is always
+ * enabled in core profile. This can be called from
+ * _mesa_FramebufferTextureLayer in compatibility profile (OpenGL 3.0),
+ * so we do have to check the profile.
+ */
+ return ctx->API == API_OPENGL_CORE;
+ }
+
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(invalid texture target %s)", caller,
+ _mesa_enum_to_string(target));
+ return false;
+}
+
+
+/**
+ * Common code called by glFramebufferTexture*D() to verify the texture
+ * target.
+ *
+ * \return true if no errors, false if errors
+ */
+static bool
+check_textarget(struct gl_context *ctx, int dims, GLenum target,
+ GLenum textarget, const char *caller)
+{
+ bool err = false;
+
+ switch (dims) {
+ case 1:
+ switch (textarget) {
+ case GL_TEXTURE_1D:
+ break;
+ case GL_TEXTURE_1D_ARRAY:
+ err = !ctx->Extensions.EXT_texture_array;
+ break;
+ default:
+ err = true;
}
- else {
- /* can't render to a non-existant texture */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture%s(non existant texture)",
- caller);
- return;
+ break;
+ case 2:
+ switch (textarget) {
+ case GL_TEXTURE_2D:
+ break;
+ case GL_TEXTURE_RECTANGLE:
+ err = _mesa_is_gles(ctx)
+ || !ctx->Extensions.NV_texture_rectangle;
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ err = !ctx->Extensions.ARB_texture_cube_map;
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ err = (_mesa_is_gles(ctx) && ctx->Version < 30)
+ || !ctx->Extensions.EXT_texture_array;
+ break;
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ err = (_mesa_is_gles(ctx) ||
+ !ctx->Extensions.ARB_texture_multisample) &&
+ !_mesa_is_gles31(ctx);
+ break;
+ default:
+ err = true;
}
+ break;
+ case 3:
+ if (textarget != GL_TEXTURE_3D)
+ err = true;
+ break;
+ default:
+ err = true;
+ }
- if (err) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture%s(texture target mismatch)",
- caller);
- return;
- }
+ if (err) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(invalid textarget %s)",
+ caller, _mesa_enum_to_string(textarget));
+ return false;
+ }
- if (texObj->Target == GL_TEXTURE_3D) {
- const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
- if (zoffset >= maxSize) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%s(zoffset)", caller);
- return;
- }
+ /* Make sure textarget is consistent with the texture's type */
+ err = (target == GL_TEXTURE_CUBE_MAP) ?
+ !_mesa_is_cube_face(textarget): (target != textarget);
+
+ if (err) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(mismatched texture target)", caller);
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Common code called by gl*FramebufferTextureLayer() and
+ * glFramebufferTexture3D() to validate the layer.
+ *
+ * \return true if no errors, false if errors
+ */
+static bool
+check_layer(struct gl_context *ctx, GLenum target, GLint layer,
+ const char *caller)
+{
+ /* Page 306 (page 328 of the PDF) of the OpenGL 4.5 (Core Profile)
+ * spec says:
+ *
+ * "An INVALID_VALUE error is generated if texture is non-zero
+ * and layer is negative."
+ */
+ if (layer < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(layer %u < 0)", caller, layer);
+ return false;
+ }
+
+ if (target == GL_TEXTURE_3D) {
+ const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
+ if (layer >= maxSize) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(invalid layer %u)", caller, layer);
+ return false;
}
- else if ((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 (zoffset >= ctx->Const.MaxArrayTextureLayers) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%s(layer)", caller);
- return;
- }
+ }
+ else if ((target == GL_TEXTURE_1D_ARRAY) ||
+ (target == GL_TEXTURE_2D_ARRAY) ||
+ (target == GL_TEXTURE_CUBE_MAP_ARRAY) ||
+ (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) {
+ if (layer >= ctx->Const.MaxArrayTextureLayers) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(layer %u >= GL_MAX_ARRAY_TEXTURE_LAYERS)",
+ caller, layer);
+ return false;
}
-
- maxLevelsTarget = textarget ? textarget : texObj->Target;
- if ((level < 0) ||
- (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) {
+ }
+ else if (target == GL_TEXTURE_CUBE_MAP) {
+ if (layer >= 6) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%s(level)", caller);
- return;
+ "%s(layer %u >= 6)", caller, layer);
+ return false;
}
}
+ return true;
+}
+
+
+/**
+ * Common code called by all gl*FramebufferTexture*() entry points to verify
+ * the level.
+ *
+ * \return true if no errors, false if errors
+ */
+static bool
+check_level(struct gl_context *ctx, GLenum target, GLint level,
+ const char *caller)
+{
+ if ((level < 0) ||
+ (level >= _mesa_max_texture_levels(ctx, target))) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(invalid level %d)", caller, level);
+ return false;
+ }
+
+ return true;
+}
+
+
+void
+_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLenum attachment,
+ struct gl_texture_object *texObj, GLenum textarget,
+ GLint level, GLuint layer, GLboolean layered,
+ const char *caller)
+{
+ struct gl_renderbuffer_attachment *att;
+
+ /* The window-system framebuffer object is immutable */
+ if (_mesa_is_winsys_fbo(fb)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(window-system framebuffer)",
+ caller);
+ return;
+ }
+
+ /* Not a hash lookup, so we can afford to get the attachment here. */
att = get_attachment(ctx, fb, attachment);
if (att == NULL) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture%s(attachment)", caller);
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller,
+ _mesa_enum_to_string(attachment));
return;
}
level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
_mesa_tex_target_to_face(textarget) ==
fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
- zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) {
+ layer == fb->Attachment[BUFFER_STENCIL].Zoffset) {
/* The texture object is already attached to the stencil attachment
* point. Don't create a new renderbuffer; just reuse the stencil
* attachment's. This is required to prevent a GL error in
level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
_mesa_tex_target_to_face(textarget) ==
fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
- zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) {
+ layer == fb->Attachment[BUFFER_DEPTH].Zoffset) {
/* As above, but with depth and stencil transposed. */
reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
BUFFER_DEPTH);
} else {
set_texture_attachment(ctx, fb, att, texObj, textarget,
- level, zoffset, layered);
+ level, layer, layered);
+
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
/* Above we created a new renderbuffer and attached it to the
* depth attachment point. Now attach it to the stencil attachment
}
+static void
+framebuffer_texture_with_dims(int dims, GLenum target,
+ GLenum attachment, GLenum textarget,
+ GLuint texture, GLint level, GLint layer,
+ const char *caller)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+ struct gl_texture_object *texObj;
+
+ /* Get the framebuffer object */
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller,
+ _mesa_enum_to_string(target));
+ return;
+ }
+
+ /* Get the texture object */
+ if (!get_texture_for_framebuffer(ctx, texture, false, caller, &texObj))
+ return;
+
+ if (texObj) {
+ if (!check_textarget(ctx, dims, texObj->Target, textarget, caller))
+ return;
+
+ if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller))
+ return;
+
+ if (!check_level(ctx, textarget, level, caller))
+ return;
+ }
+
+ _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level,
+ layer, GL_FALSE, caller);
+}
+
+
void GLAPIENTRY
_mesa_FramebufferTexture1D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
+{
+ framebuffer_texture_with_dims(1, target, attachment, textarget, texture,
+ level, 0, "glFramebufferTexture1D");
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture, GLint level)
+{
+ framebuffer_texture_with_dims(2, target, attachment, textarget, texture,
+ level, 0, "glFramebufferTexture2D");
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture,
+ GLint level, GLint layer)
+{
+ framebuffer_texture_with_dims(3, target, attachment, textarget, texture,
+ level, layer, "glFramebufferTexture3D");
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
+ GLuint texture, GLint level, GLint layer)
{
GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+ struct gl_texture_object *texObj;
+ GLenum textarget = 0;
- if (texture != 0) {
- GLboolean error;
+ const char *func = "glFramebufferTextureLayer";
- switch (textarget) {
- case GL_TEXTURE_1D:
- error = GL_FALSE;
- break;
- case GL_TEXTURE_1D_ARRAY:
- error = !ctx->Extensions.EXT_texture_array;
- break;
- default:
- error = GL_TRUE;
- }
+ /* Get the framebuffer object */
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTextureLayer(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return;
+ }
- if (error) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture1D(textarget=%s)",
- _mesa_lookup_enum_by_nr(textarget));
+ /* Get the texture object */
+ if (!get_texture_for_framebuffer(ctx, texture, false, func, &texObj))
+ return;
+
+ if (texObj) {
+ if (!check_texture_target(ctx, texObj->Target, func))
return;
+
+ if (!check_layer(ctx, texObj->Target, layer, func))
+ return;
+
+ if (!check_level(ctx, texObj->Target, level, func))
+ return;
+
+ if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+ assert(layer >= 0 && layer < 6);
+ textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
+ layer = 0;
}
}
- framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
- level, 0, GL_FALSE);
+ _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level,
+ layer, GL_FALSE, func);
}
void GLAPIENTRY
-_mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture, GLint level)
+_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment,
+ GLuint texture, GLint level, GLint layer)
{
GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+ struct gl_texture_object *texObj;
+ GLenum textarget = 0;
- if (texture != 0) {
- GLboolean error;
+ const char *func = "glNamedFramebufferTextureLayer";
- switch (textarget) {
- case GL_TEXTURE_2D:
- error = GL_FALSE;
- break;
- case GL_TEXTURE_RECTANGLE:
- error = _mesa_is_gles(ctx)
- || !ctx->Extensions.NV_texture_rectangle;
- break;
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- error = !ctx->Extensions.ARB_texture_cube_map;
- break;
- case GL_TEXTURE_2D_ARRAY:
- error = (_mesa_is_gles(ctx) && ctx->Version < 30)
- || !ctx->Extensions.EXT_texture_array;
- break;
- case GL_TEXTURE_2D_MULTISAMPLE:
- case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
- error = _mesa_is_gles(ctx)
- || !ctx->Extensions.ARB_texture_multisample;
- break;
- default:
- error = GL_TRUE;
- }
+ /* Get the framebuffer object */
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func);
+ if (!fb)
+ return;
- if (error) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture2D(textarget=%s)",
- _mesa_lookup_enum_by_nr(textarget));
+ /* Get the texture object */
+ if (!get_texture_for_framebuffer(ctx, texture, false, func, &texObj))
+ return;
+
+ if (texObj) {
+ if (!check_texture_target(ctx, texObj->Target, func))
+ return;
+
+ if (!check_layer(ctx, texObj->Target, layer, func))
return;
+
+ if (!check_level(ctx, texObj->Target, level, func))
+ return;
+
+ if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+ assert(layer >= 0 && layer < 6);
+ textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
+ layer = 0;
}
}
- framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
- level, 0, GL_FALSE);
+ _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level,
+ layer, GL_FALSE, func);
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture(GLenum target, GLenum attachment,
+ GLuint texture, GLint level)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+ struct gl_texture_object *texObj;
+ GLboolean layered = GL_FALSE;
+
+ const char *func = "FramebufferTexture";
+
+ if (!_mesa_has_geometry_shaders(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "unsupported function (glFramebufferTexture) called");
+ return;
+ }
+
+ /* Get the framebuffer object */
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return;
+ }
+
+ /* Get the texture object */
+ if (!get_texture_for_framebuffer(ctx, texture, true, func, &texObj))
+ return;
+
+ if (texObj) {
+ if (!check_layered_texture_target(ctx, texObj->Target, func, &layered))
+ return;
+
+ if (!check_level(ctx, texObj->Target, level, func))
+ return;
+ }
+
+ _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level,
+ 0, layered, func);
+}
+
+
+void GLAPIENTRY
+_mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment,
+ GLuint texture, GLint level)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+ struct gl_texture_object *texObj;
+ GLboolean layered = GL_FALSE;
+
+ const char *func = "glNamedFramebufferTexture";
+
+ if (!_mesa_has_geometry_shaders(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "unsupported function (glNamedFramebufferTexture) called");
+ return;
+ }
+
+ /* Get the framebuffer object */
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func);
+ if (!fb)
+ return;
+
+ /* Get the texture object */
+ if (!get_texture_for_framebuffer(ctx, texture, true, func, &texObj))
+ return;
+
+ if (texObj) {
+ if (!check_layered_texture_target(ctx, texObj->Target, func,
+ &layered))
+ return;
+
+ if (!check_level(ctx, texObj->Target, level, func))
+ return;
+ }
+
+ _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level,
+ 0, layered, func);
+}
+
+
+void
+_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ GLenum attachment,
+ struct gl_renderbuffer *rb)
+{
+ assert(!_mesa_is_winsys_fbo(fb));
+
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ assert(ctx->Driver.FramebufferRenderbuffer);
+ ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
+
+ /* Some subsequent GL commands may depend on the framebuffer's visual
+ * after the binding is updated. Update visual info now.
+ */
+ _mesa_update_framebuffer_visual(ctx, fb);
}
-
-void GLAPIENTRY
-_mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture,
- GLint level, GLint zoffset)
+static void
+framebuffer_renderbuffer(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ GLenum attachment,
+ struct gl_renderbuffer *rb,
+ const char *func)
{
- GET_CURRENT_CONTEXT(ctx);
+ struct gl_renderbuffer_attachment *att;
- if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
+ if (_mesa_is_winsys_fbo(fb)) {
+ /* Can't attach new renderbuffers to a window system framebuffer */
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture3D(textarget)");
+ "%s(window-system framebuffer)", func);
return;
}
- framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
- level, zoffset, GL_FALSE);
-}
-
-
-void GLAPIENTRY
-_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
- GLuint texture, GLint level, GLint layer)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
- level, layer, GL_FALSE);
-}
-
-
-void GLAPIENTRY
-_mesa_FramebufferTexture(GLenum target, GLenum attachment,
- GLuint texture, GLint level)
-{
- GET_CURRENT_CONTEXT(ctx);
+ att = get_attachment(ctx, fb, attachment);
+ if (att == NULL) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(invalid attachment %s)", func,
+ _mesa_enum_to_string(attachment));
+ return;
+ }
- if (_mesa_has_geometry_shaders(ctx)) {
- framebuffer_texture(ctx, "", target, attachment, 0, texture,
- level, 0, GL_TRUE);
- } else {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "unsupported function (glFramebufferTexture) called");
+ if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
+ rb && rb->Format != MESA_FORMAT_NONE) {
+ /* make sure the renderbuffer is a depth/stencil format */
+ const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
+ if (baseFormat != GL_DEPTH_STENCIL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(renderbuffer is not DEPTH_STENCIL format)", func);
+ return;
+ }
}
-}
+ _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
+}
void GLAPIENTRY
_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
- GLenum renderbufferTarget,
+ GLenum renderbuffertarget,
GLuint renderbuffer)
{
- struct gl_renderbuffer_attachment *att;
struct gl_framebuffer *fb;
struct gl_renderbuffer *rb;
GET_CURRENT_CONTEXT(ctx);
fb = get_framebuffer_target(ctx, target);
if (!fb) {
_mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbuffer(target)");
+ "glFramebufferRenderbuffer(invalid target %s)",
+ _mesa_enum_to_string(target));
return;
}
- if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
+ if (renderbuffertarget != GL_RENDERBUFFER) {
_mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbuffer(renderbufferTarget)");
+ "glFramebufferRenderbuffer(renderbuffertarget is not "
+ "GL_RENDERBUFFER)");
return;
}
- if (_mesa_is_winsys_fbo(fb)) {
- /* Can't attach new renderbuffers to a window system framebuffer */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbuffer");
- return;
+ if (renderbuffer) {
+ rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer,
+ "glFramebufferRenderbuffer");
+ if (!rb)
+ return;
+ }
+ else {
+ /* remove renderbuffer attachment */
+ rb = NULL;
}
- att = get_attachment(ctx, fb, attachment);
- if (att == NULL) {
+ framebuffer_renderbuffer(ctx, fb, attachment, rb,
+ "glFramebufferRenderbuffer");
+}
+
+
+void GLAPIENTRY
+_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer)
+{
+ struct gl_framebuffer *fb;
+ struct gl_renderbuffer *rb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glNamedFramebufferRenderbuffer");
+ if (!fb)
+ return;
+
+ if (renderbuffertarget != GL_RENDERBUFFER) {
_mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbuffer(invalid attachment %s)",
- _mesa_lookup_enum_by_nr(attachment));
+ "glNamedFramebufferRenderbuffer(renderbuffertarget is not "
+ "GL_RENDERBUFFER)");
return;
}
if (renderbuffer) {
- rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
- if (!rb) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferRenderbuffer(non-existant"
- " renderbuffer %u)", renderbuffer);
- return;
- }
- else if (rb == &DummyRenderbuffer) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferRenderbuffer(renderbuffer %u)",
- renderbuffer);
+ rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer,
+ "glNamedFramebufferRenderbuffer");
+ if (!rb)
return;
- }
}
else {
/* remove renderbuffer attachment */
rb = NULL;
}
- if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
- rb && rb->Format != MESA_FORMAT_NONE) {
- /* make sure the renderbuffer is a depth/stencil format */
- const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
- if (baseFormat != GL_DEPTH_STENCIL) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferRenderbuffer(renderbuffer"
- " is not DEPTH_STENCIL format)");
- return;
- }
- }
-
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- assert(ctx->Driver.FramebufferRenderbuffer);
- ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
-
- /* Some subsequent GL commands may depend on the framebuffer's visual
- * after the binding is updated. Update visual info now.
- */
- _mesa_update_framebuffer_visual(ctx, fb);
+ framebuffer_renderbuffer(ctx, fb, attachment, rb,
+ "glNamedFramebufferRenderbuffer");
}
-void GLAPIENTRY
-_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
- GLenum pname, GLint *params)
+void
+_mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx,
+ struct gl_framebuffer *buffer,
+ GLenum attachment, GLenum pname,
+ GLint *params, const char *caller)
{
const struct gl_renderbuffer_attachment *att;
- struct gl_framebuffer *buffer;
GLenum err;
- GET_CURRENT_CONTEXT(ctx);
- /* The error differs in GL and GLES. */
- err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
-
- buffer = get_framebuffer_target(ctx, target);
- if (!buffer) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameteriv(target)");
- return;
- }
+ /* The error code for an attachment type of GL_NONE differs between APIs.
+ *
+ * From the ES 2.0.25 specification, page 127:
+ * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then
+ * querying any other pname will generate INVALID_ENUM."
+ *
+ * From the OpenGL 3.0 specification, page 337, or identically,
+ * the OpenGL ES 3.0.4 specification, page 240:
+ *
+ * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, no
+ * framebuffer is bound to target. In this case querying pname
+ * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero, and all other
+ * queries will generate an INVALID_OPERATION error."
+ */
+ err = ctx->API == API_OPENGLES2 && ctx->Version < 30 ?
+ GL_INVALID_ENUM : GL_INVALID_OPERATION;
if (_mesa_is_winsys_fbo(buffer)) {
/* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec
!ctx->Extensions.ARB_framebuffer_object)
&& !_mesa_is_gles3(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetFramebufferAttachmentParameteriv(bound FBO = 0)");
+ "%s(window-system framebuffer)", caller);
return;
}
if (_mesa_is_gles3(ctx) && attachment != GL_BACK &&
attachment != GL_DEPTH && attachment != GL_STENCIL) {
_mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameteriv(attachment)");
+ "%s(invalid attachment %s)", caller,
+ _mesa_enum_to_string(attachment));
+ return;
+ }
+
+ /* The specs are not clear about how to handle
+ * GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME with the default framebuffer,
+ * but dEQP-GLES3 expects an INVALID_ENUM error. This has also been
+ * discussed in:
+ *
+ * https://cvs.khronos.org/bugzilla/show_bug.cgi?id=12928#c1
+ * and https://bugs.freedesktop.org/show_bug.cgi?id=31947
+ */
+ if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(requesting GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME "
+ "when GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is "
+ "GL_FRAMEBUFFER_DEFAULT is not allowed)", caller);
return;
}
+
/* the default / window-system FBO */
att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
}
}
if (att == NULL) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameteriv(attachment)");
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller,
+ _mesa_enum_to_string(attachment));
return;
}
* attachment, since it does not have a single format."
*/
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetFramebufferAttachmentParameteriv("
- "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"
- " is invalid for depth+stencil attachment)");
+ "%s(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"
+ " is invalid for depth+stencil attachment)", caller);
return;
}
/* the depth and stencil attachments must point to the same buffer */
stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetFramebufferAttachmentParameteriv(DEPTH/STENCIL"
- " attachments differ)");
+ "%s(DEPTH/STENCIL attachments differ)", caller);
return;
}
}
switch (pname) {
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
- *params = _mesa_is_winsys_fbo(buffer)
+ /* From the OpenGL spec, 9.2. Binding and Managing Framebuffer Objects:
+ *
+ * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then
+ * either no framebuffer is bound to target; or the default framebuffer
+ * is bound, attachment is DEPTH or STENCIL, and the number of depth or
+ * stencil bits, respectively, is zero."
+ */
+ *params = (_mesa_is_winsys_fbo(buffer) &&
+ ((attachment != GL_DEPTH && attachment != GL_STENCIL) ||
+ (att->Type != GL_NONE)))
? GL_FRAMEBUFFER_DEFAULT : att->Type;
return;
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
*params = att->TextureLevel;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, err,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
}
else {
goto invalid_pname_enum;
}
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, err,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
}
else {
goto invalid_pname_enum;
if (ctx->API == API_OPENGLES) {
goto invalid_pname_enum;
} else if (att->Type == GL_NONE) {
- _mesa_error(ctx, err,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
} else if (att->Type == GL_TEXTURE) {
if (att->Texture && (att->Texture->Target == GL_TEXTURE_3D ||
att->Texture->Target == GL_TEXTURE_2D_ARRAY)) {
goto invalid_pname_enum;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, err,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
}
else {
if (ctx->Extensions.EXT_framebuffer_sRGB) {
goto invalid_pname_enum;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, err,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
}
else {
mesa_format format = att->Renderbuffer->Format;
if (_mesa_is_gles3(ctx) &&
attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetFramebufferAttachmentParameteriv(cannot query "
+ "%s(cannot query "
"GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of "
- "GL_DEPTH_STENCIL_ATTACHMENT");
+ "GL_DEPTH_STENCIL_ATTACHMENT)", caller);
return;
}
goto invalid_pname_enum;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, err,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
}
else if (att->Texture) {
const struct gl_texture_image *texImage =
att->Renderbuffer->Format);
}
else {
- _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:"
- " invalid FBO attachment structure");
+ _mesa_problem(ctx, "%s: invalid FBO attachment structure", caller);
}
return;
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
} else if (att->Type == GL_TEXTURE) {
*params = att->Layered;
} else if (att->Type == GL_NONE) {
- _mesa_error(ctx, err,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
} else {
goto invalid_pname_enum;
}
return;
invalid_pname_enum:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameteriv(pname)");
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
return;
}
+void GLAPIENTRY
+_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
+ GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *buffer;
+
+ buffer = get_framebuffer_target(ctx, target);
+ if (!buffer) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameteriv(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return;
+ }
+
+ _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
+ params,
+ "glGetFramebufferAttachmentParameteriv");
+}
+
+
+void GLAPIENTRY
+_mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer,
+ GLenum attachment,
+ GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *buffer;
+
+ if (framebuffer) {
+ buffer = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glGetNamedFramebufferAttachmentParameteriv");
+ if (!buffer)
+ return;
+ }
+ else {
+ /*
+ * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL
+ * 4.5 core spec (30.10.2014, PDF page 314):
+ * "If framebuffer is zero, then the default draw framebuffer is
+ * queried."
+ */
+ buffer = ctx->WinSysDrawBuffer;
+ }
+
+ _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
+ params,
+ "glGetNamedFramebufferAttachmentParameteriv");
+}
+
+
+void GLAPIENTRY
+_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname,
+ GLint param)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb = NULL;
+
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glNamedFramebufferParameteri("
+ "ARB_framebuffer_no_attachments not implemented)");
+ return;
+ }
+
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glNamedFramebufferParameteri");
+
+ if (fb) {
+ framebuffer_parameteri(ctx, fb, pname, param,
+ "glNamedFramebufferParameteriv");
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname,
+ GLint *param)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glNamedFramebufferParameteriv("
+ "ARB_framebuffer_no_attachments not implemented)");
+ return;
+ }
+
+ if (framebuffer) {
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glGetNamedFramebufferParameteriv");
+ } else {
+ fb = ctx->WinSysDrawBuffer;
+ }
+
+ if (fb) {
+ get_framebuffer_parameteriv(ctx, fb, pname, param,
+ "glGetNamedFramebufferParameteriv");
+ }
+}
+
+
static void
-invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments,
+invalidate_framebuffer_storage(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ GLsizei numAttachments,
const GLenum *attachments, GLint x, GLint y,
GLsizei width, GLsizei height, const char *name)
{
int i;
- struct gl_framebuffer *fb;
- GET_CURRENT_CONTEXT(ctx);
- fb = get_framebuffer_target(ctx, target);
- if (!fb) {
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name);
+ /* Section 17.4 Whole Framebuffer Operations of the OpenGL 4.5 Core
+ * Spec (2.2.2015, PDF page 522) says:
+ * "An INVALID_VALUE error is generated if numAttachments, width, or
+ * height is negative."
+ */
+ if (numAttachments < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(numAttachments < 0)", name);
return;
}
- if (numAttachments < 0) {
+ if (width < 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "%s(numAttachments < 0)", name);
+ "%s(width < 0)", name);
+ return;
+ }
+
+ if (height < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(height < 0)", name);
return;
}
return;
invalid_enum:
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(attachment)", name);
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", name,
+ _mesa_enum_to_string(attachments[i]));
return;
}
const GLenum *attachments, GLint x, GLint y,
GLsizei width, GLsizei height)
{
- invalidate_framebuffer_storage(target, numAttachments, attachments,
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glInvalidateSubFramebuffer(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return;
+ }
+
+ invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
x, y, width, height,
"glInvalidateSubFramebuffer");
}
+void GLAPIENTRY
+_mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer,
+ GLsizei numAttachments,
+ const GLenum *attachments,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole
+ * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the
+ * default draw framebuffer is affected."
+ */
+ if (framebuffer) {
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glInvalidateNamedFramebufferSubData");
+ if (!fb)
+ return;
+ }
+ else
+ fb = ctx->WinSysDrawBuffer;
+
+ invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
+ x, y, width, height,
+ "glInvalidateNamedFramebufferSubData");
+}
+
+
void GLAPIENTRY
_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments,
const GLenum *attachments)
{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glInvalidateFramebuffer(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return;
+ }
+
/* The GL_ARB_invalidate_subdata spec says:
*
* "The command
* <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
* <MAX_VIEWPORT_DIMS[1]> respectively."
*/
- invalidate_framebuffer_storage(target, numAttachments, attachments,
+ invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
0, 0,
- MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT,
+ ctx->Const.MaxViewportWidth,
+ ctx->Const.MaxViewportHeight,
"glInvalidateFramebuffer");
}
+void GLAPIENTRY
+_mesa_InvalidateNamedFramebufferData(GLuint framebuffer,
+ GLsizei numAttachments,
+ const GLenum *attachments)
+{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole
+ * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the
+ * default draw framebuffer is affected."
+ */
+ if (framebuffer) {
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glInvalidateNamedFramebufferData");
+ if (!fb)
+ return;
+ }
+ else
+ fb = ctx->WinSysDrawBuffer;
+
+ /* The GL_ARB_invalidate_subdata spec says:
+ *
+ * "The command
+ *
+ * void InvalidateFramebuffer(enum target,
+ * sizei numAttachments,
+ * const enum *attachments);
+ *
+ * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>,
+ * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
+ * <MAX_VIEWPORT_DIMS[1]> respectively."
+ */
+ invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
+ 0, 0,
+ ctx->Const.MaxViewportWidth,
+ ctx->Const.MaxViewportHeight,
+ "glInvalidateNamedFramebufferData");
+}
+
+
void GLAPIENTRY
_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments,
const GLenum *attachments)
if (!fb) {
_mesa_error(ctx, GL_INVALID_ENUM,
"glDiscardFramebufferEXT(target %s)",
- _mesa_lookup_enum_by_nr(target));
+ _mesa_enum_to_string(target));
return;
}
invalid_enum:
_mesa_error(ctx, GL_INVALID_ENUM,
"glDiscardFramebufferEXT(attachment %s)",
- _mesa_lookup_enum_by_nr(attachments[i]));
+ _mesa_enum_to_string(attachments[i]));
}