X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=284990d7d003f29043caffe6ca08a26546b4ea83;hb=095515e16ca3cb2c9f1813b6602ee57ae28325a8;hp=88679215c2775e1bfe44acc527275a80c1f215d1;hpb=d90ced445c21b412c08928f0fc0af222021685f7;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 88679215c27..284990d7d00 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; @@ -330,6 +331,15 @@ 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]; @@ -471,6 +481,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)) @@ -549,7 +560,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 +586,7 @@ _mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, invalidate_framebuffer(fb); - mtx_unlock(&fb->Mutex); + simple_mtx_unlock(&fb->Mutex); } @@ -718,7 +729,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 +748,18 @@ 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: 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 +801,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 +872,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 +975,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; @@ -1032,6 +1054,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; @@ -1052,14 +1076,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 +1083,9 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); return; } + + attNumSamples = texImg->NumSamples; + attNumStorageSamples = texImg->NumSamples; } else if (att->Type == GL_RENDERBUFFER_EXT) { minWidth = MIN2(minWidth, att->Renderbuffer->Width); @@ -1077,14 +1096,6 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx, 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 +1104,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); @@ -1204,6 +1241,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) { @@ -1392,14 +1474,45 @@ _mesa_BindRenderbufferEXT(GLenum target, GLuint 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; + 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) @@ -1436,13 +1549,33 @@ 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); } void GLAPIENTRY @@ -1451,10 +1584,12 @@ _mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param) GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *fb; - 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, "glFramebufferParameteriv not supported " - "(ARB_framebuffer_no_attachments not implemented)"); + "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations" + " is available)"); return; } @@ -1465,56 +1600,85 @@ _mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param) return; } - /* check framebuffer binding */ - if (_mesa_is_winsys_fbo(fb)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferParameteri"); - return; - } - framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri"); } static bool -_pname_valid_for_default_framebuffer(struct gl_context *ctx, - GLenum pname) +validate_get_framebuffer_parameteriv_pname(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLuint pname, const char *func) { - if (!_mesa_is_desktop_gl(ctx)) - return false; + 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: - return true; + /* 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, + "%s(invalid pname=0x%x for default framebuffer)", func, pname); return false; } + + 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) { - /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries: - * - * "An INVALID_OPERATION error is generated by GetFramebufferParameteriv - * if the default framebuffer is bound to target and pname is not one - * of the accepted values from table 23.73, other than - * SAMPLE_POSITION." - * - * For OpenGL ES, using default framebuffer still raises INVALID_OPERATION - * for any pname. - */ - if (_mesa_is_winsys_fbo(fb) && - !_pname_valid_for_default_framebuffer(ctx, pname)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(invalid pname=0x%x for default framebuffer)", func, pname); + if (!validate_get_framebuffer_parameteriv_pname(ctx, fb, pname, func)) return; - } switch (pname) { case GL_FRAMEBUFFER_DEFAULT_WIDTH: @@ -1524,14 +1688,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: @@ -1558,9 +1714,15 @@ get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, case GL_STEREO: *params = fb->Visual.stereoMode; break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(pname=0x%x)", func, pname); + 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; } } @@ -1570,10 +1732,12 @@ _mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params) GET_CURRENT_CONTEXT(ctx); struct gl_framebuffer *fb; - 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, "glGetFramebufferParameteriv not supported " - "(ARB_framebuffer_no_attachments not implemented)"); + "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations" + " is available)"); return; } @@ -1705,11 +1869,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; @@ -1734,8 +1893,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); @@ -1743,13 +1917,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, @@ -1766,7 +1956,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 @@ -1822,8 +2012,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; @@ -1858,39 +2050,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: + _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: @@ -1938,6 +2147,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 && @@ -2088,7 +2300,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); @@ -2099,7 +2312,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); @@ -2107,7 +2321,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; } @@ -2115,6 +2330,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); @@ -2135,6 +2351,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. */ @@ -2151,7 +2368,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; @@ -2178,30 +2396,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); } /** @@ -2211,7 +2433,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); @@ -2236,7 +2458,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); } /** @@ -2247,7 +2470,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); @@ -2278,7 +2501,7 @@ renderbuffer_storage_target(GLenum target, GLenum internalFormat, } renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width, - height, samples, func); + height, samples, storageSamples, func); } @@ -2341,7 +2564,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"); } @@ -2351,7 +2574,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"); } @@ -2372,7 +2607,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"); } @@ -2385,7 +2620,7 @@ _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 @@ -2394,11 +2629,22 @@ _mesa_NamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples, GLsizei width, GLsizei height) { renderbuffer_storage_named(renderbuffer, internalformat, width, height, - samples, + 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, @@ -2425,19 +2671,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)); } @@ -2643,6 +2894,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) @@ -2822,6 +3074,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) { @@ -2910,6 +3172,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. @@ -2920,9 +3192,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. */ @@ -3131,8 +3403,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; } @@ -3174,11 +3445,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; @@ -3224,18 +3503,13 @@ _mesa_get_and_validate_attachment(struct gl_context *ctx, 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, GLuint layer, GLboolean layered, - const char *caller) + GLint level, GLuint layer, GLboolean layered) { - struct gl_renderbuffer_attachment *att = - _mesa_get_and_validate_attachment(ctx, fb, attachment, caller); - if (!att) - return; - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - mtx_lock(&fb->Mutex); + simple_mtx_lock(&fb->Mutex); if (texObj) { if (attachment == GL_DEPTH_ATTACHMENT && texObj == fb->Attachment[BUFFER_STENCIL].Texture && @@ -3294,30 +3568,52 @@ _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(int dims, GLenum target, - GLenum attachment, GLenum textarget, - GLuint texture, GLint level, GLint layer, - const char *caller) +framebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint layer) { GET_CURRENT_CONTEXT(ctx); - struct gl_framebuffer *fb; - struct gl_texture_object *texObj; /* Get the framebuffer object */ - fb = get_framebuffer_target(ctx, target); - if (!fb) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller, - _mesa_enum_to_string(target)); - return; + 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, layer, GL_FALSE); +} + + +static void +framebuffer_texture_with_dims(int dims, GLenum target, + GLenum attachment, GLenum textarget, + GLuint texture, GLint level, GLint layer, + const char *caller) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + struct gl_texture_object *texObj; + + /* Get the framebuffer object */ + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller, + _mesa_enum_to_string(target)); + return; } /* Get the texture object */ - if (!get_texture_for_framebuffer(ctx, texture, false, caller, &texObj)) + if (!get_texture_for_framebuffer_err(ctx, texture, false, caller, &texObj)) return; if (texObj) { @@ -3327,12 +3623,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, 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); } @@ -3345,6 +3656,16 @@ _mesa_FramebufferTexture1D(GLenum target, GLenum attachment, } +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); +} + + void GLAPIENTRY _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) @@ -3354,6 +3675,16 @@ _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, } +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); +} + + void GLAPIENTRY _mesa_FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, @@ -3364,91 +3695,140 @@ _mesa_FramebufferTexture3D(GLenum target, GLenum attachment, } -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 (!check_layer(ctx, texObj->Target, layer, func)) + return; + } + + if (!check_level(ctx, texObj, texObj->Target, level, func)) + return; + } - if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + 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, 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; + frame_buffer_texture(0, target, attachment, texture, level, layer, + "glFramebufferTextureLayer", false, true, false); +} - const char *func = "glNamedFramebufferTextureLayer"; - /* Get the framebuffer object */ - fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); - if (!fb) - 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); +} - /* Get the texture object */ - if (!get_texture_for_framebuffer(ctx, texture, false, func, &texObj)) - return; - if (texObj) { - if (!check_texture_target(ctx, texObj->Target, func)) - return; +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_layer(ctx, texObj->Target, layer, func)) - return; - if (!check_level(ctx, texObj->Target, level, func)) - return; +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); +} - if (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); +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); } @@ -3456,42 +3836,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); } @@ -3499,39 +3853,8 @@ void GLAPIENTRY _mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) { - GET_CURRENT_CONTEXT(ctx); - struct gl_framebuffer *fb; - struct gl_texture_object *texObj; - GLboolean layered = GL_FALSE; - - const char *func = "glNamedFramebufferTexture"; - - if (!_mesa_has_geometry_shaders(ctx)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "unsupported function (glNamedFramebufferTexture) called"); - return; - } - - /* Get the framebuffer object */ - fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); - if (!fb) - return; - - /* Get the texture object */ - if (!get_texture_for_framebuffer(ctx, texture, true, func, &texObj)) - return; - - if (texObj) { - if (!check_layered_texture_target(ctx, texObj->Target, func, - &layered)) - return; - - if (!check_level(ctx, texObj->Target, level, func)) - return; - } - - _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level, - 0, layered, func); + frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0, + "glNamedFramebufferTexture", true, false, true); } @@ -3554,70 +3877,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, &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)); + if (renderbuffer) { + if (!no_error) { + rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func); + if (!rb) + return; } else { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(invalid attachment %s)", func, - _mesa_enum_to_string(attachment)); + rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); } - - return; + } else { + /* remove renderbuffer attachment */ + rb = NULL; } - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && - rb && rb->Format != MESA_FORMAT_NONE) { - /* make sure the renderbuffer is a depth/stencil format */ - const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); - if (baseFormat != GL_DEPTH_STENCIL) { + 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); @@ -3628,36 +4002,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, @@ -3665,26 +4033,9 @@ _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; - } - - 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"); + framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, + renderbuffer, + "glNamedFramebufferRenderbuffer"); } @@ -4084,15 +4435,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, @@ -4111,16 +4468,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, @@ -4259,6 +4616,15 @@ invalid_enum: } +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, const GLenum *attachments, GLint x, GLint y, @@ -4310,6 +4676,14 @@ _mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, } +void GLAPIENTRY +_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments, + const GLenum *attachments) +{ + /* no-op */ +} + + void GLAPIENTRY _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments) @@ -4438,3 +4812,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] = CLAMP(v[i], 0.0f, 1.0f); + } + + 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); +}