X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=88679215c2775e1bfe44acc527275a80c1f215d1;hb=d90ced445c21b412c08928f0fc0af222021685f7;hp=8db651ca2a146a07cce6525f33f109837f847f10;hpb=cb49940766b581c6656473d89c221653c69fa0f9;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 8db651ca2a1..88679215c27 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -222,15 +222,21 @@ get_framebuffer_target(struct gl_context *ctx, GLenum target) * default / window-system FB object. * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to * the depth buffer attachment point. + * Returns if the attachment is a GL_COLOR_ATTACHMENTm_EXT on + * is_color_attachment, because several callers would return different errors + * if they don't find the attachment. */ static struct gl_renderbuffer_attachment * get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, - GLenum attachment) + GLenum attachment, bool *is_color_attachment) { GLuint i; assert(_mesa_is_user_fbo(fb)); + if (is_color_attachment) + *is_color_attachment = false; + switch (attachment) { case GL_COLOR_ATTACHMENT0_EXT: case GL_COLOR_ATTACHMENT1_EXT: @@ -248,6 +254,8 @@ get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, case GL_COLOR_ATTACHMENT13_EXT: case GL_COLOR_ATTACHMENT14_EXT: case GL_COLOR_ATTACHMENT15_EXT: + if (is_color_attachment) + *is_color_attachment = true; /* Only OpenGL ES 1.x forbids color attachments other than * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the * hardware is used. @@ -277,8 +285,8 @@ get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, * window-system framebuffer (not user-created framebuffer objects). */ static struct gl_renderbuffer_attachment * -_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, - GLenum attachment) +get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment) { assert(_mesa_is_winsys_fbo(fb)); @@ -295,7 +303,7 @@ _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, return &fb->Attachment[BUFFER_BACK_LEFT]; return &fb->Attachment[BUFFER_FRONT_LEFT]; case GL_DEPTH: - return &fb->Attachment[BUFFER_DEPTH]; + return &fb->Attachment[BUFFER_DEPTH]; case GL_STENCIL: return &fb->Attachment[BUFFER_STENCIL]; } @@ -303,9 +311,21 @@ _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, switch (attachment) { case GL_FRONT_LEFT: - return &fb->Attachment[BUFFER_FRONT_LEFT]; + /* Front buffers can be allocated on the first use, but + * glGetFramebufferAttachmentParameteriv must work even if that + * allocation hasn't happened yet. In such case, use the back buffer, + * which should be the same. + */ + if (fb->Attachment[BUFFER_FRONT_LEFT].Type == GL_NONE) + return &fb->Attachment[BUFFER_BACK_LEFT]; + else + return &fb->Attachment[BUFFER_FRONT_LEFT]; case GL_FRONT_RIGHT: - return &fb->Attachment[BUFFER_FRONT_RIGHT]; + /* Same as above. */ + if (fb->Attachment[BUFFER_FRONT_RIGHT].Type == GL_NONE) + return &fb->Attachment[BUFFER_BACK_RIGHT]; + else + return &fb->Attachment[BUFFER_FRONT_RIGHT]; case GL_BACK_LEFT: return &fb->Attachment[BUFFER_BACK_LEFT]; case GL_BACK_RIGHT: @@ -389,7 +409,8 @@ 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) + if (!texImage || + texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0) return false; if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY @@ -430,7 +451,7 @@ _mesa_update_texture_renderbuffer(struct gl_context *ctx, _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); return; } - _mesa_reference_renderbuffer(&att->Renderbuffer, rb); + att->Renderbuffer = rb; /* This can't get called on a texture renderbuffer, so set it to NULL * for clarity compared to user renderbuffers. @@ -530,13 +551,13 @@ _mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, mtx_lock(&fb->Mutex); - att = get_attachment(ctx, fb, attachment); + att = get_attachment(ctx, fb, attachment, NULL); assert(att); if (rb) { set_renderbuffer_attachment(ctx, att, rb); if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { /* do stencil attachment here (depth already done above) */ - att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); + att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL); assert(att); set_renderbuffer_attachment(ctx, att, rb); } @@ -546,7 +567,7 @@ _mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, remove_attachment(ctx, att); if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { /* detach stencil (depth was detached above) */ - att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); + att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL); assert(att); remove_attachment(ctx, att); } @@ -811,7 +832,7 @@ test_attachment_completeness(const struct gl_context *ctx, GLenum format, break; } - baseFormat = _mesa_get_format_base_format(texImage->TexFormat); + baseFormat = texImage->_BaseFormat; if (format == GL_COLOR) { if (!_mesa_is_legal_color_format(ctx, baseFormat)) { @@ -868,8 +889,7 @@ test_attachment_completeness(const struct gl_context *ctx, GLenum format, } } 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 || @@ -957,6 +977,8 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fb->Height = 0; fb->_AllColorBuffersFixedPoint = GL_TRUE; fb->_HasSNormOrFloatColorBuffer = GL_FALSE; + fb->_HasAttachments = true; + fb->_IntegerBuffers = 0; /* Start at -2 to more easily loop over all attachment points. * -2: depth buffer @@ -1077,13 +1099,14 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, continue; } - /* check if integer color */ - fb->_IntegerColor = _mesa_is_format_integer_color(attFormat); - - /* Update _AllColorBuffersFixedPoint and _HasSNormOrFloatColorBuffer. */ + /* Update flags describing color buffer datatypes */ if (i >= 0) { GLenum type = _mesa_get_format_datatype(attFormat); + /* check if integer color */ + if (_mesa_is_format_integer_color(attFormat)) + fb->_IntegerBuffers |= (1 << i); + fb->_AllColorBuffersFixedPoint = fb->_AllColorBuffersFixedPoint && (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED); @@ -1155,14 +1178,48 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, } 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 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) { @@ -1170,7 +1227,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { if (fb->ColorDrawBuffer[j] != GL_NONE) { const struct gl_renderbuffer_attachment *att - = get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); + = get_attachment(ctx, fb, fb->ColorDrawBuffer[j], NULL); assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; @@ -1183,7 +1240,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, /* Check that the ReadBuffer is present */ if (fb->ColorReadBuffer != GL_NONE) { const struct gl_renderbuffer_attachment *att - = get_attachment(ctx, fb, fb->ColorReadBuffer); + = get_attachment(ctx, fb, fb->ColorReadBuffer, NULL); assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; @@ -1218,42 +1275,42 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, 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); } GLboolean GLAPIENTRY _mesa_IsRenderbuffer(GLuint renderbuffer) { + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - if (renderbuffer) { - struct gl_renderbuffer *rb = - _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (rb != NULL && rb != &DummyRenderbuffer) - return GL_TRUE; - } - return GL_FALSE; + + rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + return rb != NULL && rb != &DummyRenderbuffer; } 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; @@ -1264,10 +1321,7 @@ allocate_renderbuffer(struct gl_context *ctx, GLuint renderbuffer, return NULL; } assert(newRb->AllocStorage); - mtx_lock(&ctx->Shared->Mutex); - _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); - newRb->RefCount = 1; /* referenced by hash table */ - mtx_unlock(&ctx->Shared->Mutex); + _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffer, newRb); return newRb; } @@ -1301,7 +1355,10 @@ bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names) } 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 { @@ -1334,6 +1391,203 @@ _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 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 bool +_pname_valid_for_default_framebuffer(struct gl_context *ctx, + GLenum pname) +{ + if (!_mesa_is_desktop_gl(ctx)) + return false; + + switch (pname) { + case GL_DOUBLEBUFFER: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_SAMPLES: + case GL_SAMPLE_BUFFERS: + case GL_STEREO: + return true; + default: + return false; + } +} + +static void +get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum pname, GLint *params, const char *func) +{ + /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries: + * + * "An INVALID_OPERATION error is generated by GetFramebufferParameteriv + * if the default framebuffer is bound to target and pname is not one + * of the accepted values from table 23.73, other than + * SAMPLE_POSITION." + * + * For OpenGL ES, using default framebuffer still raises INVALID_OPERATION + * for any pname. + */ + if (_mesa_is_winsys_fbo(fb) && + !_pname_valid_for_default_framebuffer(ctx, pname)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid pname=0x%x for default framebuffer)", func, pname); + return; + } + + 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; + case GL_DOUBLEBUFFER: + *params = fb->Visual.doubleBufferMode; + break; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + *params = _mesa_get_color_read_format(ctx, fb, func); + break; + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + *params = _mesa_get_color_read_type(ctx, fb, func); + break; + case GL_SAMPLES: + *params = _mesa_geometric_samples(fb); + break; + case GL_SAMPLE_BUFFERS: + *params = _mesa_geometric_samples(fb) > 0; + break; + case GL_STEREO: + *params = fb->Visual.stereoMode; + 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; + } + + get_framebuffer_parameteriv(ctx, fb, pname, params, + "glGetFramebufferParameteriv"); +} + /** * Remove the specified renderbuffer or texture from any attachment point in @@ -1459,6 +1713,8 @@ create_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers, if (!renderbuffers) return; + _mesa_HashLockMutex(ctx->Shared->RenderBuffers); + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); for (i = 0; i < n; i++) { @@ -1466,14 +1722,15 @@ create_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers, 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); } @@ -1489,14 +1746,6 @@ void GLAPIENTRY _mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers) { GET_CURRENT_CONTEXT(ctx); - - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCreateRenderbuffers(GL_ARB_direct_state_access " - "is not supported)"); - return; - } - create_render_buffers(ctx, n, renderbuffers, true); } @@ -1836,6 +2085,63 @@ invalidate_rb(GLuint key, void *data, void *userData) /** 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 @@ -1853,7 +2159,7 @@ renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 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; } @@ -1879,51 +2185,23 @@ renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, */ 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); } /** @@ -1937,22 +2215,16 @@ renderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat, { GET_CURRENT_CONTEXT(ctx); - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(GL_ARB_direct_state_access is not supported)", func); - return; - } - if (MESA_VERBOSE & VERBOSE_API) { 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); } @@ -1983,14 +2255,14 @@ renderbuffer_storage_target(GLenum target, GLenum internalFormat, 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); } @@ -2163,7 +2435,7 @@ get_render_buffer_parameteriv(struct gl_context *ctx, /* 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; } } @@ -2197,13 +2469,6 @@ _mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, { GET_CURRENT_CONTEXT(ctx); - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetNamedRenderbufferParameteriv(" - "GL_ARB_direct_state_access is not supported)"); - return; - } - struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); if (!rb || rb == &DummyRenderbuffer) { /* ID was reserved, but no real renderbuffer object made yet */ @@ -2284,7 +2549,6 @@ 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); @@ -2338,18 +2602,23 @@ bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names) 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. @@ -2386,7 +2655,12 @@ bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names) } 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); } } @@ -2475,12 +2749,6 @@ create_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) const char *func = dsa ? "glCreateFramebuffers" : "glGenFramebuffers"; - if (dsa && !ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(GL_ARB_direct_state_access is not supported)", func); - return; - } - if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; @@ -2489,6 +2757,8 @@ create_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) if (!framebuffers) return; + _mesa_HashLockMutex(ctx->Shared->FrameBuffers); + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); for (i = 0; i < n; i++) { @@ -2498,6 +2768,7 @@ create_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) 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; } @@ -2505,10 +2776,10 @@ create_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) else fb = &DummyFramebuffer; - mtx_lock(&ctx->Shared->Mutex); - _mesa_HashInsert(ctx->Shared->FrameBuffers, name, fb); - mtx_unlock(&ctx->Shared->Mutex); + _mesa_HashInsertLocked(ctx->Shared->FrameBuffers, name, fb); } + + _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers); } @@ -2559,13 +2830,13 @@ _mesa_CheckFramebufferStatus(GLenum target) if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); fb = get_framebuffer_target(ctx, target); if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return 0; } @@ -2579,13 +2850,6 @@ _mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) struct gl_framebuffer *fb; GET_CURRENT_CONTEXT(ctx); - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCheckNamedFramebufferStatus(GL_ARB_direct_state_access " - "is not supported)"); - return 0; - } - /* 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 @@ -2604,7 +2868,7 @@ _mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) default: _mesa_error(ctx, GL_INVALID_ENUM, "glCheckNamedFramebufferStatus(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return 0; } @@ -2640,7 +2904,9 @@ reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, dst_att->Type = src_att->Type; dst_att->Complete = src_att->Complete; dst_att->TextureLevel = src_att->TextureLevel; + dst_att->CubeMapFace = src_att->CubeMapFace; dst_att->Zoffset = src_att->Zoffset; + dst_att->Layered = src_att->Layered; } @@ -2723,7 +2989,7 @@ check_layered_texture_target(struct gl_context *ctx, GLenum target, _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture target %s)", caller, - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return false; } @@ -2741,6 +3007,10 @@ check_texture_target(struct gl_context *ctx, GLenum target, /* 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. */ switch (target) { case GL_TEXTURE_3D: @@ -2750,15 +3020,18 @@ check_texture_target(struct gl_context *ctx, GLenum target, case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: return true; case GL_TEXTURE_CUBE_MAP: - /* This target is valid in TextureLayer when ARB_direct_state_access - * or OpenGL 4.5 is supported. + /* 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->Extensions.ARB_direct_state_access; + return ctx->API == API_OPENGL_CORE; } _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture target %s)", caller, - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return false; } @@ -2775,59 +3048,55 @@ check_textarget(struct gl_context *ctx, int dims, GLenum target, { 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; - } + switch (textarget) { + case GL_TEXTURE_1D: + err = dims != 1; 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; - break; - default: - err = true; - } + case GL_TEXTURE_1D_ARRAY: + err = dims != 1 || !ctx->Extensions.EXT_texture_array; break; - case 3: - if (textarget != GL_TEXTURE_3D) - err = true; + case GL_TEXTURE_2D: + err = dims != 2; break; - default: + case GL_TEXTURE_2D_ARRAY: + err = dims != 2 || !ctx->Extensions.EXT_texture_array || + (_mesa_is_gles(ctx) && ctx->Version < 30); + break; + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + err = dims != 2 || + !ctx->Extensions.ARB_texture_multisample || + (_mesa_is_gles(ctx) && ctx->Version < 31); + break; + case GL_TEXTURE_RECTANGLE: + err = dims != 2 || _mesa_is_gles(ctx) || + !ctx->Extensions.NV_texture_rectangle; + break; + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_ARRAY: err = true; + 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 = dims != 2 || !ctx->Extensions.ARB_texture_cube_map; + break; + case GL_TEXTURE_3D: + err = dims != 3; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(unknown textarget 0x%x)", caller, textarget); + return false; } if (err) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid textarget %s)", - caller, _mesa_lookup_enum_by_nr(textarget)); + caller, _mesa_enum_to_string(textarget)); return false; } @@ -2919,30 +3188,51 @@ check_level(struct gl_context *ctx, GLenum target, GLint level, } -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 * +_mesa_get_and_validate_attachment(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLenum attachment, 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; + return NULL; } /* Not a hash lookup, so we can afford to get the attachment here. */ - att = get_attachment(ctx, fb, attachment); + bool is_color_attachment; + struct gl_renderbuffer_attachment *att = + get_attachment(ctx, fb, attachment, &is_color_attachment); if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, - _mesa_lookup_enum_by_nr(attachment)); - return; + if (is_color_attachment) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid color attachment %s)", caller, + _mesa_enum_to_string(attachment)); + } else { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(invalid attachment %s)", caller, + _mesa_enum_to_string(attachment)); + } + return NULL; } + return att; +} + + +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 = + _mesa_get_and_validate_attachment(ctx, fb, attachment, caller); + if (!att) + return; + FLUSH_VERTICES(ctx, _NEW_BUFFERS); mtx_lock(&fb->Mutex); @@ -3022,7 +3312,7 @@ framebuffer_texture_with_dims(int dims, GLenum target, fb = get_framebuffer_target(ctx, target); if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller, - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } @@ -3036,10 +3326,10 @@ framebuffer_texture_with_dims(int dims, GLenum target, if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller)) return; - } - if (!check_level(ctx, textarget, level, caller)) - return; + if (!check_level(ctx, textarget, level, caller)) + return; + } _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level, layer, GL_FALSE, caller); @@ -3090,7 +3380,7 @@ _mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTextureLayer(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } @@ -3131,12 +3421,6 @@ _mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, const char *func = "glNamedFramebufferTextureLayer"; - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(GL_ARB_direct_state_access is not supported)", func); - return; - } - /* Get the framebuffer object */ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); if (!fb) @@ -3175,7 +3459,7 @@ _mesa_FramebufferTexture(GLenum target, GLenum attachment, GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *fb; struct gl_texture_object *texObj; - GLboolean layered; + GLboolean layered = GL_FALSE; const char *func = "FramebufferTexture"; @@ -3190,7 +3474,7 @@ _mesa_FramebufferTexture(GLenum target, GLenum attachment, if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } @@ -3218,16 +3502,10 @@ _mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *fb; struct gl_texture_object *texObj; - GLboolean layered; + GLboolean layered = GL_FALSE; const char *func = "glNamedFramebufferTexture"; - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(GL_ARB_direct_state_access is not supported)", func); - return; - } - if (!_mesa_has_geometry_shaders(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "unsupported function (glNamedFramebufferTexture) called"); @@ -3261,10 +3539,30 @@ void _mesa_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, GLenum attachment, - struct gl_renderbuffer *rb, - const char *func) + 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); +} + +static void +framebuffer_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLenum attachment, + struct gl_renderbuffer *rb, + const char *func) { struct gl_renderbuffer_attachment *att; + bool is_color_attachment; if (_mesa_is_winsys_fbo(fb)) { /* Can't attach new renderbuffers to a window system framebuffer */ @@ -3273,11 +3571,29 @@ _mesa_framebuffer_renderbuffer(struct gl_context *ctx, return; } - att = get_attachment(ctx, fb, attachment); + att = get_attachment(ctx, fb, attachment, &is_color_attachment); if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(invalid attachment %s)", func, - _mesa_lookup_enum_by_nr(attachment)); + /* + * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images to + * a Framebuffer": + * + * "An INVALID_OPERATION error is generated if attachment is COLOR_- + * ATTACHMENTm where m is greater than or equal to the value of + * MAX_COLOR_- ATTACHMENTS ." + * + * If we are at this point, is because the attachment is not valid, so + * if is_color_attachment is true, is because of the previous reason. + */ + if (is_color_attachment) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid color attachment %s)", func, + _mesa_enum_to_string(attachment)); + } else { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(invalid attachment %s)", func, + _mesa_enum_to_string(attachment)); + } + return; } @@ -3292,18 +3608,9 @@ _mesa_framebuffer_renderbuffer(struct gl_context *ctx, } } - 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); + _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); } - void GLAPIENTRY _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, @@ -3317,7 +3624,7 @@ _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbuffer(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } @@ -3339,8 +3646,8 @@ _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, rb = NULL; } - _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb, - "glFramebufferRenderbuffer"); + framebuffer_renderbuffer(ctx, fb, attachment, rb, + "glFramebufferRenderbuffer"); } @@ -3353,15 +3660,10 @@ _mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glNamedFramebufferRenderbuffer(GL_ARB_direct_state_access " - "is not supported)"); - return; - } - fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, "glNamedFramebufferRenderbuffer"); + if (!fb) + return; if (renderbuffertarget != GL_RENDERBUFFER) { _mesa_error(ctx, GL_INVALID_ENUM, @@ -3381,22 +3683,37 @@ _mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, rb = NULL; } - _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb, - "glNamedFramebufferRenderbuffer"); + framebuffer_renderbuffer(ctx, fb, attachment, rb, + "glNamedFramebufferRenderbuffer"); } -void -_mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, - struct gl_framebuffer *buffer, - GLenum attachment, GLenum pname, - GLint *params, const char *caller) +static void +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; + bool is_color_attachment = false; GLenum err; - /* The error differs in GL and GLES. */ - err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM; + /* 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 @@ -3421,20 +3738,52 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, attachment != GL_DEPTH && attachment != GL_STENCIL) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, - _mesa_lookup_enum_by_nr(attachment)); + _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); + att = get_fb0_attachment(ctx, buffer, attachment); } else { /* user-created framebuffer FBO */ - att = get_attachment(ctx, buffer, attachment); + att = get_attachment(ctx, buffer, attachment, &is_color_attachment); } if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, - _mesa_lookup_enum_by_nr(attachment)); + /* + * From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries": + * + * "An INVALID_OPERATION error is generated if a framebuffer object + * is bound to target and attachment is COLOR_ATTACHMENTm where m is + * greater than or equal to the value of MAX_COLOR_ATTACHMENTS." + * + * If we are at this point, is because the attachment is not valid, so + * if is_color_attachment is true, is because of the previous reason. + */ + if (is_color_attachment) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid color attachment %s)", + caller, _mesa_enum_to_string(attachment)); + } else { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, + _mesa_enum_to_string(attachment)); + } return; } @@ -3453,8 +3802,8 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, return; } /* the depth and stencil attachments must point to the same buffer */ - depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); - stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); + depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT, NULL); + stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT, NULL); if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(DEPTH/STENCIL attachments differ)", caller); @@ -3466,8 +3815,19 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, switch (pname) { case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = _mesa_is_winsys_fbo(buffer) - ? GL_FRAMEBUFFER_DEFAULT : att->Type; + /* 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." + * + * Note that we don't need explicit checks on DEPTH and STENCIL, because + * on the case the spec is pointing, att->Type is already NONE, so we + * just need to check att->Type. + */ + *params = (_mesa_is_winsys_fbo(buffer) && att->Type != GL_NONE) ? + GL_FRAMEBUFFER_DEFAULT : att->Type; return; case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: if (att->Type == GL_RENDERBUFFER_EXT) { @@ -3491,7 +3851,7 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, } else if (att->Type == GL_NONE) { _mesa_error(ctx, err, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); } else { goto invalid_pname_enum; @@ -3508,7 +3868,7 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, } else if (att->Type == GL_NONE) { _mesa_error(ctx, err, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); } else { goto invalid_pname_enum; @@ -3519,7 +3879,7 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, goto invalid_pname_enum; } else if (att->Type == GL_NONE) { _mesa_error(ctx, err, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); + _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)) { @@ -3540,8 +3900,13 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, goto invalid_pname_enum; } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); + if (_mesa_is_winsys_fbo(buffer) && + (attachment == GL_DEPTH || attachment == GL_STENCIL)) { + *params = GL_LINEAR; + } else { + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_enum_to_string(pname)); + } } else { if (ctx->Extensions.EXT_framebuffer_sRGB) { @@ -3564,7 +3929,7 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, } else if (att->Type == GL_NONE) { _mesa_error(ctx, err, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); } else { mesa_format format = att->Renderbuffer->Format; @@ -3614,10 +3979,6 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, && !_mesa_is_gles3(ctx)) { goto invalid_pname_enum; } - else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); - } else if (att->Texture) { const struct gl_texture_image *texImage = _mesa_select_tex_image(att->Texture, att->Texture->Target, @@ -3635,7 +3996,9 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, att->Renderbuffer->Format); } else { - _mesa_problem(ctx, "%s: invalid FBO attachment structure", caller); + assert(att->Type == GL_NONE); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_enum_to_string(pname)); } return; case GL_FRAMEBUFFER_ATTACHMENT_LAYERED: @@ -3645,7 +4008,7 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, *params = att->Layered; } else if (att->Type == GL_NONE) { _mesa_error(ctx, err, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); } else { goto invalid_pname_enum; } @@ -3658,7 +4021,7 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, invalid_pname_enum: _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname %s)", caller, - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); return; } @@ -3674,12 +4037,12 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, if (!buffer) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameteriv(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } - _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, - params, + get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, + params, "glGetFramebufferAttachmentParameteriv"); } @@ -3692,13 +4055,6 @@ _mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *buffer; - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetNamedFramebufferAttachmentParameteriv(" - "GL_ARB_direct_state_access is not supported)"); - return; - } - if (framebuffer) { buffer = _mesa_lookup_framebuffer_err(ctx, framebuffer, "glGetNamedFramebufferAttachmentParameteriv"); @@ -3715,8 +4071,8 @@ _mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, buffer = ctx->WinSysDrawBuffer; } - _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, - params, + get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, + params, "glGetNamedFramebufferAttachmentParameteriv"); } @@ -3726,21 +4082,22 @@ _mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GLint param) { GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb = NULL; - (void) framebuffer; - (void) pname; - (void) param; - - if (!ctx->Extensions.ARB_direct_state_access) { + if (!ctx->Extensions.ARB_framebuffer_no_attachments) { _mesa_error(ctx, GL_INVALID_OPERATION, "glNamedFramebufferParameteri(" - "GL_ARB_direct_state_access is not supported)"); + "ARB_framebuffer_no_attachments not implemented)"); return; } - _mesa_error(ctx, GL_INVALID_OPERATION, - "glNamedFramebufferParameteri not supported " - "(ARB_framebuffer_no_attachments not implemented)"); + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glNamedFramebufferParameteri"); + + if (fb) { + framebuffer_parameteri(ctx, fb, pname, param, + "glNamedFramebufferParameteriv"); + } } @@ -3749,21 +4106,26 @@ _mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, GLint *param) { GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; - (void) framebuffer; - (void) pname; - (void) param; - - if (!ctx->Extensions.ARB_direct_state_access) { + if (!ctx->Extensions.ARB_framebuffer_no_attachments) { _mesa_error(ctx, GL_INVALID_OPERATION, "glNamedFramebufferParameteriv(" - "GL_ARB_direct_state_access is not supported)"); + "ARB_framebuffer_no_attachments not implemented)"); return; } - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetNamedFramebufferParameteriv not supported " - "(ARB_framebuffer_no_attachments not implemented)"); + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glGetNamedFramebufferParameteriv"); + } else { + fb = ctx->WinSysDrawBuffer; + } + + if (fb) { + get_framebuffer_parameteriv(ctx, fb, pname, param, + "glGetNamedFramebufferParameteriv"); + } } @@ -3892,7 +4254,7 @@ invalidate_framebuffer_storage(struct gl_context *ctx, invalid_enum: _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", name, - _mesa_lookup_enum_by_nr(attachments[i])); + _mesa_enum_to_string(attachments[i])); return; } @@ -3909,7 +4271,7 @@ _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glInvalidateSubFramebuffer(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } @@ -3929,13 +4291,6 @@ _mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, struct gl_framebuffer *fb; GET_CURRENT_CONTEXT(ctx); - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glInvalidateNamedFramebufferSubData(" - "GL_ARB_direct_state_access is not supported)"); - return; - } - /* 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." @@ -3966,7 +4321,7 @@ _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glInvalidateFramebuffer(invalid target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } @@ -3984,7 +4339,8 @@ _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, */ invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 0, 0, - MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, + ctx->Const.MaxViewportWidth, + ctx->Const.MaxViewportHeight, "glInvalidateFramebuffer"); } @@ -3997,13 +4353,6 @@ _mesa_InvalidateNamedFramebufferData(GLuint framebuffer, struct gl_framebuffer *fb; GET_CURRENT_CONTEXT(ctx); - if (!ctx->Extensions.ARB_direct_state_access) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glInvalidateNamedFramebufferData(" - "GL_ARB_direct_state_access is not supported)"); - return; - } - /* 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." @@ -4031,7 +4380,8 @@ _mesa_InvalidateNamedFramebufferData(GLuint framebuffer, */ invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 0, 0, - MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, + ctx->Const.MaxViewportWidth, + ctx->Const.MaxViewportHeight, "glInvalidateNamedFramebufferData"); } @@ -4049,7 +4399,7 @@ _mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "glDiscardFramebufferEXT(target %s)", - _mesa_lookup_enum_by_nr(target)); + _mesa_enum_to_string(target)); return; } @@ -4086,5 +4436,5 @@ _mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, invalid_enum: _mesa_error(ctx, GL_INVALID_ENUM, "glDiscardFramebufferEXT(attachment %s)", - _mesa_lookup_enum_by_nr(attachments[i])); + _mesa_enum_to_string(attachments[i])); }