X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=c8735d0459ac297f1b06273a5aa26562605cf8b3;hb=HEAD;hp=ce5eeae048cab6e7ba40de9e24fe006607e81178;hpb=c6eb3aeba530fe82087c1c3c06ded23cb79bc199;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index ce5eeae048c..c8735d0459a 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -35,6 +35,7 @@ #include "buffers.h" #include "context.h" +#include "debug_output.h" #include "enums.h" #include "fbobject.h" #include "formats.h" @@ -89,9 +90,9 @@ delete_dummy_framebuffer(struct gl_framebuffer *fb) void _mesa_init_fbobjects(struct gl_context *ctx) { - mtx_init(&DummyFramebuffer.Mutex, mtx_plain); - mtx_init(&DummyRenderbuffer.Mutex, mtx_plain); - mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain); + simple_mtx_init(&DummyFramebuffer.Mutex, mtx_plain); + simple_mtx_init(&DummyRenderbuffer.Mutex, mtx_plain); + simple_mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain); DummyFramebuffer.Delete = delete_dummy_framebuffer; DummyRenderbuffer.Delete = delete_dummy_renderbuffer; IncompleteFramebuffer.Delete = delete_dummy_framebuffer; @@ -154,6 +155,36 @@ _mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) fb = (struct gl_framebuffer *) _mesa_HashLookup(ctx->Shared->FrameBuffers, id); + + return fb; +} + + +struct gl_framebuffer * +_mesa_lookup_framebuffer_dsa(struct gl_context *ctx, GLuint id, + const char* func) +{ + struct gl_framebuffer *fb; + + if (id == 0) + return NULL; + + fb = _mesa_lookup_framebuffer(ctx, id); + + /* Name exists but buffer is not initialized */ + if (fb == &DummyFramebuffer) { + fb = ctx->Driver.NewFramebuffer(ctx, id); + _mesa_HashInsert(ctx->Shared->FrameBuffers, id, fb); + } + /* Name doesn't exist */ + else if (!fb) { + fb = ctx->Driver.NewFramebuffer(ctx, id); + if (!fb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); + return NULL; + } + _mesa_HashInsert(ctx->Shared->FrameBuffers, id, fb); + } return fb; } @@ -265,6 +296,7 @@ get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, || (i > 0 && ctx->API == API_OPENGLES)) { return NULL; } + assert(BUFFER_COLOR0 + i < ARRAY_SIZE(fb->Attachment)); return &fb->Attachment[BUFFER_COLOR0 + i]; case GL_DEPTH_STENCIL_ATTACHMENT: if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) @@ -285,27 +317,29 @@ 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)); + attachment = _mesa_back_to_front_if_single_buffered(fb, attachment); + if (_mesa_is_gles3(ctx)) { - assert(attachment == GL_BACK || - attachment == GL_DEPTH || - attachment == GL_STENCIL); switch (attachment) { case GL_BACK: /* Since there is no stereo rendering in ES 3.0, only return the * LEFT bits. */ - if (ctx->DrawBuffer->Visual.doubleBufferMode) - return &fb->Attachment[BUFFER_BACK_LEFT]; + return &fb->Attachment[BUFFER_BACK_LEFT]; + case GL_FRONT: + /* We might get this if back_to_front triggers above */ 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]; + default: + unreachable("invalid attachment"); } } @@ -330,6 +364,15 @@ _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, return &fb->Attachment[BUFFER_BACK_LEFT]; case GL_BACK_RIGHT: return &fb->Attachment[BUFFER_BACK_RIGHT]; + case GL_BACK: + /* The ARB_ES3_1_compatibility spec says: + * + * "Since this command can only query a single framebuffer + * attachment, BACK is equivalent to BACK_LEFT." + */ + if (ctx->Extensions.ARB_ES3_1_compatibility) + return &fb->Attachment[BUFFER_BACK_LEFT]; + return NULL; case GL_AUX0: if (fb->Visual.numAuxBuffers == 1) { return &fb->Attachment[BUFFER_AUX0]; @@ -451,7 +494,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. @@ -471,6 +514,7 @@ _mesa_update_texture_renderbuffer(struct gl_context *ctx, rb->Height = texImage->Height2; rb->Depth = texImage->Depth2; rb->NumSamples = texImage->NumSamples; + rb->NumStorageSamples = texImage->NumSamples; rb->TexImage = texImage; if (driver_RenderTexture_is_safe(att)) @@ -486,8 +530,8 @@ set_texture_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att, struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint layer, - GLboolean layered) + GLenum texTarget, GLuint level, GLsizei samples, + GLuint layer, GLboolean layered) { struct gl_renderbuffer *rb = att->Renderbuffer; @@ -509,6 +553,7 @@ set_texture_attachment(struct gl_context *ctx, /* always update these fields */ att->TextureLevel = level; + att->NumSamples = samples; att->CubeMapFace = _mesa_tex_target_to_face(texTarget); att->Zoffset = layer; att->Layered = layered; @@ -549,7 +594,7 @@ _mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, { struct gl_renderbuffer_attachment *att; - mtx_lock(&fb->Mutex); + simple_mtx_lock(&fb->Mutex); att = get_attachment(ctx, fb, attachment, NULL); assert(att); @@ -575,7 +620,7 @@ _mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, invalidate_framebuffer(fb); - mtx_unlock(&fb->Mutex); + simple_mtx_unlock(&fb->Mutex); } @@ -663,11 +708,11 @@ fbo_incomplete(struct gl_context *ctx, const char *msg, int index) { static GLuint msg_id; - _mesa_gl_debug(ctx, &msg_id, - MESA_DEBUG_SOURCE_API, - MESA_DEBUG_TYPE_OTHER, - MESA_DEBUG_SEVERITY_MEDIUM, - "FBO incomplete: %s [%d]\n", msg, index); + _mesa_gl_debugf(ctx, &msg_id, + MESA_DEBUG_SOURCE_API, + MESA_DEBUG_TYPE_OTHER, + MESA_DEBUG_SEVERITY_MEDIUM, + "FBO incomplete: %s [%d]\n", msg, index); if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); @@ -718,7 +763,15 @@ is_format_color_renderable(const struct gl_context *ctx, mesa_format format, /* Reject additional cases for GLES */ switch (internalFormat) { + case GL_R8_SNORM: + case GL_RG8_SNORM: case GL_RGBA8_SNORM: + return _mesa_has_EXT_render_snorm(ctx); + case GL_R16_SNORM: + case GL_RG16_SNORM: + case GL_RGBA16_SNORM: + return _mesa_has_EXT_texture_norm16(ctx) && + _mesa_has_EXT_render_snorm(ctx); case GL_RGB32F: case GL_RGB32I: case GL_RGB32UI: @@ -729,16 +782,19 @@ is_format_color_renderable(const struct gl_context *ctx, mesa_format format, case GL_RGB8I: case GL_RGB8UI: case GL_SRGB8: + case GL_RGB10: case GL_RGB9_E5: - case GL_RG8_SNORM: - case GL_R8_SNORM: + case GL_SR8_EXT: return GL_FALSE; default: break; } - if (format == MESA_FORMAT_B10G10R10A2_UNORM && - internalFormat != GL_RGB10_A2) { + if (internalFormat != GL_RGB10_A2 && + (format == MESA_FORMAT_B10G10R10A2_UNORM || + format == MESA_FORMAT_B10G10R10X2_UNORM || + format == MESA_FORMAT_R10G10B10A2_UNORM || + format == MESA_FORMAT_R10G10B10X2_UNORM)) { return GL_FALSE; } @@ -780,7 +836,7 @@ test_attachment_completeness(const struct gl_context *ctx, GLenum format, /* Look for reasons why the attachment might be incomplete */ if (att->Type == GL_TEXTURE) { const struct gl_texture_object *texObj = att->Texture; - struct gl_texture_image *texImage; + const struct gl_texture_image *texImage; GLenum baseFormat; if (!texObj) { @@ -851,8 +907,7 @@ test_attachment_completeness(const struct gl_context *ctx, GLenum format, * these textures to be used as a render target, this is done via * GL_EXT_color_buffer(_half)_float with set of new sized types. */ - if (_mesa_is_gles(ctx) && (texImage->TexObject->_IsFloat || - texImage->TexObject->_IsHalfFloat)) { + if (_mesa_is_gles(ctx) && (texObj->_IsFloat || texObj->_IsHalfFloat)) { att_incomplete("bad internal format"); att->Complete = GL_FALSE; return; @@ -955,7 +1010,9 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, GLuint numImages; GLenum intFormat = GL_NONE; /* color buffers' internal format */ GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; - GLint numSamples = -1; + GLint numColorSamples = -1; + GLint numColorStorageSamples = -1; + GLint numDepthSamples = -1; GLint fixedSampleLocations = -1; GLint i; GLuint j; @@ -979,6 +1036,8 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fb->_HasSNormOrFloatColorBuffer = GL_FALSE; fb->_HasAttachments = true; fb->_IntegerBuffers = 0; + fb->_RGBBuffers = 0; + fb->_FP32Buffers = 0; /* Start at -2 to more easily loop over all attachment points. * -2: depth buffer @@ -988,6 +1047,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { struct gl_renderbuffer_attachment *att; GLenum f; + GLenum baseFormat; mesa_format attFormat; GLenum att_tex_target = GL_NONE; @@ -1032,6 +1092,8 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, /* get width, height, format of the renderbuffer/texture */ + unsigned attNumSamples, attNumStorageSamples; + if (att->Type == GL_TEXTURE) { const struct gl_texture_image *texImg = att->Renderbuffer->TexImage; att_tex_target = att->Texture->Target; @@ -1040,6 +1102,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, minHeight = MIN2(minHeight, texImg->Height); maxHeight = MAX2(maxHeight, texImg->Height); f = texImg->_BaseFormat; + baseFormat = f; attFormat = texImg->TexFormat; numImages++; @@ -1052,14 +1115,6 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, return; } - if (numSamples < 0) - numSamples = texImg->NumSamples; - else if (numSamples != texImg->NumSamples) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; - fbo_incomplete(ctx, "inconsistent sample count", -1); - return; - } - if (fixedSampleLocations < 0) fixedSampleLocations = texImg->FixedSampleLocations; else if (fixedSampleLocations != texImg->FixedSampleLocations) { @@ -1067,6 +1122,12 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); return; } + + if (att->NumSamples > 0) + attNumSamples = att->NumSamples; + else + attNumSamples = texImg->NumSamples; + attNumStorageSamples = attNumSamples; } else if (att->Type == GL_RENDERBUFFER_EXT) { minWidth = MIN2(minWidth, att->Renderbuffer->Width); @@ -1074,17 +1135,10 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, minHeight = MIN2(minHeight, att->Renderbuffer->Height); maxHeight = MAX2(minHeight, att->Renderbuffer->Height); f = att->Renderbuffer->InternalFormat; + baseFormat = att->Renderbuffer->_BaseFormat; attFormat = att->Renderbuffer->Format; numImages++; - if (numSamples < 0) - numSamples = att->Renderbuffer->NumSamples; - else if (numSamples != att->Renderbuffer->NumSamples) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; - fbo_incomplete(ctx, "inconsistent sample count", -1); - return; - } - /* RENDERBUFFER has fixedSampleLocations implicitly true */ if (fixedSampleLocations < 0) fixedSampleLocations = GL_TRUE; @@ -1093,12 +1147,38 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); return; } + + attNumSamples = att->Renderbuffer->NumSamples; + attNumStorageSamples = att->Renderbuffer->NumStorageSamples; } else { assert(att->Type == GL_NONE); continue; } + if (i >= 0) { + /* Color buffers. */ + if (numColorSamples < 0) { + assert(numColorStorageSamples < 0); + numColorSamples = attNumSamples; + numColorStorageSamples = attNumStorageSamples; + } else if (numColorSamples != attNumSamples || + numColorStorageSamples != attNumStorageSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample counts", -1); + return; + } + } else { + /* Depth/stencil buffers. */ + if (numDepthSamples < 0) { + numDepthSamples = attNumSamples; + } else if (numDepthSamples != attNumSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample counts", -1); + return; + } + } + /* Update flags describing color buffer datatypes */ if (i >= 0) { GLenum type = _mesa_get_format_datatype(attFormat); @@ -1107,6 +1187,12 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, if (_mesa_is_format_integer_color(attFormat)) fb->_IntegerBuffers |= (1 << i); + if (baseFormat == GL_RGB) + fb->_RGBBuffers |= (1 << i); + + if (type == GL_FLOAT && _mesa_get_format_max_bits(attFormat) > 16) + fb->_FP32Buffers |= (1 << i); + fb->_AllColorBuffersFixedPoint = fb->_AllColorBuffersFixedPoint && (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED); @@ -1204,6 +1290,51 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, */ } + if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { + /* See if non-matching sample counts are supported. */ + if (numColorSamples >= 0 && numDepthSamples >= 0) { + bool found = false; + + assert(numColorStorageSamples != -1); + + numColorSamples = MAX2(numColorSamples, 1); + numColorStorageSamples = MAX2(numColorStorageSamples, 1); + numDepthSamples = MAX2(numDepthSamples, 1); + + if (numColorSamples == 1 && numColorStorageSamples == 1 && + numDepthSamples == 1) { + found = true; + } else { + for (i = 0; i < ctx->Const.NumSupportedMultisampleModes; i++) { + GLint *counts = + &ctx->Const.SupportedMultisampleModes[i].NumColorSamples; + + if (counts[0] == numColorSamples && + counts[1] == numColorStorageSamples && + counts[2] == numDepthSamples) { + found = true; + break; + } + } + } + + if (!found) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "unsupported sample counts", -1); + return; + } + } + } else { + /* If the extension is unsupported, all sample counts must be equal. */ + if (numColorSamples >= 0 && + (numColorSamples != numColorStorageSamples || + (numDepthSamples >= 0 && numColorSamples != numDepthSamples))) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete(ctx, "inconsistent sample counts", -1); + return; + } + } + fb->MaxNumLayers = max_layer_count; if (numImages == 0) { @@ -1297,15 +1428,14 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, 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; } @@ -1323,14 +1453,13 @@ allocate_renderbuffer_locked(struct gl_context *ctx, GLuint renderbuffer, } assert(newRb->AllocStorage); _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffer, newRb); - newRb->RefCount = 1; /* referenced by hash table */ return newRb; } static void -bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names) +bind_renderbuffer(GLenum target, GLuint renderbuffer) { struct gl_renderbuffer *newRb; GET_CURRENT_CONTEXT(ctx); @@ -1350,9 +1479,10 @@ bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names) /* ID was reserved, but no real renderbuffer object made yet */ newRb = NULL; } - else if (!newRb && !allow_user_names) { + else if (!newRb && ctx->API == API_OPENGL_CORE) { /* All RB IDs must be Gen'd */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindRenderbuffer(non-gen name)"); return; } @@ -1375,33 +1505,59 @@ bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names) void GLAPIENTRY _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) { - GET_CURRENT_CONTEXT(ctx); - /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same * entry point, but they allow the use of user-generated names. */ - bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx)); + bind_renderbuffer(target, renderbuffer); } void GLAPIENTRY _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) { - /* This function should not be in the dispatch table for core profile / - * OpenGL 3.1, so execution should never get here in those cases -- no - * need for an explicit test. - */ - bind_renderbuffer(target, renderbuffer, true); + bind_renderbuffer(target, renderbuffer); } /** - * ARB_framebuffer_no_attachment - Application passes requested param's - * here. NOTE: NumSamples requested need not be _NumSamples which is - * what the hw supports. + * ARB_framebuffer_no_attachment and ARB_sample_locations - 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) { + bool cannot_be_winsys_fbo = false; + + switch (pname) { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + case GL_FRAMEBUFFER_DEFAULT_LAYERS: + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + if (!ctx->Extensions.ARB_framebuffer_no_attachments) + goto invalid_pname_enum; + cannot_be_winsys_fbo = true; + break; + case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: + case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: + if (!ctx->Extensions.ARB_sample_locations) + goto invalid_pname_enum; + break; + case GL_FRAMEBUFFER_FLIP_Y_MESA: + if (!ctx->Extensions.MESA_framebuffer_flip_y) + goto invalid_pname_enum; + cannot_be_winsys_fbo = true; + break; + default: + goto invalid_pname_enum; + } + + if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid pname=0x%x for default framebuffer)", func, pname); + return; + } + switch (pname) { case GL_FRAMEBUFFER_DEFAULT_WIDTH: if (param < 0 || param > ctx->Const.MaxFramebufferWidth) @@ -1438,13 +1594,65 @@ framebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb, case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: fb->DefaultGeometry.FixedSampleLocations = param; break; + case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: + fb->ProgrammableSampleLocations = !!param; + break; + case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: + fb->SampleLocationPixelGrid = !!param; + break; + case GL_FRAMEBUFFER_FLIP_Y_MESA: + fb->FlipY = param; + break; + } + + switch (pname) { + case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: + case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: + if (fb == ctx->DrawBuffer) + ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; + break; default: - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(pname=0x%x)", func, pname); + invalidate_framebuffer(fb); + ctx->NewState |= _NEW_BUFFERS; + break; } - invalidate_framebuffer(fb); - ctx->NewState |= _NEW_BUFFERS; + return; + +invalid_pname_enum: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); +} + +static bool +validate_framebuffer_parameter_extensions(GLenum pname, const char *func) +{ + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_framebuffer_no_attachments && + !ctx->Extensions.ARB_sample_locations && + !ctx->Extensions.MESA_framebuffer_flip_y) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s not supported " + "(none of ARB_framebuffer_no_attachments," + " ARB_sample_locations, or" + " MESA_framebuffer_flip_y extensions are available)", + func); + return false; + } + + /* + * If only the MESA_framebuffer_flip_y extension is enabled + * pname can only be GL_FRAMEBUFFER_FLIP_Y_MESA + */ + if (ctx->Extensions.MESA_framebuffer_flip_y && + pname != GL_FRAMEBUFFER_FLIP_Y_MESA && + !(ctx->Extensions.ARB_framebuffer_no_attachments || + ctx->Extensions.ARB_sample_locations)) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); + return false; + } + + return true; } void GLAPIENTRY @@ -1453,10 +1661,8 @@ _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)"); + if (!validate_framebuffer_parameter_extensions(pname, + "glFramebufferParameteri")) { return; } @@ -1467,20 +1673,92 @@ _mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param) return; } - /* check framebuffer binding */ - if (_mesa_is_winsys_fbo(fb)) { + framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri"); +} + +void GLAPIENTRY +_mesa_FramebufferParameteriMESA(GLenum target, GLenum pname, GLint param) +{ + _mesa_FramebufferParameteri(target, pname, param); +} + +static bool +validate_get_framebuffer_parameteriv_pname(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLuint pname, const char *func) +{ + bool cannot_be_winsys_fbo = true; + + switch (pname) { + 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); + return false; + } + break; + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + break; + 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: + /* 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 raises INVALID_OPERATION + * for any pname. + */ + cannot_be_winsys_fbo = !_mesa_is_desktop_gl(ctx); + break; + case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: + case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: + if (!ctx->Extensions.ARB_sample_locations) + goto invalid_pname_enum; + cannot_be_winsys_fbo = false; + break; + case GL_FRAMEBUFFER_FLIP_Y_MESA: + if (!ctx->Extensions.MESA_framebuffer_flip_y) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); + return false; + } + break; + default: + goto invalid_pname_enum; + } + + if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferParameteri"); - return; + "%s(invalid pname=0x%x for default framebuffer)", func, pname); + return false; } - framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri"); + return true; + +invalid_pname_enum: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); + return false; } static void get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, GLenum pname, GLint *params, const char *func) { + if (!validate_get_framebuffer_parameteriv_pname(ctx, fb, pname, func)) + return; + switch (pname) { case GL_FRAMEBUFFER_DEFAULT_WIDTH: *params = fb->DefaultGeometry.Width; @@ -1489,14 +1767,6 @@ get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, *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: @@ -1505,9 +1775,33 @@ get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, 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); + 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; + case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: + *params = fb->ProgrammableSampleLocations; + break; + case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: + *params = fb->SampleLocationPixelGrid; + break; + case GL_FRAMEBUFFER_FLIP_Y_MESA: + *params = fb->FlipY; + break; } } @@ -1517,10 +1811,8 @@ _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)"); + if (!validate_framebuffer_parameter_extensions(pname, + "glGetFramebufferParameteriv")) { return; } @@ -1531,17 +1823,15 @@ _mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params) 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"); } +void GLAPIENTRY +_mesa_GetFramebufferParameterivMESA(GLenum target, GLenum pname, GLint *params) +{ + _mesa_GetFramebufferParameteriv(target, pname, params); +} /** * Remove the specified renderbuffer or texture from any attachment point in @@ -1659,11 +1949,6 @@ create_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers, GLuint first; GLint i; - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func); - return; - } - if (!renderbuffers) return; @@ -1688,8 +1973,23 @@ create_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers, } +static void +create_render_buffers_err(struct gl_context *ctx, GLsizei n, + GLuint *renderbuffers, bool dsa) +{ + const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers"; + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func); + return; + } + + create_render_buffers(ctx, n, renderbuffers, dsa); +} + + void GLAPIENTRY -_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) +_mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers) { GET_CURRENT_CONTEXT(ctx); create_render_buffers(ctx, n, renderbuffers, false); @@ -1697,13 +1997,29 @@ _mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) void GLAPIENTRY -_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers) +_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) +{ + GET_CURRENT_CONTEXT(ctx); + create_render_buffers_err(ctx, n, renderbuffers, false); +} + + +void GLAPIENTRY +_mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers) { GET_CURRENT_CONTEXT(ctx); create_render_buffers(ctx, n, renderbuffers, true); } +void GLAPIENTRY +_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers) +{ + GET_CURRENT_CONTEXT(ctx); + create_render_buffers_err(ctx, n, renderbuffers, true); +} + + /** * Given an internal format token for a render buffer, return the * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, @@ -1720,7 +2036,7 @@ _mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers) * \return the base internal format, or 0 if internalFormat is illegal */ GLenum -_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) +_mesa_base_fbo_format(const struct gl_context *ctx, GLenum internalFormat) { /* * Notes: some formats such as alpha, luminance, etc. were added @@ -1776,8 +2092,10 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) case GL_RGBA: case GL_RGBA2: case GL_RGBA12: - case GL_RGBA16: return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0; + case GL_RGBA16: + return _mesa_is_desktop_gl(ctx) || _mesa_has_EXT_texture_norm16(ctx) + ? GL_RGBA : 0; case GL_RGB10_A2: case GL_SRGB8_ALPHA8_EXT: return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0; @@ -1812,39 +2130,56 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) ctx->Extensions.ARB_depth_buffer_float) ? GL_DEPTH_STENCIL : 0; case GL_RED: + return _mesa_has_ARB_texture_rg(ctx) ? GL_RED : 0; case GL_R16: - return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg + return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx) ? GL_RED : 0; case GL_R8: return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg ? GL_RED : 0; case GL_RG: + return _mesa_has_ARB_texture_rg(ctx) ? GL_RG : 0; case GL_RG16: - return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg + return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx) ? GL_RG : 0; case GL_RG8: return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg ? GL_RG : 0; /* signed normalized texture formats */ - case GL_RED_SNORM: case GL_R8_SNORM: + return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) + ? GL_RED : 0; + case GL_RED_SNORM: + return _mesa_has_EXT_texture_snorm(ctx) ? GL_RED : 0; case GL_R16_SNORM: - return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm + return _mesa_has_EXT_texture_snorm(ctx) || + (_mesa_has_EXT_render_snorm(ctx) && + _mesa_has_EXT_texture_norm16(ctx)) ? GL_RED : 0; - case GL_RG_SNORM: case GL_RG8_SNORM: + return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) + ? GL_RG : 0; + case GL_RG_SNORM: + return _mesa_has_EXT_texture_snorm(ctx) ? GL_RG : 0; case GL_RG16_SNORM: - return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm + return _mesa_has_EXT_texture_snorm(ctx) || + (_mesa_has_EXT_render_snorm(ctx) && + _mesa_has_EXT_texture_norm16(ctx)) ? GL_RG : 0; case GL_RGB_SNORM: case GL_RGB8_SNORM: case GL_RGB16_SNORM: return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm ? GL_RGB : 0; - case GL_RGBA_SNORM: case GL_RGBA8_SNORM: + return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) + ? GL_RGBA : 0; + case GL_RGBA_SNORM: + return _mesa_has_EXT_texture_snorm(ctx) ? GL_RGBA : 0; case GL_RGBA16_SNORM: - return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm + return _mesa_has_EXT_texture_snorm(ctx) || + (_mesa_has_EXT_render_snorm(ctx) && + _mesa_has_EXT_texture_norm16(ctx)) ? GL_RGBA : 0; case GL_ALPHA_SNORM: case GL_ALPHA8_SNORM: @@ -1892,6 +2227,9 @@ _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) ctx->Extensions.ARB_texture_float) || _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) ? GL_RGBA : 0; + case GL_RGB9_E5: + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_shared_exponent) + ? GL_RGB: 0; case GL_ALPHA16F_ARB: case GL_ALPHA32F_ARB: return ctx->API == API_OPENGL_COMPAT && @@ -2042,7 +2380,8 @@ invalidate_rb(GLuint key, void *data, void *userData) void _mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLsizei width, - GLsizei height, GLsizei samples) + GLsizei height, GLsizei samples, + GLsizei storageSamples) { const GLenum baseFormat = _mesa_base_fbo_format(ctx, internalFormat); @@ -2053,7 +2392,8 @@ _mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, if (samples != 0) { assert(samples > 0); assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER, - internalFormat, samples) == GL_NO_ERROR); + internalFormat, samples, + storageSamples) == GL_NO_ERROR); } FLUSH_VERTICES(ctx, _NEW_BUFFERS); @@ -2061,7 +2401,8 @@ _mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, if (rb->InternalFormat == internalFormat && rb->Width == (GLuint) width && rb->Height == (GLuint) height && - rb->NumSamples == samples) { + rb->NumSamples == samples && + rb->NumStorageSamples == storageSamples) { /* no change in allocation needed */ return; } @@ -2069,6 +2410,7 @@ _mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, /* These MUST get set by the AllocStorage func */ rb->Format = MESA_FORMAT_NONE; rb->NumSamples = samples; + rb->NumStorageSamples = storageSamples; /* Now allocate the storage */ assert(rb->AllocStorage); @@ -2089,6 +2431,7 @@ _mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, rb->InternalFormat = GL_NONE; rb->_BaseFormat = GL_NONE; rb->NumSamples = 0; + rb->NumStorageSamples = 0; } /* Invalidate the framebuffers the renderbuffer is attached in. */ @@ -2105,7 +2448,8 @@ _mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, static void renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLsizei width, - GLsizei height, GLsizei samples, const char *func) + GLsizei height, GLsizei samples, GLsizei storageSamples, + const char *func) { GLenum baseFormat; GLenum sample_count_error; @@ -2132,30 +2476,34 @@ renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, if (samples == NO_SAMPLES) { /* NumSamples == 0 indicates non-multisampling */ samples = 0; + storageSamples = 0; } else { /* check the sample count; * note: driver may choose to use more samples than what's requested */ sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER, - internalFormat, samples); + internalFormat, samples, storageSamples); /* 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) { + if (samples < 0 || storageSamples < 0) { sample_count_error = GL_INVALID_VALUE; } if (sample_count_error != GL_NO_ERROR) { - _mesa_error(ctx, sample_count_error, "%s(samples=%d)", func, samples); + _mesa_error(ctx, sample_count_error, + "%s(samples=%d, storageSamples=%d)", func, samples, + storageSamples); return; } } - _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples); + _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, + storageSamples); } /** @@ -2165,7 +2513,7 @@ renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, static void renderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei samples, - const char *func) + GLsizei storageSamples, const char *func) { GET_CURRENT_CONTEXT(ctx); @@ -2190,7 +2538,8 @@ renderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat, return; } - renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, func); + renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, + storageSamples, func); } /** @@ -2201,7 +2550,7 @@ renderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat, static void renderbuffer_storage_target(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei samples, - const char *func) + GLsizei storageSamples, const char *func) { GET_CURRENT_CONTEXT(ctx); @@ -2232,7 +2581,7 @@ renderbuffer_storage_target(GLenum target, GLenum internalFormat, } renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width, - height, samples, func); + height, samples, storageSamples, func); } @@ -2295,7 +2644,7 @@ _mesa_RenderbufferStorage(GLenum target, GLenum internalFormat, * a token value here just for error reporting purposes. */ renderbuffer_storage_target(target, internalFormat, width, height, - NO_SAMPLES, "glRenderbufferStorage"); + NO_SAMPLES, 0, "glRenderbufferStorage"); } @@ -2305,7 +2654,19 @@ _mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLsizei width, GLsizei height) { renderbuffer_storage_target(target, internalFormat, width, height, - samples, "glRenderbufferStorageMultisample"); + samples, samples, + "glRenderbufferStorageMultisample"); +} + + +void GLAPIENTRY +_mesa_RenderbufferStorageMultisampleAdvancedAMD( + GLenum target, GLsizei samples, GLsizei storageSamples, + GLenum internalFormat, GLsizei width, GLsizei height) +{ + renderbuffer_storage_target(target, internalFormat, width, height, + samples, storageSamples, + "glRenderbufferStorageMultisampleAdvancedAMD"); } @@ -2326,7 +2687,7 @@ _es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, break; } - renderbuffer_storage_target(target, internalFormat, width, height, 0, + renderbuffer_storage_target(target, internalFormat, width, height, 0, 0, "glRenderbufferStorageEXT"); } @@ -2339,20 +2700,66 @@ _mesa_NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, * a token value here just for error reporting purposes. */ renderbuffer_storage_named(renderbuffer, internalformat, width, height, - NO_SAMPLES, "glNamedRenderbufferStorage"); + NO_SAMPLES, 0, "glNamedRenderbufferStorage"); +} + +void GLAPIENTRY +_mesa_NamedRenderbufferStorageEXT(GLuint renderbuffer, GLenum internalformat, + GLsizei width, GLsizei height) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (!rb || rb == &DummyRenderbuffer) { + _mesa_HashLockMutex(ctx->Shared->RenderBuffers); + rb = allocate_renderbuffer_locked(ctx, renderbuffer, "glNamedRenderbufferStorageEXT"); + _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); + } + renderbuffer_storage(ctx, rb, internalformat, width, height, NO_SAMPLES, + 0, "glNamedRenderbufferStorageEXT"); } + void GLAPIENTRY _mesa_NamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { renderbuffer_storage_named(renderbuffer, internalformat, width, height, - samples, + samples, samples, "glNamedRenderbufferStorageMultisample"); } +void GLAPIENTRY +_mesa_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples, + GLenum internalformat, + GLsizei width, GLsizei height) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (!rb || rb == &DummyRenderbuffer) { + _mesa_HashLockMutex(ctx->Shared->RenderBuffers); + rb = allocate_renderbuffer_locked(ctx, renderbuffer, + "glNamedRenderbufferStorageMultisampleEXT"); + _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); + } + renderbuffer_storage(ctx, rb, internalformat, width, height, + samples, samples, + "glNamedRenderbufferStorageMultisample"); +} + + +void GLAPIENTRY +_mesa_NamedRenderbufferStorageMultisampleAdvancedAMD( + GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, + GLenum internalformat, GLsizei width, GLsizei height) +{ + renderbuffer_storage_named(renderbuffer, internalformat, width, height, + samples, storageSamples, + "glNamedRenderbufferStorageMultisampleAdvancedAMD"); +} + + static void get_render_buffer_parameteriv(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum pname, @@ -2379,19 +2786,24 @@ get_render_buffer_parameteriv(struct gl_context *ctx, case GL_RENDERBUFFER_DEPTH_SIZE_EXT: case GL_RENDERBUFFER_STENCIL_SIZE_EXT: *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); - break; + return; case GL_RENDERBUFFER_SAMPLES: if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object) || _mesa_is_gles3(ctx)) { *params = rb->NumSamples; - break; + return; } - /* fallthrough */ - default: - _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func, - _mesa_enum_to_string(pname)); - return; + break; + case GL_RENDERBUFFER_STORAGE_SAMPLES_AMD: + if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { + *params = rb->NumStorageSamples; + return; + } + break; } + + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func, + _mesa_enum_to_string(pname)); } @@ -2436,6 +2848,24 @@ _mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, } +void GLAPIENTRY +_mesa_GetNamedRenderbufferParameterivEXT(GLuint renderbuffer, GLenum pname, + GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + + struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (!rb || rb == &DummyRenderbuffer) { + _mesa_HashLockMutex(ctx->Shared->RenderBuffers); + rb = allocate_renderbuffer_locked(ctx, renderbuffer, "glGetNamedRenderbufferParameterivEXT"); + _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); + } + + get_render_buffer_parameteriv(ctx, rb, pname, params, + "glGetNamedRenderbufferParameterivEXT"); +} + + GLboolean GLAPIENTRY _mesa_IsFramebuffer(GLuint framebuffer) { @@ -2500,7 +2930,7 @@ check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) static void -bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names) +bind_framebuffer(GLenum target, GLuint framebuffer) { struct gl_framebuffer *newDrawFb, *newReadFb; GLboolean bindReadBuf, bindDrawBuf; @@ -2531,9 +2961,10 @@ bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names) /* ID was reserved, but no real framebuffer object made yet */ newDrawFb = NULL; } - else if (!newDrawFb && !allow_user_names) { + else if (!newDrawFb && ctx->API == API_OPENGL_CORE) { /* All FBO IDs must be Gen'd */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindFramebuffer(non-gen name)"); return; } @@ -2597,6 +3028,7 @@ _mesa_bind_framebuffers(struct gl_context *ctx, if (bindDrawBuf) { FLUSH_VERTICES(ctx, _NEW_BUFFERS); + ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; /* check if old framebuffer had any texture attachments */ if (oldDrawFb) @@ -2606,6 +3038,7 @@ _mesa_bind_framebuffers(struct gl_context *ctx, check_begin_texture_render(ctx, newDrawFb); _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); + _mesa_update_allow_draw_out_of_order(ctx); } if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { @@ -2621,23 +3054,17 @@ _mesa_bind_framebuffers(struct gl_context *ctx, void GLAPIENTRY _mesa_BindFramebuffer(GLenum target, GLuint framebuffer) { - GET_CURRENT_CONTEXT(ctx); - /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry * point, but they allow the use of user-generated names. */ - bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx)); + bind_framebuffer(target, framebuffer); } void GLAPIENTRY _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) { - /* This function should not be in the dispatch table for core profile / - * OpenGL 3.1, so execution should never get here in those cases -- no - * need for an explicit test. - */ - bind_framebuffer(target, framebuffer, true); + bind_framebuffer(target, framebuffer); } @@ -2776,6 +3203,16 @@ _mesa_check_framebuffer_status(struct gl_context *ctx, } +GLenum GLAPIENTRY +_mesa_CheckFramebufferStatus_no_error(GLenum target) +{ + GET_CURRENT_CONTEXT(ctx); + + struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); + return _mesa_check_framebuffer_status(ctx, fb); +} + + GLenum GLAPIENTRY _mesa_CheckFramebufferStatus(GLenum target) { @@ -2837,6 +3274,37 @@ _mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) } +GLenum GLAPIENTRY +_mesa_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target) +{ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + switch (target) { + case GL_DRAW_FRAMEBUFFER: + case GL_FRAMEBUFFER: + case GL_READ_FRAMEBUFFER: + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glCheckNamedFramebufferStatusEXT(invalid target %s)", + _mesa_enum_to_string(target)); + return 0; + } + + if (framebuffer == 0) { + return _mesa_CheckNamedFramebufferStatus(0, target); + } + + fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, + "glCheckNamedFramebufferStatusEXT"); + 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 @@ -2864,6 +3332,16 @@ reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, } +static struct gl_texture_object * +get_texture_for_framebuffer(struct gl_context *ctx, GLuint texture) +{ + if (!texture) + return NULL; + + return _mesa_lookup_texture(ctx, texture); +} + + /** * Common code called by gl*FramebufferTexture*() to retrieve the correct * texture object pointer. @@ -2874,9 +3352,9 @@ reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, * \return true if no errors, false if errors */ static bool -get_texture_for_framebuffer(struct gl_context *ctx, GLuint texture, - bool layered, const char *caller, - struct gl_texture_object **texObj) +get_texture_for_framebuffer_err(struct gl_context *ctx, GLuint texture, + bool layered, const char *caller, + struct gl_texture_object **texObj) { *texObj = NULL; /* This will get returned if texture = 0. */ @@ -2974,13 +3452,14 @@ check_texture_target(struct gl_context *ctx, GLenum target, 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. + /* GL_TEXTURE_CUBE_MAP is only allowed by OpenGL 4.5 here, which + * includes the DSA API. + * + * Because DSA is only enabled for GL 3.1+ and this can be called + * from _mesa_FramebufferTextureLayer in compatibility profile, + * we need to check the version. */ - return ctx->API == API_OPENGL_CORE; + return _mesa_is_desktop_gl(ctx) && ctx->Version >= 31; } _mesa_error(ctx, GL_INVALID_OPERATION, @@ -3085,8 +3564,7 @@ check_layer(struct gl_context *ctx, GLenum target, GLint layer, * and layer is negative." */ if (layer < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "%s(layer %u < 0)", caller, layer); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(layer %d < 0)", caller, layer); return false; } @@ -3128,11 +3606,19 @@ check_layer(struct gl_context *ctx, GLenum target, GLint layer, * \return true if no errors, false if errors */ static bool -check_level(struct gl_context *ctx, GLenum target, GLint level, - const char *caller) +check_level(struct gl_context *ctx, struct gl_texture_object *texObj, + GLenum target, GLint level, const char *caller) { - if ((level < 0) || - (level >= _mesa_max_texture_levels(ctx, target))) { + /* Section 9.2.8 of the OpenGL 4.6 specification says: + * + * "If texture refers to an immutable-format texture, level must be + * greater than or equal to zero and smaller than the value of + * TEXTURE_VIEW_NUM_LEVELS for texture." + */ + const int max_levels = texObj->Immutable ? texObj->ImmutableLevels : + _mesa_max_texture_levels(ctx, target); + + if (level < 0 || level >= max_levels) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid level %d)", caller, level); return false; @@ -3142,39 +3628,57 @@ 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, NULL); + 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_enum_to_string(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_renderbuffer_attachment *att, + struct gl_texture_object *texObj, GLenum textarget, + GLint level, GLsizei samples, + GLuint layer, GLboolean layered) +{ FLUSH_VERTICES(ctx, _NEW_BUFFERS); - mtx_lock(&fb->Mutex); + simple_mtx_lock(&fb->Mutex); if (texObj) { if (attachment == GL_DEPTH_ATTACHMENT && texObj == fb->Attachment[BUFFER_STENCIL].Texture && level == fb->Attachment[BUFFER_STENCIL].TextureLevel && _mesa_tex_target_to_face(textarget) == fb->Attachment[BUFFER_STENCIL].CubeMapFace && + samples == fb->Attachment[BUFFER_STENCIL].NumSamples && 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 @@ -3188,13 +3692,14 @@ _mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb, level == fb->Attachment[BUFFER_DEPTH].TextureLevel && _mesa_tex_target_to_face(textarget) == fb->Attachment[BUFFER_DEPTH].CubeMapFace && + samples == fb->Attachment[BUFFER_DEPTH].NumSamples && 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, layer, layered); + level, samples, layer, layered); if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { /* Above we created a new renderbuffer and attached it to the @@ -3227,22 +3732,48 @@ _mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb, invalidate_framebuffer(fb); - mtx_unlock(&fb->Mutex); + simple_mtx_unlock(&fb->Mutex); +} + + +static void +framebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint layer) +{ + GET_CURRENT_CONTEXT(ctx); + + /* Get the framebuffer object */ + struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); + + /* Get the texture object */ + struct gl_texture_object *texObj = + get_texture_for_framebuffer(ctx, texture); + + struct gl_renderbuffer_attachment *att = + get_attachment(ctx, fb, attachment, NULL); + + _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, + level, 0, layer, GL_FALSE); } static void -framebuffer_texture_with_dims(int dims, GLenum target, +framebuffer_texture_with_dims(int dims, GLenum target, GLuint framebuffer, GLenum attachment, GLenum textarget, - GLuint texture, GLint level, GLint layer, - const char *caller) + GLuint texture, GLint level, GLsizei samples, + GLint layer, const char *caller, bool dsa) { GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *fb; struct gl_texture_object *texObj; /* Get the framebuffer object */ - fb = get_framebuffer_target(ctx, target); + if (dsa) { + fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, caller); + } else { + fb = get_framebuffer_target(ctx, target); + } if (!fb) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller, _mesa_enum_to_string(target)); @@ -3250,7 +3781,7 @@ framebuffer_texture_with_dims(int dims, GLenum target, } /* Get the texture object */ - if (!get_texture_for_framebuffer(ctx, texture, false, caller, &texObj)) + if (!get_texture_for_framebuffer_err(ctx, texture, false, caller, &texObj)) return; if (texObj) { @@ -3260,12 +3791,27 @@ 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)) + if (!check_level(ctx, texObj, textarget, level, caller)) return; } - _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level, - layer, GL_FALSE, caller); + struct gl_renderbuffer_attachment *att = + _mesa_get_and_validate_attachment(ctx, fb, attachment, caller); + if (!att) + return; + + _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, + level, samples, layer, GL_FALSE); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture1D_no_error(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level) +{ + framebuffer_texture_with_dims_no_error(target, attachment, textarget, + texture, level, 0); } @@ -3273,8 +3819,18 @@ 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"); + framebuffer_texture_with_dims(1, target, 0, attachment, textarget, texture, + level, 0, 0, "glFramebufferTexture1D", false); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture2D_no_error(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level) +{ + framebuffer_texture_with_dims_no_error(target, attachment, textarget, + texture, level, 0); } @@ -3282,8 +3838,30 @@ 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"); + framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture, + level, 0, 0, "glFramebufferTexture2D", false); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLsizei samples) +{ + framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture, + level, samples, 0, + "glFramebufferTexture2DMultisampleEXT", + false); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint layer) +{ + framebuffer_texture_with_dims_no_error(target, attachment, textarget, + texture, level, layer); } @@ -3292,96 +3870,145 @@ _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"); + framebuffer_texture_with_dims(3, target, 0, attachment, textarget, texture, + level, 0, layer, "glFramebufferTexture3D", false); } -void GLAPIENTRY -_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer) +static ALWAYS_INLINE void +frame_buffer_texture(GLuint framebuffer, GLenum target, + GLenum attachment, GLuint texture, + GLint level, GLint layer, const char *func, + bool dsa, bool no_error, bool check_layered) { GET_CURRENT_CONTEXT(ctx); - struct gl_framebuffer *fb; - struct gl_texture_object *texObj; - GLenum textarget = 0; + GLboolean layered = GL_FALSE; - const char *func = "glFramebufferTextureLayer"; + if (!no_error && check_layered) { + if (!_mesa_has_geometry_shaders(ctx)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "unsupported function (%s) called", func); + return; + } + } /* 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; + struct gl_framebuffer *fb; + if (no_error) { + if (dsa) { + fb = _mesa_lookup_framebuffer(ctx, framebuffer); + } else { + fb = get_framebuffer_target(ctx, target); + } + } else { + if (dsa) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); + if (!fb) + return; + } else { + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", + func, _mesa_enum_to_string(target)); + return; + } + } } - /* 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)) + /* Get the texture object and framebuffer attachment*/ + struct gl_renderbuffer_attachment *att; + struct gl_texture_object *texObj; + if (no_error) { + texObj = get_texture_for_framebuffer(ctx, texture); + att = get_attachment(ctx, fb, attachment, NULL); + } else { + if (!get_texture_for_framebuffer_err(ctx, texture, check_layered, func, + &texObj)) return; - if (!check_layer(ctx, texObj->Target, layer, func)) + att = _mesa_get_and_validate_attachment(ctx, fb, attachment, func); + if (!att) return; + } - if (!check_level(ctx, texObj->Target, level, func)) - return; + GLenum textarget = 0; + if (texObj) { + if (check_layered) { + /* We do this regardless of no_error because this sets layered */ + if (!check_layered_texture_target(ctx, texObj->Target, func, + &layered)) + return; + } + + if (!no_error) { + if (!check_layered) { + if (!check_texture_target(ctx, texObj->Target, func)) + return; - if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + if (!check_layer(ctx, texObj->Target, layer, func)) + return; + } + + if (!check_level(ctx, texObj, texObj->Target, level, func)) + return; + } + + if (!check_layered && texObj->Target == GL_TEXTURE_CUBE_MAP) { assert(layer >= 0 && layer < 6); textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; layer = 0; } } - _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level, - layer, GL_FALSE, func); + _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, + level, 0, layer, layered); } - void GLAPIENTRY -_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, - GLuint texture, GLint level, GLint layer) +_mesa_FramebufferTextureLayer_no_error(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; - - const char *func = "glNamedFramebufferTextureLayer"; + frame_buffer_texture(0, target, attachment, texture, level, layer, + "glFramebufferTextureLayer", false, true, false); +} - /* 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, false, func, &texObj)) - return; +void GLAPIENTRY +_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + frame_buffer_texture(0, target, attachment, texture, level, layer, + "glFramebufferTextureLayer", false, false, false); +} - if (texObj) { - if (!check_texture_target(ctx, texObj->Target, func)) - return; - if (!check_layer(ctx, texObj->Target, layer, func)) - return; +void GLAPIENTRY +_mesa_NamedFramebufferTextureLayer_no_error(GLuint framebuffer, + GLenum attachment, + GLuint texture, GLint level, + GLint layer) +{ + frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer, + "glNamedFramebufferTextureLayer", true, true, false); +} - 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; - } - } +void GLAPIENTRY +_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer, + "glNamedFramebufferTextureLayer", true, false, false); +} - _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level, - layer, GL_FALSE, func); + +void GLAPIENTRY +_mesa_FramebufferTexture_no_error(GLenum target, GLenum attachment, + GLuint texture, GLint level) +{ + frame_buffer_texture(0, target, attachment, texture, level, 0, + "glFramebufferTexture", false, true, true); } @@ -3389,42 +4016,16 @@ 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; - } + frame_buffer_texture(0, target, attachment, texture, level, 0, + "glFramebufferTexture", false, false, true); +} - _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level, - 0, layered, func); +void GLAPIENTRY +_mesa_NamedFramebufferTexture_no_error(GLuint framebuffer, GLenum attachment, + GLuint texture, GLint level) +{ + frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0, + "glNamedFramebufferTexture", true, true, true); } @@ -3432,39 +4033,39 @@ 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"; + frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0, + "glNamedFramebufferTexture", true, false, true); +} - 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; +void GLAPIENTRY +_mesa_NamedFramebufferTexture1DEXT(GLuint framebuffer, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + framebuffer_texture_with_dims(1, GL_FRAMEBUFFER, framebuffer, attachment, + textarget, texture, level, 0, 0, + "glNamedFramebufferTexture1DEXT", true); +} - /* 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; +void GLAPIENTRY +_mesa_NamedFramebufferTexture2DEXT(GLuint framebuffer, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + framebuffer_texture_with_dims(2, GL_FRAMEBUFFER, framebuffer, attachment, + textarget, texture, level, 0, 0, + "glNamedFramebufferTexture2DEXT", true); +} - if (!check_level(ctx, texObj->Target, level, func)) - return; - } - _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level, - 0, layered, func); +void GLAPIENTRY +_mesa_NamedFramebufferTexture3DEXT(GLuint framebuffer, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint zoffset) +{ + framebuffer_texture_with_dims(3, GL_FRAMEBUFFER, framebuffer, attachment, + textarget, texture, level, 0, zoffset, + "glNamedFramebufferTexture3DEXT", true); } @@ -3487,51 +4088,121 @@ _mesa_framebuffer_renderbuffer(struct gl_context *ctx, _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) +static ALWAYS_INLINE void +framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment, GLenum renderbuffertarget, + GLuint renderbuffer, const char *func, bool no_error) { struct gl_renderbuffer_attachment *att; + struct gl_renderbuffer *rb; + bool is_color_attachment; - if (_mesa_is_winsys_fbo(fb)) { - /* Can't attach new renderbuffers to a window system framebuffer */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(window-system framebuffer)", func); + if (!no_error && renderbuffertarget != GL_RENDERBUFFER) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(renderbuffertarget is not GL_RENDERBUFFER)", func); return; } - att = get_attachment(ctx, fb, attachment, NULL); - if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(invalid attachment %s)", func, - _mesa_enum_to_string(attachment)); - return; + if (renderbuffer) { + if (!no_error) { + rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func); + if (!rb) + return; + } else { + rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + } + } 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) { + if (!no_error) { + if (_mesa_is_winsys_fbo(fb)) { + /* Can't attach new renderbuffers to a window system framebuffer */ _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(renderbuffer is not DEPTH_STENCIL format)", func); + "%s(window-system framebuffer)", func); return; } + + att = get_attachment(ctx, fb, attachment, &is_color_attachment); + if (att == NULL) { + /* + * 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; + } + + 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); } +static void +framebuffer_renderbuffer_error(struct gl_context *ctx, + struct gl_framebuffer *fb, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer, const char *func) +{ + framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget, + renderbuffer, func, false); +} + +static void +framebuffer_renderbuffer_no_error(struct gl_context *ctx, + struct gl_framebuffer *fb, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer, const char *func) +{ + framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget, + renderbuffer, func, true); +} + +void GLAPIENTRY +_mesa_FramebufferRenderbuffer_no_error(GLenum target, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) +{ + GET_CURRENT_CONTEXT(ctx); + + struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); + framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget, + renderbuffer, "glFramebufferRenderbuffer"); +} + void GLAPIENTRY _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { struct gl_framebuffer *fb; - struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); fb = get_framebuffer_target(ctx, target); @@ -3542,36 +4213,30 @@ _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, return; } - if (renderbuffertarget != GL_RENDERBUFFER) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbuffer(renderbuffertarget is not " - "GL_RENDERBUFFER)"); - return; - } + framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, + renderbuffer, "glFramebufferRenderbuffer"); +} - if (renderbuffer) { - rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, - "glFramebufferRenderbuffer"); - if (!rb) - return; - } - else { - /* remove renderbuffer attachment */ - rb = NULL; - } +void GLAPIENTRY +_mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) +{ + GET_CURRENT_CONTEXT(ctx); - framebuffer_renderbuffer(ctx, fb, attachment, rb, - "glFramebufferRenderbuffer"); + struct gl_framebuffer *fb = _mesa_lookup_framebuffer(ctx, framebuffer); + framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget, + renderbuffer, + "glNamedFramebufferRenderbuffer"); } - 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, @@ -3579,36 +4244,39 @@ _mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, if (!fb) return; - if (renderbuffertarget != GL_RENDERBUFFER) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glNamedFramebufferRenderbuffer(renderbuffertarget is not " - "GL_RENDERBUFFER)"); - return; - } + framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, + renderbuffer, + "glNamedFramebufferRenderbuffer"); +} - if (renderbuffer) { - rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, - "glNamedFramebufferRenderbuffer"); - if (!rb) - return; - } - else { - /* remove renderbuffer attachment */ - rb = NULL; - } - framebuffer_renderbuffer(ctx, fb, attachment, rb, - "glNamedFramebufferRenderbuffer"); +void GLAPIENTRY +_mesa_NamedFramebufferRenderbufferEXT(GLuint framebuffer, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) +{ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, + "glNamedFramebufferRenderbufferEXT"); + if (!fb) + return; + + framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, + renderbuffer, + "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 code for an attachment type of GL_NONE differs between APIs. @@ -3672,16 +4340,31 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, } /* 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, NULL); + att = get_attachment(ctx, buffer, attachment, &is_color_attachment); } if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, - _mesa_enum_to_string(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; } @@ -3719,11 +4402,13 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, * 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) && - ((attachment != GL_DEPTH && attachment != GL_STENCIL) || - (att->Type != GL_NONE))) - ? GL_FRAMEBUFFER_DEFAULT : 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) { @@ -3805,9 +4490,9 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, } } else { - if (ctx->Extensions.EXT_framebuffer_sRGB) { - *params = - _mesa_get_format_color_encoding(att->Renderbuffer->Format); + if (ctx->Extensions.EXT_sRGB) { + *params = (_mesa_is_format_srgb(att->Renderbuffer->Format) ? + GL_SRGB : GL_LINEAR); } else { /* According to ARB_framebuffer_sRGB, we should return LINEAR @@ -3875,10 +4560,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_enum_to_string(pname)); - } else if (att->Texture) { const struct gl_texture_image *texImage = _mesa_select_tex_image(att->Texture, att->Texture->Target, @@ -3896,7 +4577,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: @@ -3911,6 +4594,18 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, goto invalid_pname_enum; } return; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT: + if (!ctx->Extensions.EXT_multisampled_render_to_texture) { + goto invalid_pname_enum; + } else if (att->Type == GL_TEXTURE) { + *params = att->NumSamples; + } else if (att->Type == GL_NONE) { + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_enum_to_string(pname)); + } else { + goto invalid_pname_enum; + } + return; default: goto invalid_pname_enum; } @@ -3939,8 +4634,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, return; } - _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, - params, + get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, + params, "glGetFramebufferAttachmentParameteriv"); } @@ -3969,12 +4664,42 @@ _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"); } +void GLAPIENTRY +_mesa_GetNamedFramebufferAttachmentParameterivEXT(GLuint framebuffer, + GLenum attachment, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *buffer; + + if (framebuffer) { + buffer = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, + "glGetNamedFramebufferAttachmentParameterivEXT"); + 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; + } + + get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, + params, + "glGetNamedFramebufferAttachmentParameterivEXT"); +} + + void GLAPIENTRY _mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GLint param) @@ -3982,15 +4707,21 @@ _mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *fb = NULL; - if (!ctx->Extensions.ARB_framebuffer_no_attachments) { + if (!ctx->Extensions.ARB_framebuffer_no_attachments && + !ctx->Extensions.ARB_sample_locations) { _mesa_error(ctx, GL_INVALID_OPERATION, "glNamedFramebufferParameteri(" - "ARB_framebuffer_no_attachments not implemented)"); + "neither ARB_framebuffer_no_attachments nor " + "ARB_sample_locations is available)"); return; } - fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, - "glNamedFramebufferParameteri"); + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glNamedFramebufferParameteri"); + } else { + fb = ctx->WinSysDrawBuffer; + } if (fb) { framebuffer_parameteri(ctx, fb, pname, param, @@ -3999,6 +4730,104 @@ _mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, } +/* Helper function for ARB_framebuffer_no_attachments functions interacting with EXT_direct_state_access */ +static struct gl_framebuffer * +lookup_named_framebuffer_ext_dsa(struct gl_context *ctx, GLuint framebuffer, const char* caller) +{ + struct gl_framebuffer *fb = NULL; + + if (framebuffer) { + /* The ARB_framebuffer_no_attachments spec says: + * + * "The error INVALID_VALUE is generated if is not + * a name returned by GenFramebuffers. If a framebuffer object + * named does not yet exist, it will be created." + * + * This is different from the EXT_direct_state_access spec which says: + * + * "If the framebuffer object named by the framebuffer parameter has not + * been previously bound or has been deleted since the last binding, + * the GL first creates a new state vector in the same manner as when + * BindFramebuffer creates a new framebuffer object" + * + * So first we verify that the name exists. + */ + fb = _mesa_lookup_framebuffer(ctx, framebuffer); + if (!fb) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(frameBuffer)", caller); + return NULL; + } + /* Then, make sure it's initialized */ + if (fb == &DummyFramebuffer) { + fb = ctx->Driver.NewFramebuffer(ctx, framebuffer); + _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, fb); + } + } + else + fb = ctx->WinSysDrawBuffer; + + return fb; +} + + +void GLAPIENTRY +_mesa_NamedFramebufferParameteriEXT(GLuint framebuffer, GLenum pname, + GLint param) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb = + lookup_named_framebuffer_ext_dsa(ctx, framebuffer, + "glNamedFramebufferParameteriEXT"); + + if (!fb) + return; + + framebuffer_parameteri(ctx, fb, pname, param, + "glNamedFramebufferParameteriEXT"); +} + + +void GLAPIENTRY +_mesa_GetFramebufferParameterivEXT(GLuint framebuffer, GLenum pname, + GLint *param) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + + if (framebuffer) + fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, + "glGetFramebufferParameterivEXT"); + else + fb = ctx->WinSysDrawBuffer; + + if (fb) { + /* The GL_EXT_direct_state_access says: + * + * The pname parameter must be one of framebuffer dependent values + * listed in either table 4.nnn (namely DRAW_BUFFER, READ_BUFFER, + * or DRAW_BUFFER0 through DRAW_BUFFER15). + */ + if (pname == GL_DRAW_BUFFER) { + *param = fb->ColorDrawBuffer[0]; + + } + else if (pname == GL_READ_BUFFER) { + *param = fb->ColorReadBuffer; + } + else if (GL_DRAW_BUFFER0 <= pname && pname <= GL_DRAW_BUFFER15) { + unsigned buffer = pname - GL_DRAW_BUFFER0; + if (buffer < ARRAY_SIZE(fb->ColorDrawBuffer)) + *param = fb->ColorDrawBuffer[buffer]; + else + _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferParameterivEXT(pname)"); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferParameterivEXT(pname)"); + } + } +} + + void GLAPIENTRY _mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, GLint *param) @@ -4009,16 +4838,16 @@ _mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, if (!ctx->Extensions.ARB_framebuffer_no_attachments) { _mesa_error(ctx, GL_INVALID_OPERATION, "glNamedFramebufferParameteriv(" - "ARB_framebuffer_no_attachments not implemented)"); + "neither ARB_framebuffer_no_attachments nor ARB_sample_locations" + " is available)"); return; } - if (framebuffer) { + if (framebuffer) fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, "glGetNamedFramebufferParameteriv"); - } else { + else fb = ctx->WinSysDrawBuffer; - } if (fb) { get_framebuffer_parameteriv(ctx, fb, pname, param, @@ -4027,6 +4856,23 @@ _mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, } +void GLAPIENTRY +_mesa_GetNamedFramebufferParameterivEXT(GLuint framebuffer, GLenum pname, + GLint *param) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb = + lookup_named_framebuffer_ext_dsa(ctx, framebuffer, + "glGetNamedFramebufferParameterivEXT"); + + if (!fb) + return; + + get_framebuffer_parameteriv(ctx, fb, pname, param, + "glGetNamedFramebufferParameterivEXT"); +} + + static void invalidate_framebuffer_storage(struct gl_context *ctx, struct gl_framebuffer *fb, @@ -4156,6 +5002,97 @@ invalid_enum: return; } +static struct gl_renderbuffer_attachment * +get_fb_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, + const GLenum attachment) +{ + switch (attachment) { + case GL_COLOR: + return &fb->Attachment[BUFFER_BACK_LEFT]; + case GL_COLOR_ATTACHMENT0: + case GL_COLOR_ATTACHMENT1: + case GL_COLOR_ATTACHMENT2: + case GL_COLOR_ATTACHMENT3: + case GL_COLOR_ATTACHMENT4: + case GL_COLOR_ATTACHMENT5: + case GL_COLOR_ATTACHMENT6: + case GL_COLOR_ATTACHMENT7: + case GL_COLOR_ATTACHMENT8: + case GL_COLOR_ATTACHMENT9: + case GL_COLOR_ATTACHMENT10: + case GL_COLOR_ATTACHMENT11: + case GL_COLOR_ATTACHMENT12: + case GL_COLOR_ATTACHMENT13: + case GL_COLOR_ATTACHMENT14: + case GL_COLOR_ATTACHMENT15: { + const unsigned i = attachment - GL_COLOR_ATTACHMENT0; + if (i >= ctx->Const.MaxColorAttachments) + return NULL; + assert(BUFFER_COLOR0 + i < ARRAY_SIZE(fb->Attachment)); + return &fb->Attachment[BUFFER_COLOR0 + i]; + } + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + case GL_DEPTH_STENCIL_ATTACHMENT: + return &fb->Attachment[BUFFER_DEPTH]; + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + return &fb->Attachment[BUFFER_STENCIL]; + default: + return NULL; + } +} + +static void +discard_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLsizei numAttachments, const GLenum *attachments) +{ + if (!ctx->Driver.DiscardFramebuffer) + return; + + for (int i = 0; i < numAttachments; i++) { + struct gl_renderbuffer_attachment *att = + get_fb_attachment(ctx, fb, attachments[i]); + + if (!att) + continue; + + /* If we're asked to invalidate just depth or just stencil, but the + * attachment is packed depth/stencil, then we can only use + * Driver.DiscardFramebuffer if the attachments list includes both depth + * and stencil and they both point at the same renderbuffer. + */ + if ((attachments[i] == GL_DEPTH_ATTACHMENT || + attachments[i] == GL_STENCIL_ATTACHMENT) && + (!att->Renderbuffer || + att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL)) { + GLenum other_format = (attachments[i] == GL_DEPTH_ATTACHMENT ? + GL_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT); + bool has_both = false; + for (int j = 0; j < numAttachments; j++) { + if (attachments[j] == other_format) { + has_both = true; + break; + } + } + + if (fb->Attachment[BUFFER_DEPTH].Renderbuffer != + fb->Attachment[BUFFER_STENCIL].Renderbuffer || !has_both) + continue; + } + + ctx->Driver.DiscardFramebuffer(ctx, fb, att); + } +} + +void GLAPIENTRY +_mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments, + const GLenum *attachments, GLint x, + GLint y, GLsizei width, GLsizei height) +{ + /* no-op */ +} + void GLAPIENTRY _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, @@ -4207,6 +5144,20 @@ _mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, "glInvalidateNamedFramebufferSubData"); } +void GLAPIENTRY +_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments, + const GLenum *attachments) +{ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) + return; + + discard_framebuffer(ctx, fb, numAttachments, attachments); +} + void GLAPIENTRY _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, @@ -4240,6 +5191,8 @@ _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, ctx->Const.MaxViewportWidth, ctx->Const.MaxViewportHeight, "glInvalidateFramebuffer"); + + discard_framebuffer(ctx, fb, numAttachments, attachments); } @@ -4326,8 +5279,7 @@ _mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, } } - if (ctx->Driver.DiscardFramebuffer) - ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments); + discard_framebuffer(ctx, fb, numAttachments, attachments); return; @@ -4336,3 +5288,141 @@ invalid_enum: "glDiscardFramebufferEXT(attachment %s)", _mesa_enum_to_string(attachments[i])); } + +static void +sample_locations(struct gl_context *ctx, struct gl_framebuffer *fb, + GLuint start, GLsizei count, const GLfloat *v, bool no_error, + const char *name) +{ + GLsizei i; + + if (!no_error) { + if (!ctx->Extensions.ARB_sample_locations) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s not supported " + "(ARB_sample_locations not available)", name); + return; + } + + if (start + count > MAX_SAMPLE_LOCATION_TABLE_SIZE) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(start+size > sample location table size)", name); + return; + } + } + + if (!fb->SampleLocationTable) { + size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat); + fb->SampleLocationTable = malloc(size); + if (!fb->SampleLocationTable) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "Cannot allocate sample location table"); + return; + } + for (i = 0; i < MAX_SAMPLE_LOCATION_TABLE_SIZE * 2; i++) + fb->SampleLocationTable[i] = 0.5f; + } + + for (i = 0; i < count * 2; i++) { + /* The ARB_sample_locations spec says: + * + * Sample locations outside of [0,1] result in undefined + * behavior. + * + * To simplify driver implementations, we choose to clamp to + * [0,1] and change NaN into 0.5. + */ + if (isnan(v[i]) || v[i] < 0.0f || v[i] > 1.0f) { + static GLuint msg_id = 0; + static const char* msg = "Invalid sample location specified"; + _mesa_debug_get_id(&msg_id); + + _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_UNDEFINED, + msg_id, MESA_DEBUG_SEVERITY_HIGH, strlen(msg), msg); + } + + if (isnan(v[i])) + fb->SampleLocationTable[start * 2 + i] = 0.5f; + else + fb->SampleLocationTable[start * 2 + i] = SATURATE(v[i]); + } + + if (fb == ctx->DrawBuffer) + ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; +} + +void GLAPIENTRY +_mesa_FramebufferSampleLocationsfvARB(GLenum target, GLuint start, + GLsizei count, const GLfloat *v) +{ + struct gl_framebuffer *fb; + + GET_CURRENT_CONTEXT(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferSampleLocationsfvARB(target %s)", + _mesa_enum_to_string(target)); + return; + } + + sample_locations(ctx, fb, start, count, v, false, + "glFramebufferSampleLocationsfvARB"); +} + +void GLAPIENTRY +_mesa_NamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start, + GLsizei count, const GLfloat *v) +{ + struct gl_framebuffer *fb; + + GET_CURRENT_CONTEXT(ctx); + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glNamedFramebufferSampleLocationsfvARB"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + sample_locations(ctx, fb, start, count, v, false, + "glNamedFramebufferSampleLocationsfvARB"); +} + +void GLAPIENTRY +_mesa_FramebufferSampleLocationsfvARB_no_error(GLenum target, GLuint start, + GLsizei count, const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + sample_locations(ctx, get_framebuffer_target(ctx, target), start, + count, v, true, "glFramebufferSampleLocationsfvARB"); +} + +void GLAPIENTRY +_mesa_NamedFramebufferSampleLocationsfvARB_no_error(GLuint framebuffer, + GLuint start, GLsizei count, + const GLfloat *v) +{ + GET_CURRENT_CONTEXT(ctx); + sample_locations(ctx, _mesa_lookup_framebuffer(ctx, framebuffer), start, + count, v, true, "glNamedFramebufferSampleLocationsfvARB"); +} + +void GLAPIENTRY +_mesa_EvaluateDepthValuesARB(void) +{ + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_sample_locations) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "EvaluateDepthValuesARB not supported (neither " + "ARB_sample_locations nor NV_sample_locations is available)"); + return; + } + + if (ctx->Driver.EvaluateDepthValues) + ctx->Driver.EvaluateDepthValues(ctx); +}