X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=c8735d0459ac297f1b06273a5aa26562605cf8b3;hb=HEAD;hp=5d7e5d29847dcfdbb23ea9dfc0f88fe579fc603b;hpb=67f40dadaa6666dacd90d1540eaadef20b9d48ba;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 5d7e5d29847..c8735d0459a 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -155,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; } @@ -266,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)) @@ -291,22 +322,24 @@ get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, { 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]; case GL_STENCIL: return &fb->Attachment[BUFFER_STENCIL]; + default: + unreachable("invalid attachment"); } } @@ -481,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)) @@ -496,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; @@ -519,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; @@ -673,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); @@ -728,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: @@ -741,8 +784,7 @@ is_format_color_renderable(const struct gl_context *ctx, mesa_format format, 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; @@ -968,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; @@ -992,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 @@ -1001,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; @@ -1045,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; @@ -1053,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++; @@ -1065,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) { @@ -1080,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); @@ -1087,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; @@ -1106,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); @@ -1120,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); @@ -1217,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) { @@ -1341,7 +1459,7 @@ allocate_renderbuffer_locked(struct gl_context *ctx, GLuint renderbuffer, 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); @@ -1361,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; } @@ -1386,22 +1505,16 @@ 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); } /** @@ -1430,6 +1543,11 @@ framebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb, 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; } @@ -1482,6 +1600,9 @@ framebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb, case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: fb->SampleLocationPixelGrid = !!param; break; + case GL_FRAMEBUFFER_FLIP_Y_MESA: + fb->FlipY = param; + break; } switch (pname) { @@ -1502,18 +1623,46 @@ 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 _mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param) { GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *fb; - if (!ctx->Extensions.ARB_framebuffer_no_attachments && - !ctx->Extensions.ARB_sample_locations) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferParameteriv not supported " - "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations" - " is available)"); + if (!validate_framebuffer_parameter_extensions(pname, + "glFramebufferParameteri")) { return; } @@ -1527,6 +1676,12 @@ _mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param) 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, @@ -1574,6 +1729,12 @@ validate_get_framebuffer_parameteriv_pname(struct gl_context *ctx, 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; } @@ -1638,6 +1799,9 @@ get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: *params = fb->SampleLocationPixelGrid; break; + case GL_FRAMEBUFFER_FLIP_Y_MESA: + *params = fb->FlipY; + break; } } @@ -1647,12 +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 && - !ctx->Extensions.ARB_sample_locations) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetFramebufferParameteriv not supported " - "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations" - " is available)"); + if (!validate_framebuffer_parameter_extensions(pname, + "glGetFramebufferParameteriv")) { return; } @@ -1667,6 +1827,11 @@ _mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *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 @@ -1927,8 +2092,10 @@ _mesa_base_fbo_format(const 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; @@ -1963,39 +2130,56 @@ _mesa_base_fbo_format(const 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: @@ -2196,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); @@ -2207,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); @@ -2215,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; } @@ -2223,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); @@ -2243,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. */ @@ -2259,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; @@ -2286,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); } /** @@ -2319,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); @@ -2344,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); } /** @@ -2355,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); @@ -2386,7 +2581,7 @@ renderbuffer_storage_target(GLenum target, GLenum internalFormat, } renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width, - height, samples, func); + height, samples, storageSamples, func); } @@ -2449,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"); } @@ -2459,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"); } @@ -2480,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"); } @@ -2493,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, @@ -2533,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)); } @@ -2590,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) { @@ -2654,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; @@ -2685,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; } @@ -2761,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) { @@ -2776,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); } @@ -3002,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 @@ -3149,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, @@ -3362,7 +3666,8 @@ _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, GLuint layer, GLboolean layered) + GLint level, GLsizei samples, + GLuint layer, GLboolean layered) { FLUSH_VERTICES(ctx, _NEW_BUFFERS); @@ -3373,6 +3678,7 @@ _mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb, 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 @@ -3386,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 @@ -3447,22 +3754,26 @@ framebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment, get_attachment(ctx, fb, attachment, NULL); _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, - level, layer, GL_FALSE); + 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)); @@ -3490,7 +3801,7 @@ framebuffer_texture_with_dims(int dims, GLenum target, return; _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, - level, layer, GL_FALSE); + level, samples, layer, GL_FALSE); } @@ -3508,8 +3819,8 @@ 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); } @@ -3527,8 +3838,20 @@ 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); } @@ -3547,8 +3870,8 @@ _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); } @@ -3638,7 +3961,7 @@ frame_buffer_texture(GLuint framebuffer, GLenum target, } _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, - level, layer, layered); + level, 0, layer, layered); } void GLAPIENTRY @@ -3715,6 +4038,37 @@ _mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, } +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); +} + + +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); +} + + +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); +} + + void _mesa_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, @@ -3896,6 +4250,25 @@ _mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, } +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"); +} + + static void get_framebuffer_attachment_parameter(struct gl_context *ctx, struct gl_framebuffer *buffer, @@ -4117,9 +4490,9 @@ 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 @@ -4221,6 +4594,18 @@ 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; } @@ -4285,6 +4670,36 @@ _mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, } +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) @@ -4315,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) @@ -4343,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, @@ -4472,6 +5002,88 @@ 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, @@ -4532,12 +5144,18 @@ _mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, "glInvalidateNamedFramebufferSubData"); } - void GLAPIENTRY _mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments, const GLenum *attachments) { - /* no-op */ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) + return; + + discard_framebuffer(ctx, fb, numAttachments, attachments); } @@ -4573,6 +5191,8 @@ _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, ctx->Const.MaxViewportWidth, ctx->Const.MaxViewportHeight, "glInvalidateFramebuffer"); + + discard_framebuffer(ctx, fb, numAttachments, attachments); } @@ -4659,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; @@ -4695,9 +5314,11 @@ sample_locations(struct gl_context *ctx, struct gl_framebuffer *fb, if (!fb->SampleLocationTable) { size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat); fb->SampleLocationTable = malloc(size); - if (!fb->SampleLocationTable) + 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; } @@ -4723,7 +5344,7 @@ sample_locations(struct gl_context *ctx, struct gl_framebuffer *fb, if (isnan(v[i])) fb->SampleLocationTable[start * 2 + i] = 0.5f; else - fb->SampleLocationTable[start * 2 + i] = CLAMP(v[i], 0.0f, 1.0f); + fb->SampleLocationTable[start * 2 + i] = SATURATE(v[i]); } if (fb == ctx->DrawBuffer)