X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fmain%2Fformatquery.c;h=215c14f889fe131c1e350f1bf1d347e15e7a0a0a;hb=37266dfb7c747536d254b32eefa9222c60a37508;hp=a7f053e3c94a36713ed63cfaa8e4ec029e317557;hpb=a347a0f53fbdd9b607d7eae4a483e62f82c68cb1;p=mesa.git diff --git a/src/mesa/main/formatquery.c b/src/mesa/main/formatquery.c index a7f053e3c94..215c14f889f 100644 --- a/src/mesa/main/formatquery.c +++ b/src/mesa/main/formatquery.c @@ -28,156 +28,1557 @@ #include "enums.h" #include "fbobject.h" #include "formatquery.h" +#include "teximage.h" +#include "texparam.h" +#include "texobj.h" +#include "get.h" +#include "genmipmap.h" +#include "shaderimage.h" +#include "texcompress.h" +#include "textureview.h" -/* default implementation of QueryInternalFormat driverfunc, for - * drivers not implementing ARB_internalformat_query2. - */ -void -_mesa_query_internal_format_default(struct gl_context *ctx, GLenum target, - GLenum internalFormat, GLenum pname, - GLint *params) +static bool +_is_renderable(struct gl_context *ctx, GLenum internalformat) { - (void) ctx; - (void) target; - (void) internalFormat; + /* Section 4.4.4 on page 212 of the GLES 3.0.4 spec says: + * + * "An internal format is color-renderable if it is one of the + * formats from table 3.13 noted as color-renderable or if it + * is unsized format RGBA or RGB." + * + * Therefore, we must accept GL_RGB and GL_RGBA here. + */ + if (internalformat != GL_RGB && internalformat != GL_RGBA && + _mesa_base_fbo_format(ctx, internalformat) == 0) + return false; - switch (pname) { - case GL_SAMPLES: - case GL_NUM_SAMPLE_COUNTS: - params[0] = 1; - break; - default: - /* @TODO: handle default values for all the different pnames. */ - break; - } + return true; } -void GLAPIENTRY -_mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, - GLsizei bufSize, GLint *params) -{ - GLint buffer[16]; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.ARB_internalformat_query) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInternalformativ"); - return; - } +/* Handles the cases where either ARB_internalformat_query or + * ARB_internalformat_query2 have to return an error. + */ +static bool +_legal_parameters(struct gl_context *ctx, GLenum target, GLenum internalformat, + GLenum pname, GLsizei bufSize, GLint *params) - assert(ctx->Driver.QueryInternalFormat != NULL); +{ + bool query2 = _mesa_has_ARB_internalformat_query2(ctx); - /* The ARB_internalformat_query spec says: + /* The ARB_internalformat_query2 spec says: * - * "If the parameter to GetInternalformativ is not one of - * TEXTURE_2D_MULTISAMPLE, TEXTURE_2D_MULTISAMPLE_ARRAY or RENDERBUFFER - * then an INVALID_ENUM error is generated." + * "The INVALID_ENUM error is generated if the parameter to + * GetInternalformati*v is not one of the targets listed in Table 6.xx. */ - switch (target) { + switch(target){ + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_BUFFER: + if (!query2) { + /* The ARB_internalformat_query spec says: + * + * "If the parameter to GetInternalformativ is not one of + * TEXTURE_2D_MULTISAMPLE, TEXTURE_2D_MULTISAMPLE_ARRAY + * or RENDERBUFFER then an INVALID_ENUM error is generated. + */ + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetInternalformativ(target=%s)", + _mesa_enum_to_string(target)); + + return false; + } + break; + case GL_RENDERBUFFER: break; case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - /* These enums are only valid if ARB_texture_multisample is supported */ - if ((_mesa_is_desktop_gl(ctx) && - ctx->Extensions.ARB_texture_multisample) || - _mesa_is_gles31(ctx)) - break; + /* The non-existence of ARB_texture_multisample is treated in + * ARB_internalformat_query implementation like an error. + */ + if (!query2 && + !(_mesa_has_ARB_texture_multisample(ctx) || _mesa_is_gles31(ctx))) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetInternalformativ(target=%s)", + _mesa_enum_to_string(target)); + + return false; + } + break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetInternalformativ(target=%s)", _mesa_enum_to_string(target)); - return; + return false; } - /* The ARB_internalformat_query spec says: - * - * "If the parameter to GetInternalformativ is not - * color-, depth- or stencil-renderable, then an INVALID_ENUM error is - * generated." - * - * Page 243 of the GLES 3.0.4 spec says this for GetInternalformativ: - * - * "internalformat must be color-renderable, depth-renderable or - * stencilrenderable (as defined in section 4.4.4)." - * - * Section 4.4.4 on page 212 of the same spec says: - * - * "An internal format is color-renderable if it is one of the - * formats from table 3.13 noted as color-renderable or if it - * is unsized format RGBA or RGB." + + /* The ARB_internalformat_query2 spec says: * - * Therefore, we must accept GL_RGB and GL_RGBA here. + * "The INVALID_ENUM error is generated if the parameter is + * not one of the listed possibilities. */ - if (internalformat != GL_RGB && internalformat != GL_RGBA && - _mesa_base_fbo_format(ctx, internalformat) == 0) { + switch(pname){ + case GL_SAMPLES: + case GL_NUM_SAMPLE_COUNTS: + break; + + case GL_SRGB_DECODE_ARB: + /* The ARB_internalformat_query2 spec says: + * + * "If ARB_texture_sRGB_decode or EXT_texture_sRGB_decode or + * equivalent functionality is not supported, queries for the + * SRGB_DECODE_ARB set the INVALID_ENUM error. + */ + if (!_mesa_has_EXT_texture_sRGB_decode(ctx)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetInternalformativ(pname=%s)", + _mesa_enum_to_string(pname)); + return false; + } + /* fallthrough */ + case GL_INTERNALFORMAT_SUPPORTED: + case GL_INTERNALFORMAT_PREFERRED: + case GL_INTERNALFORMAT_RED_SIZE: + case GL_INTERNALFORMAT_GREEN_SIZE: + case GL_INTERNALFORMAT_BLUE_SIZE: + case GL_INTERNALFORMAT_ALPHA_SIZE: + case GL_INTERNALFORMAT_DEPTH_SIZE: + case GL_INTERNALFORMAT_STENCIL_SIZE: + case GL_INTERNALFORMAT_SHARED_SIZE: + case GL_INTERNALFORMAT_RED_TYPE: + case GL_INTERNALFORMAT_GREEN_TYPE: + case GL_INTERNALFORMAT_BLUE_TYPE: + case GL_INTERNALFORMAT_ALPHA_TYPE: + case GL_INTERNALFORMAT_DEPTH_TYPE: + case GL_INTERNALFORMAT_STENCIL_TYPE: + case GL_MAX_WIDTH: + case GL_MAX_HEIGHT: + case GL_MAX_DEPTH: + case GL_MAX_LAYERS: + case GL_MAX_COMBINED_DIMENSIONS: + case GL_COLOR_COMPONENTS: + case GL_DEPTH_COMPONENTS: + case GL_STENCIL_COMPONENTS: + case GL_COLOR_RENDERABLE: + case GL_DEPTH_RENDERABLE: + case GL_STENCIL_RENDERABLE: + case GL_FRAMEBUFFER_RENDERABLE: + case GL_FRAMEBUFFER_RENDERABLE_LAYERED: + case GL_FRAMEBUFFER_BLEND: + case GL_READ_PIXELS: + case GL_READ_PIXELS_FORMAT: + case GL_READ_PIXELS_TYPE: + case GL_TEXTURE_IMAGE_FORMAT: + case GL_TEXTURE_IMAGE_TYPE: + case GL_GET_TEXTURE_IMAGE_FORMAT: + case GL_GET_TEXTURE_IMAGE_TYPE: + case GL_MIPMAP: + case GL_MANUAL_GENERATE_MIPMAP: + case GL_AUTO_GENERATE_MIPMAP: + case GL_COLOR_ENCODING: + case GL_SRGB_READ: + case GL_SRGB_WRITE: + case GL_FILTER: + case GL_VERTEX_TEXTURE: + case GL_TESS_CONTROL_TEXTURE: + case GL_TESS_EVALUATION_TEXTURE: + case GL_GEOMETRY_TEXTURE: + case GL_FRAGMENT_TEXTURE: + case GL_COMPUTE_TEXTURE: + case GL_TEXTURE_SHADOW: + case GL_TEXTURE_GATHER: + case GL_TEXTURE_GATHER_SHADOW: + case GL_SHADER_IMAGE_LOAD: + case GL_SHADER_IMAGE_STORE: + case GL_SHADER_IMAGE_ATOMIC: + case GL_IMAGE_TEXEL_SIZE: + case GL_IMAGE_COMPATIBILITY_CLASS: + case GL_IMAGE_PIXEL_FORMAT: + case GL_IMAGE_PIXEL_TYPE: + case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE: + case GL_TEXTURE_COMPRESSED: + case GL_TEXTURE_COMPRESSED_BLOCK_WIDTH: + case GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT: + case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: + case GL_CLEAR_BUFFER: + case GL_TEXTURE_VIEW: + case GL_VIEW_COMPATIBILITY_CLASS: + /* The ARB_internalformat_query spec says: + * + * "If the parameter to GetInternalformativ is not SAMPLES + * or NUM_SAMPLE_COUNTS, then an INVALID_ENUM error is generated." + */ + if (!query2) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetInternalformativ(pname=%s)", + _mesa_enum_to_string(pname)); + + return false; + } + break; + + default: _mesa_error(ctx, GL_INVALID_ENUM, - "glGetInternalformativ(internalformat=%s)", - _mesa_enum_to_string(internalformat)); - return; + "glGetInternalformativ(pname=%s)", + _mesa_enum_to_string(pname)); + return false; } /* The ARB_internalformat_query spec says: * * "If the parameter to GetInternalformativ is negative, then * an INVALID_VALUE error is generated." + * + * Nothing is said in ARB_internalformat_query2 but we assume the same. */ if (bufSize < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetInternalformativ(target=%s)", _mesa_enum_to_string(target)); - return; + return false; } - /* initialize the contents of the temporary buffer */ - memcpy(buffer, params, MIN2(bufSize, 16) * sizeof(GLint)); + /* The ARB_internalformat_query spec says: + * + * "If the parameter to GetInternalformativ is not + * color-, depth- or stencil-renderable, then an INVALID_ENUM error is + * generated." + */ + if (!query2 && !_is_renderable(ctx, internalformat)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetInternalformativ(internalformat=%s)", + _mesa_enum_to_string(internalformat)); + return false; + } - switch (pname) { + return true; +} + +/* Sets the appropriate "unsupported" response as defined by the + * ARB_internalformat_query2 spec for each each . + */ +static void +_set_default_response(GLenum pname, GLint buffer[16]) +{ + /* The ARB_internalformat_query2 defines which is the reponse best + * representing "not supported" or "not applicable" for each . + * + * " In general: + * - size- or count-based queries will return zero, + * - support-, format- or type-based queries will return NONE, + * - boolean-based queries will return FALSE, and + * - list-based queries return no entries." + */ + switch(pname) { case GL_SAMPLES: - ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, - buffer); break; - case GL_NUM_SAMPLE_COUNTS: { - if ((ctx->API == API_OPENGLES2 && ctx->Version == 30) && - _mesa_is_enum_format_integer(internalformat)) { - /* From GL ES 3.0 specification, section 6.1.15 page 236: "Since - * multisampling is not supported for signed and unsigned integer - * internal formats, the value of NUM_SAMPLE_COUNTS will be zero - * for such formats. - * - * Such a restriction no longer exists in GL ES 3.1. - */ - buffer[0] = 0; - } else { - ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, - buffer); - } + + case GL_MAX_COMBINED_DIMENSIONS: + /* This value can be a 64-bit value. As the default is the 32-bit query, + * we pack 2 32-bit integers. So we need to clean both */ + buffer[0] = 0; + buffer[1] = 0; + break; + + case GL_NUM_SAMPLE_COUNTS: + case GL_INTERNALFORMAT_RED_SIZE: + case GL_INTERNALFORMAT_GREEN_SIZE: + case GL_INTERNALFORMAT_BLUE_SIZE: + case GL_INTERNALFORMAT_ALPHA_SIZE: + case GL_INTERNALFORMAT_DEPTH_SIZE: + case GL_INTERNALFORMAT_STENCIL_SIZE: + case GL_INTERNALFORMAT_SHARED_SIZE: + case GL_MAX_WIDTH: + case GL_MAX_HEIGHT: + case GL_MAX_DEPTH: + case GL_MAX_LAYERS: + case GL_IMAGE_TEXEL_SIZE: + case GL_TEXTURE_COMPRESSED_BLOCK_WIDTH: + case GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT: + case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: + buffer[0] = 0; + break; + + case GL_INTERNALFORMAT_PREFERRED: + case GL_INTERNALFORMAT_RED_TYPE: + case GL_INTERNALFORMAT_GREEN_TYPE: + case GL_INTERNALFORMAT_BLUE_TYPE: + case GL_INTERNALFORMAT_ALPHA_TYPE: + case GL_INTERNALFORMAT_DEPTH_TYPE: + case GL_INTERNALFORMAT_STENCIL_TYPE: + case GL_FRAMEBUFFER_RENDERABLE: + case GL_FRAMEBUFFER_RENDERABLE_LAYERED: + case GL_FRAMEBUFFER_BLEND: + case GL_READ_PIXELS: + case GL_READ_PIXELS_FORMAT: + case GL_READ_PIXELS_TYPE: + case GL_TEXTURE_IMAGE_FORMAT: + case GL_TEXTURE_IMAGE_TYPE: + case GL_GET_TEXTURE_IMAGE_FORMAT: + case GL_GET_TEXTURE_IMAGE_TYPE: + case GL_MANUAL_GENERATE_MIPMAP: + case GL_AUTO_GENERATE_MIPMAP: + case GL_COLOR_ENCODING: + case GL_SRGB_READ: + case GL_SRGB_WRITE: + case GL_SRGB_DECODE_ARB: + case GL_FILTER: + case GL_VERTEX_TEXTURE: + case GL_TESS_CONTROL_TEXTURE: + case GL_TESS_EVALUATION_TEXTURE: + case GL_GEOMETRY_TEXTURE: + case GL_FRAGMENT_TEXTURE: + case GL_COMPUTE_TEXTURE: + case GL_TEXTURE_SHADOW: + case GL_TEXTURE_GATHER: + case GL_TEXTURE_GATHER_SHADOW: + case GL_SHADER_IMAGE_LOAD: + case GL_SHADER_IMAGE_STORE: + case GL_SHADER_IMAGE_ATOMIC: + case GL_IMAGE_COMPATIBILITY_CLASS: + case GL_IMAGE_PIXEL_FORMAT: + case GL_IMAGE_PIXEL_TYPE: + case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE: + case GL_CLEAR_BUFFER: + case GL_TEXTURE_VIEW: + case GL_VIEW_COMPATIBILITY_CLASS: + buffer[0] = GL_NONE; + break; + + case GL_INTERNALFORMAT_SUPPORTED: + case GL_COLOR_COMPONENTS: + case GL_DEPTH_COMPONENTS: + case GL_STENCIL_COMPONENTS: + case GL_COLOR_RENDERABLE: + case GL_DEPTH_RENDERABLE: + case GL_STENCIL_RENDERABLE: + case GL_MIPMAP: + case GL_TEXTURE_COMPRESSED: + buffer[0] = GL_FALSE; + break; + + default: + unreachable("invalid 'pname'"); + } +} + +static bool +_is_target_supported(struct gl_context *ctx, GLenum target) +{ + /* The ARB_internalformat_query2 spec says: + * + * "if a particular type of is not supported by the + * implementation the "unsupported" answer should be given. + * This is not an error." + */ + switch(target){ + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + break; + + case GL_TEXTURE_1D: + if (!_mesa_is_desktop_gl(ctx)) + return false; + break; + + case GL_TEXTURE_1D_ARRAY: + if (!_mesa_has_EXT_texture_array(ctx)) + return false; + break; + + case GL_TEXTURE_2D_ARRAY: + if (!(_mesa_has_EXT_texture_array(ctx) || _mesa_is_gles3(ctx))) + return false; + break; + + case GL_TEXTURE_CUBE_MAP: + if (!_mesa_has_ARB_texture_cube_map(ctx)) + return false; + break; + + case GL_TEXTURE_CUBE_MAP_ARRAY: + if (!_mesa_has_ARB_texture_cube_map_array(ctx)) + return false; + break; + + case GL_TEXTURE_RECTANGLE: + if (!_mesa_has_NV_texture_rectangle(ctx)) + return false; + break; + + case GL_TEXTURE_BUFFER: + if (!_mesa_has_ARB_texture_buffer_object(ctx)) + return false; + break; + + case GL_RENDERBUFFER: + if (!(_mesa_has_ARB_framebuffer_object(ctx) || + _mesa_is_gles3(ctx))) + return false; + break; + + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + if (!(_mesa_has_ARB_texture_multisample(ctx) || + _mesa_is_gles31(ctx))) + return false; break; + + default: + unreachable("invalid target"); } + + return true; +} + +static bool +_is_resource_supported(struct gl_context *ctx, GLenum target, + GLenum internalformat, GLenum pname) +{ + /* From the ARB_internalformat_query2 spec: + * + * In the following descriptions, the term /resource/ is used to generically + * refer to an object of the appropriate type that has been created with + * and . If the particular and + * combination do not make sense, ... the "unsupported" + * answer should be given. This is not an error. + */ + + /* In the ARB_internalformat_query2 spec wording, some do not care + * about the /resource/ being supported or not, we return 'true' for those. + */ + switch (pname) { + case GL_INTERNALFORMAT_SUPPORTED: + case GL_INTERNALFORMAT_PREFERRED: + case GL_COLOR_COMPONENTS: + case GL_DEPTH_COMPONENTS: + case GL_STENCIL_COMPONENTS: + case GL_COLOR_RENDERABLE: + case GL_DEPTH_RENDERABLE: + case GL_STENCIL_RENDERABLE: + return true; default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetInternalformativ(pname=%s)", - _mesa_enum_to_string(pname)); - return; + break; } - if (bufSize != 0 && params == NULL) { - /* Emit a warning to aid application debugging, but go ahead and do the - * memcpy (and probably crash) anyway. + switch(target){ + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_RECTANGLE: + /* Based on what Mesa does for glTexImage1D/2D/3D and + * glCompressedTexImage1D/2D/3D functions. */ - _mesa_warning(ctx, - "glGetInternalformativ(bufSize = %d, but params = NULL)", - bufSize); + if (_mesa_base_tex_format(ctx, internalformat) < 0) + return false; + + /* additional checks for depth textures */ + if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalformat)) + return false; + + /* additional checks for compressed textures */ + if (_mesa_is_compressed_format(ctx, internalformat) && + (!_mesa_target_can_be_compressed(ctx, target, internalformat, NULL) || + _mesa_format_no_online_compression(ctx, internalformat))) + return false; + + break; + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + /* Based on what Mesa does for glTexImage2D/3DMultisample, + * glTexStorage2D/3DMultisample and + * glTextureStorage2D/3DMultisample functions. + */ + if (!_mesa_is_renderable_texture_format(ctx, internalformat)) + return false; + + break; + case GL_TEXTURE_BUFFER: + /* Based on what Mesa does for the glTexBuffer function. */ + if (_mesa_validate_texbuffer_format(ctx, internalformat) == + MESA_FORMAT_NONE) + return false; + + break; + case GL_RENDERBUFFER: + /* Based on what Mesa does for glRenderbufferStorage(Multisample) and + * glNamedRenderbufferStorage functions. + */ + if (!_mesa_base_fbo_format(ctx, internalformat)) + return false; + + break; + default: + unreachable("bad target"); } - /* Copy the data from the temporary buffer to the buffer supplied by the - * application. Clamp the size of the copy to the size supplied by the - * application. + return true; +} + +static bool +_is_internalformat_supported(struct gl_context *ctx, GLenum target, + GLenum internalformat) +{ + /* From the ARB_internalformat_query2 specification: + * + * "- INTERNALFORMAT_SUPPORTED: If is an internal format + * that is supported by the implementation in at least some subset of + * possible operations, TRUE is written to . If + * if not a valid token for any internal format usage, FALSE is returned. + * + * that must be supported (in GL 4.2 or later) include + * the following: + * - "sized internal formats" from Table 3.12, 3.13, and 3.15, + * - any specific "compressed internal format" from Table 3.14, + * - any "image unit format" from Table 3.21. + * - any generic "compressed internal format" from Table 3.14, if the + * implementation accepts it for any texture specification commands, and + * - unsized or base internal format, if the implementation accepts + * it for texture or image specification. */ - memcpy(params, buffer, MIN2(bufSize, 16) * sizeof(GLint)); + GLint buffer[1]; - return; + /* At this point a internalformat is valid if it is valid as a texture or + * as a renderbuffer format. The checks are different because those methods + * return different values when passing non supported internalformats */ + if (_mesa_base_tex_format(ctx, internalformat) < 0 && + _mesa_base_fbo_format(ctx, internalformat) == 0) + return false; + + /* Let the driver have the final word */ + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, + GL_INTERNALFORMAT_SUPPORTED, buffer); + + return (buffer[0] == GL_TRUE); +} + +static bool +_legal_target_for_framebuffer_texture_layer(struct gl_context *ctx, + GLenum target) +{ + switch (target) { + case GL_TEXTURE_3D: + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + case GL_TEXTURE_CUBE_MAP: + return true; + default: + return false; + } +} + +static GLenum +_mesa_generic_type_for_internal_format(GLenum internalFormat) +{ + if (_mesa_is_enum_format_unsigned_int(internalFormat)) + return GL_UNSIGNED_BYTE; + else if (_mesa_is_enum_format_signed_int(internalFormat)) + return GL_BYTE; + else + return GL_FLOAT; +} + +/* default implementation of QueryInternalFormat driverfunc, for + * drivers not implementing ARB_internalformat_query2. + */ +void +_mesa_query_internal_format_default(struct gl_context *ctx, GLenum target, + GLenum internalFormat, GLenum pname, + GLint *params) +{ + (void) target; + + switch (pname) { + case GL_SAMPLES: + case GL_NUM_SAMPLE_COUNTS: + params[0] = 1; + break; + + case GL_INTERNALFORMAT_SUPPORTED: + params[0] = GL_TRUE; + break; + + case GL_INTERNALFORMAT_PREFERRED: + params[0] = internalFormat; + break; + + case GL_READ_PIXELS_FORMAT: { + GLenum base_format = _mesa_base_tex_format(ctx, internalFormat); + switch (base_format) { + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + case GL_RED: + case GL_RGB: + case GL_BGR: + case GL_RGBA: + case GL_BGRA: + params[0] = base_format; + break; + default: + params[0] = GL_NONE; + break; + } + break; + } + + case GL_READ_PIXELS_TYPE: + case GL_TEXTURE_IMAGE_TYPE: + case GL_GET_TEXTURE_IMAGE_TYPE: { + GLenum base_format = _mesa_base_tex_format(ctx, internalFormat); + if (base_format > 0) + params[0] = _mesa_generic_type_for_internal_format(internalFormat); + else + params[0] = GL_NONE; + break; + } + + case GL_TEXTURE_IMAGE_FORMAT: + case GL_GET_TEXTURE_IMAGE_FORMAT: { + GLenum format = GL_NONE; + GLenum base_format = _mesa_base_tex_format(ctx, internalFormat); + if (base_format > 0) { + if (_mesa_is_enum_format_integer(internalFormat)) + format = _mesa_base_format_to_integer_format(base_format); + else + format = base_format; + } + + params[0] = format; + break; + } + + case GL_MANUAL_GENERATE_MIPMAP: + case GL_AUTO_GENERATE_MIPMAP: + case GL_SRGB_READ: + case GL_SRGB_WRITE: + case GL_SRGB_DECODE_ARB: + case GL_VERTEX_TEXTURE: + case GL_TESS_CONTROL_TEXTURE: + case GL_TESS_EVALUATION_TEXTURE: + case GL_GEOMETRY_TEXTURE: + case GL_FRAGMENT_TEXTURE: + case GL_COMPUTE_TEXTURE: + case GL_SHADER_IMAGE_LOAD: + case GL_SHADER_IMAGE_STORE: + case GL_SHADER_IMAGE_ATOMIC: + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE: + case GL_CLEAR_BUFFER: + case GL_TEXTURE_VIEW: + case GL_TEXTURE_SHADOW: + case GL_TEXTURE_GATHER: + case GL_TEXTURE_GATHER_SHADOW: + case GL_FRAMEBUFFER_RENDERABLE: + case GL_FRAMEBUFFER_RENDERABLE_LAYERED: + case GL_FRAMEBUFFER_BLEND: + case GL_FILTER: + params[0] = GL_FULL_SUPPORT; + break; + + default: + _set_default_response(pname, params); + break; + } +} + +/* + * For MAX_WIDTH/MAX_HEIGHT/MAX_DEPTH it returns the equivalent GetInteger + * pname for a Getinternalformat pname/target combination. target/pname + * combinations that would return 0 due dimension number or unsupported status + * should be already filtered out + * + * Note that this means that the returned value would be independent of the + * internalformat. This possibility is already mentioned at the Issue 7 of the + * arb_internalformat_query2 spec. + */ +static GLenum +equivalentSizePname(GLenum target, + GLenum pname) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_MULTISAMPLE: + return GL_MAX_TEXTURE_SIZE; + case GL_TEXTURE_3D: + return GL_MAX_3D_TEXTURE_SIZE; + case GL_TEXTURE_CUBE_MAP: + return GL_MAX_CUBE_MAP_TEXTURE_SIZE; + case GL_TEXTURE_RECTANGLE: + return GL_MAX_RECTANGLE_TEXTURE_SIZE; + case GL_RENDERBUFFER: + return GL_MAX_RENDERBUFFER_SIZE; + case GL_TEXTURE_1D_ARRAY: + if (pname == GL_MAX_HEIGHT) + return GL_MAX_ARRAY_TEXTURE_LAYERS; + else + return GL_MAX_TEXTURE_SIZE; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + if (pname == GL_MAX_DEPTH) + return GL_MAX_ARRAY_TEXTURE_LAYERS; + else + return GL_MAX_TEXTURE_SIZE; + case GL_TEXTURE_CUBE_MAP_ARRAY: + if (pname == GL_MAX_DEPTH) + return GL_MAX_ARRAY_TEXTURE_LAYERS; + else + return GL_MAX_CUBE_MAP_TEXTURE_SIZE; + case GL_TEXTURE_BUFFER: + return GL_MAX_TEXTURE_BUFFER_SIZE; + default: + return 0; + } +} + +/* + * Returns the dimensions associated to a target. GL_TEXTURE_BUFFER and + * GL_RENDERBUFFER have associated a dimension, but they are not textures + * per-se, so we can't just call _mesa_get_texture_dimension directly. + */ +static GLint +get_target_dimensions(GLenum target) +{ + switch(target) { + case GL_TEXTURE_BUFFER: + return 1; + case GL_RENDERBUFFER: + return 2; + default: + return _mesa_get_texture_dimensions(target); + } +} + +/* + * Returns the minimum amount of dimensions associated to a pname. So for + * example, if querying GL_MAX_HEIGHT, it is assumed that your target would + * have as minimum 2 dimensions. + * + * Useful to handle sentences like this from query2 spec: + * + * "MAX_HEIGHT: + * + * If the resource does not have at least two dimensions + * ." + */ +static GLint +get_min_dimensions(GLenum pname) +{ + switch(pname) { + case GL_MAX_WIDTH: + return 1; + case GL_MAX_HEIGHT: + return 2; + case GL_MAX_DEPTH: + return 3; + default: + return 0; + } +} + +/* + * Similar to teximage.c:check_multisample_target, but independent of the + * dimensions. + */ +static bool +is_multisample_target(GLenum target) +{ + switch(target) { + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + return true; + default: + return false; + } + +} + +void GLAPIENTRY +_mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, + GLsizei bufSize, GLint *params) +{ + GLint buffer[16]; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* ARB_internalformat_query is also mandatory for ARB_internalformat_query2 */ + if (!(_mesa_has_ARB_internalformat_query(ctx) || + _mesa_is_gles3(ctx))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInternalformativ"); + return; + } + + assert(ctx->Driver.QueryInternalFormat != NULL); + + if (!_legal_parameters(ctx, target, internalformat, pname, bufSize, params)) + return; + + /* initialize the contents of the temporary buffer */ + memcpy(buffer, params, MIN2(bufSize, 16) * sizeof(GLint)); + + /* Use the 'unsupported' response defined by the spec for every pname + * as the default answer. + */ + _set_default_response(pname, buffer); + + if (!_is_target_supported(ctx, target) || + !_is_internalformat_supported(ctx, target, internalformat) || + !_is_resource_supported(ctx, target, internalformat, pname)) + goto end; + + switch (pname) { + case GL_SAMPLES: + /* fall-through */ + case GL_NUM_SAMPLE_COUNTS: + /* The ARB_internalformat_query2 sets the response as 'unsupported' for + * SAMPLES and NUM_SAMPLE_COUNTS: + * + * "If is not color-renderable, depth-renderable, or + * stencil-renderable (as defined in section 4.4.4), or if + * does not support multiple samples (ie other than + * TEXTURE_2D_MULTISAMPLE, TEXTURE_2D_MULTISAMPLE_ARRAY, + * or RENDERBUFFER)." + */ + if ((target != GL_RENDERBUFFER && + target != GL_TEXTURE_2D_MULTISAMPLE && + target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY) || + !_is_renderable(ctx, internalformat)) + goto end; + + /* The GL ES 3.0 specification, section 6.1.15 page 236 says: + * + * "Since multisampling is not supported for signed and unsigned + * integer internal formats, the value of NUM_SAMPLE_COUNTS will be + * zero for such formats. + */ + if (pname == GL_NUM_SAMPLE_COUNTS && ctx->API == API_OPENGLES2 && + ctx->Version == 30 && _mesa_is_enum_format_integer(internalformat)) { + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_INTERNALFORMAT_SUPPORTED: + /* Having a supported is implemented as a prerequisite + * for all the . Thus, if we reach this point, the internalformat is + * supported. + */ + buffer[0] = GL_TRUE; + break; + + case GL_INTERNALFORMAT_PREFERRED: + /* The ARB_internalformat_query2 spec says: + * + * "- INTERNALFORMAT_PREFERRED: The implementation-preferred internal + * format for representing resources of the specified is + * returned in . + * + * Therefore, we let the driver answer. + */ + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_INTERNALFORMAT_RED_SIZE: + case GL_INTERNALFORMAT_GREEN_SIZE: + case GL_INTERNALFORMAT_BLUE_SIZE: + case GL_INTERNALFORMAT_ALPHA_SIZE: + case GL_INTERNALFORMAT_DEPTH_SIZE: + case GL_INTERNALFORMAT_STENCIL_SIZE: + case GL_INTERNALFORMAT_SHARED_SIZE: + case GL_INTERNALFORMAT_RED_TYPE: + case GL_INTERNALFORMAT_GREEN_TYPE: + case GL_INTERNALFORMAT_BLUE_TYPE: + case GL_INTERNALFORMAT_ALPHA_TYPE: + case GL_INTERNALFORMAT_DEPTH_TYPE: + case GL_INTERNALFORMAT_STENCIL_TYPE: { + GLint baseformat; + mesa_format texformat; + + if (target != GL_RENDERBUFFER) { + if (!_mesa_legal_get_tex_level_parameter_target(ctx, target, true)) + goto end; + + baseformat = _mesa_base_tex_format(ctx, internalformat); + } else { + baseformat = _mesa_base_fbo_format(ctx, internalformat); + } + + /* Let the driver choose the texture format. + * + * Disclaimer: I am considering that drivers use for renderbuffers the + * same format-choice logic as for textures. + */ + texformat = ctx->Driver.ChooseTextureFormat(ctx, target, internalformat, + GL_NONE /*format */, GL_NONE /* type */); + + if (texformat == MESA_FORMAT_NONE || baseformat <= 0) + goto end; + + /* Implementation based on what Mesa does for glGetTexLevelParameteriv + * and glGetRenderbufferParameteriv functions. + */ + if (pname == GL_INTERNALFORMAT_SHARED_SIZE) { + if (_mesa_has_EXT_texture_shared_exponent(ctx) && + target != GL_TEXTURE_BUFFER && + target != GL_RENDERBUFFER && + texformat == MESA_FORMAT_R9G9B9E5_FLOAT) { + buffer[0] = 5; + } + goto end; + } + + if (!_mesa_base_format_has_channel(baseformat, pname)) + goto end; + + switch (pname) { + case GL_INTERNALFORMAT_DEPTH_SIZE: + if (!_mesa_has_ARB_depth_texture(ctx) && + target != GL_RENDERBUFFER && + target != GL_TEXTURE_BUFFER) + goto end; + /* fallthrough */ + case GL_INTERNALFORMAT_RED_SIZE: + case GL_INTERNALFORMAT_GREEN_SIZE: + case GL_INTERNALFORMAT_BLUE_SIZE: + case GL_INTERNALFORMAT_ALPHA_SIZE: + case GL_INTERNALFORMAT_STENCIL_SIZE: + buffer[0] = _mesa_get_format_bits(texformat, pname); + break; + + case GL_INTERNALFORMAT_DEPTH_TYPE: + if (!_mesa_has_ARB_texture_float(ctx)) + goto end; + /* fallthrough */ + case GL_INTERNALFORMAT_RED_TYPE: + case GL_INTERNALFORMAT_GREEN_TYPE: + case GL_INTERNALFORMAT_BLUE_TYPE: + case GL_INTERNALFORMAT_ALPHA_TYPE: + case GL_INTERNALFORMAT_STENCIL_TYPE: + buffer[0] = _mesa_get_format_datatype(texformat); + break; + + default: + break; + + } + break; + } + + /* For WIDTH/HEIGHT/DEPTH/LAYERS there is no reason to think that the + * returned values should be different to the values returned by + * GetInteger with MAX_TEXTURE_SIZE, MAX_3D_TEXTURE_SIZE, etc.*/ + case GL_MAX_WIDTH: + case GL_MAX_HEIGHT: + case GL_MAX_DEPTH: { + GLenum get_pname; + GLint dimensions; + GLint min_dimensions; + + /* From query2:MAX_HEIGHT spec (as example): + * + * "If the resource does not have at least two dimensions, or if the + * resource is unsupported, zero is returned." + */ + dimensions = get_target_dimensions(target); + min_dimensions = get_min_dimensions(pname); + if (dimensions < min_dimensions) + goto end; + + get_pname = equivalentSizePname(target, pname); + if (get_pname == 0) + goto end; + + _mesa_GetIntegerv(get_pname, buffer); + break; + } + + case GL_MAX_LAYERS: + if (!_mesa_has_EXT_texture_array(ctx)) + goto end; + + if (!_mesa_is_array_texture(target)) + goto end; + + _mesa_GetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, buffer); + break; + + case GL_MAX_COMBINED_DIMENSIONS:{ + GLint64 combined_value = 1; + GLenum max_dimensions_pnames[] = { + GL_MAX_WIDTH, + GL_MAX_HEIGHT, + GL_MAX_DEPTH, + GL_SAMPLES + }; + unsigned i; + GLint current_value; + + /* Combining the dimensions. Note that for array targets, this would + * automatically include the value of MAX_LAYERS, as that value is + * returned as MAX_HEIGHT or MAX_DEPTH */ + for (i = 0; i < 4; i++) { + if (max_dimensions_pnames[i] == GL_SAMPLES && + !is_multisample_target(target)) + continue; + + _mesa_GetInternalformativ(target, internalformat, + max_dimensions_pnames[i], + 1, ¤t_value); + + if (current_value != 0) + combined_value *= current_value; + } + + if (_mesa_is_cube_map_texture(target)) + combined_value *= 6; + + /* We pack the 64-bit value on two 32-bit values. Calling the 32-bit + * query, this would work as far as the value can be hold on a 32-bit + * signed integer. For the 64-bit query, the wrapper around the 32-bit + * query will unpack the value */ + memcpy(buffer, &combined_value, sizeof(GLint64)); + break; + } + + case GL_COLOR_COMPONENTS: + /* The ARB_internalformat_query2 spec says: + * + * "- COLOR_COMPONENTS: If the internal format contains any color + * components (R, G, B, or A), TRUE is returned in . + * If the internal format is unsupported or contains no color + * components, FALSE is returned." + */ + if (_mesa_is_color_format(internalformat)) + buffer[0] = GL_TRUE; + break; + + case GL_DEPTH_COMPONENTS: + /* The ARB_internalformat_query2 spec says: + * + * "- DEPTH_COMPONENTS: If the internal format contains a depth + * component (D), TRUE is returned in . If the internal format + * is unsupported or contains no depth component, FALSE is returned." + */ + if (_mesa_is_depth_format(internalformat) || + _mesa_is_depthstencil_format(internalformat)) + buffer[0] = GL_TRUE; + break; + + case GL_STENCIL_COMPONENTS: + /* The ARB_internalformat_query2 spec says: + * + * "- STENCIL_COMPONENTS: If the internal format contains a stencil + * component (S), TRUE is returned in . If the internal format + * is unsupported or contains no stencil component, FALSE is returned. + */ + if (_mesa_is_stencil_format(internalformat) || + _mesa_is_depthstencil_format(internalformat)) + buffer[0] = GL_TRUE; + break; + + case GL_COLOR_RENDERABLE: + case GL_DEPTH_RENDERABLE: + case GL_STENCIL_RENDERABLE: + if (!_is_renderable(ctx, internalformat)) + goto end; + + if (pname == GL_COLOR_RENDERABLE) { + if (!_mesa_is_color_format(internalformat)) + goto end; + } else { + GLenum baseFormat = _mesa_base_fbo_format(ctx, internalformat); + if (baseFormat != GL_DEPTH_STENCIL && + ((pname == GL_DEPTH_RENDERABLE && baseFormat != GL_DEPTH_COMPONENT) || + (pname == GL_STENCIL_RENDERABLE && baseFormat != GL_STENCIL_INDEX))) + goto end; + } + + buffer[0] = GL_TRUE; + break; + + case GL_FRAMEBUFFER_RENDERABLE_LAYERED: + if (!_mesa_has_EXT_texture_array(ctx) || + _legal_target_for_framebuffer_texture_layer(ctx, target)) + goto end; + /* fallthrough */ + case GL_FRAMEBUFFER_RENDERABLE: + case GL_FRAMEBUFFER_BLEND: + if (!_mesa_has_ARB_framebuffer_object(ctx)) + goto end; + + if (target == GL_TEXTURE_BUFFER || + !_is_renderable(ctx, internalformat)) + goto end; + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_READ_PIXELS: + case GL_READ_PIXELS_FORMAT: + case GL_READ_PIXELS_TYPE: + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_TEXTURE_IMAGE_FORMAT: + case GL_GET_TEXTURE_IMAGE_FORMAT: + case GL_TEXTURE_IMAGE_TYPE: + case GL_GET_TEXTURE_IMAGE_TYPE: + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_MIPMAP: + case GL_MANUAL_GENERATE_MIPMAP: + case GL_AUTO_GENERATE_MIPMAP: + if (!_mesa_is_valid_generate_texture_mipmap_target(ctx, target) || + !_mesa_is_valid_generate_texture_mipmap_internalformat(ctx, + internalformat)) { + goto end; + } + + if (pname == GL_MIPMAP) { + buffer[0] = GL_TRUE; + goto end; + } + else if (pname == GL_MANUAL_GENERATE_MIPMAP) { + if (!_mesa_has_ARB_framebuffer_object(ctx)) + goto end; + } + else { + /* From ARB_internalformat_query2: + * "Dependencies on OpenGL 3.2 (Core Profile) + * In core profiles for OpenGL 3.2 and later versions, queries + * for the AUTO_GENERATE_MIPMAP return the appropriate + * unsupported response." + */ + if (_mesa_is_desktop_gl(ctx) && ctx->Version >= 32) + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_COLOR_ENCODING: + if (!_mesa_is_color_format(internalformat)) + goto end; + + if (_mesa_is_srgb_format(internalformat)) + buffer[0] = GL_SRGB; + else + buffer[0] = GL_LINEAR; + break; + + case GL_SRGB_READ: + if (!_mesa_has_EXT_texture_sRGB(ctx) || + !_mesa_is_srgb_format(internalformat)) { + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_SRGB_WRITE: + if (!_mesa_has_EXT_framebuffer_sRGB(ctx) || + !_mesa_is_color_format(internalformat)) { + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_SRGB_DECODE_ARB: + /* Presence of EXT_texture_sRGB_decode was already verified */ + if (!_mesa_has_EXT_texture_sRGB(ctx) || + target == GL_RENDERBUFFER || + !_mesa_is_srgb_format(internalformat)) { + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_FILTER: + /* If it doesn't allow to set sampler parameters then it would not allow + * to set a filter different to GL_NEAREST. In practice, this method + * only filters out MULTISAMPLE/MULTISAMPLE_ARRAY */ + if (!_mesa_target_allows_setting_sampler_parameters(target)) + goto end; + + if (_mesa_is_enum_format_integer(internalformat)) + goto end; + + if (target == GL_TEXTURE_BUFFER) + goto end; + + /* At this point we know that multi-texel filtering is supported. We + * need to call the driver to know if it is CAVEAT_SUPPORT or + * FULL_SUPPORT. + */ + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_VERTEX_TEXTURE: + case GL_TESS_CONTROL_TEXTURE: + case GL_TESS_EVALUATION_TEXTURE: + case GL_GEOMETRY_TEXTURE: + case GL_FRAGMENT_TEXTURE: + case GL_COMPUTE_TEXTURE: + if (target == GL_RENDERBUFFER) + goto end; + + if ((pname == GL_TESS_CONTROL_TEXTURE || + pname == GL_TESS_EVALUATION_TEXTURE) && + !_mesa_has_tessellation(ctx)) + goto end; + + if (pname == GL_GEOMETRY_TEXTURE && !_mesa_has_geometry_shaders(ctx)) + goto end; + + if (pname == GL_COMPUTE_TEXTURE && !_mesa_has_compute_shaders(ctx)) + goto end; + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_TEXTURE_GATHER: + case GL_TEXTURE_GATHER_SHADOW: + if (!_mesa_has_ARB_texture_gather(ctx)) + goto end; + + /* fallthrough */ + case GL_TEXTURE_SHADOW: + /* Only depth or depth-stencil image formats make sense in shadow + samplers */ + if (pname != GL_TEXTURE_GATHER && + !_mesa_is_depth_format(internalformat) && + !_mesa_is_depthstencil_format(internalformat)) + goto end; + + /* Validate the target for shadow and gather operations */ + switch (target) { + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_RECTANGLE: + break; + + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY: + /* 1D and 1DArray textures are not admitted in gather operations */ + if (pname != GL_TEXTURE_SHADOW) + goto end; + break; + + default: + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_SHADER_IMAGE_LOAD: + case GL_SHADER_IMAGE_STORE: + if (!_mesa_has_ARB_shader_image_load_store(ctx)) + goto end; + + /* We call to _mesa_is_shader_image_format_supported + * using "internalformat" as parameter, because the + * the ARB_internalformat_query2 spec says: + * "In this case the is the value of the + * parameter that is passed to BindImageTexture." + */ + if (target == GL_RENDERBUFFER || + !_mesa_is_shader_image_format_supported(ctx, internalformat)) + goto end; + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_SHADER_IMAGE_ATOMIC: + if (!_mesa_has_ARB_shader_image_load_store(ctx)) + goto end; + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_IMAGE_TEXEL_SIZE: { + mesa_format image_format; + + if (!_mesa_has_ARB_shader_image_load_store(ctx) || + target == GL_RENDERBUFFER) + goto end; + + image_format = _mesa_get_shader_image_format(internalformat); + if (image_format == MESA_FORMAT_NONE) + goto end; + + /* We return bits */ + buffer[0] = (_mesa_get_format_bytes(image_format) * 8); + break; + } + + case GL_IMAGE_COMPATIBILITY_CLASS: + if (!_mesa_has_ARB_shader_image_load_store(ctx) || + target == GL_RENDERBUFFER) + goto end; + + buffer[0] = _mesa_get_image_format_class(internalformat); + break; + + case GL_IMAGE_PIXEL_FORMAT: { + GLint base_format; + + if (!_mesa_has_ARB_shader_image_load_store(ctx) || + target == GL_RENDERBUFFER || + !_mesa_is_shader_image_format_supported(ctx, internalformat)) + goto end; + + base_format = _mesa_base_tex_format(ctx, internalformat); + if (base_format == -1) + goto end; + + if (_mesa_is_enum_format_integer(internalformat)) + buffer[0] = _mesa_base_format_to_integer_format(base_format); + else + buffer[0] = base_format; + break; + } + + case GL_IMAGE_PIXEL_TYPE: { + mesa_format image_format; + GLenum datatype; + GLuint comps; + + if (!_mesa_has_ARB_shader_image_load_store(ctx) || + target == GL_RENDERBUFFER) + goto end; + + image_format = _mesa_get_shader_image_format(internalformat); + if (image_format == MESA_FORMAT_NONE) + goto end; + + _mesa_uncompressed_format_to_type_and_comps(image_format, &datatype, + &comps); + if (!datatype) + goto end; + + buffer[0] = datatype; + break; + } + + case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: { + if (!_mesa_has_ARB_shader_image_load_store(ctx)) + goto end; + + if (!_mesa_legal_get_tex_level_parameter_target(ctx, target, true)) + goto end; + + /* From spec: "Equivalent to calling GetTexParameter with set + * to IMAGE_FORMAT_COMPATIBILITY_TYPE." + * + * GetTexParameter just returns + * tex_obj->ImageFormatCompatibilityType. We create a fake tex_obj + * just with the purpose of getting the value. + */ + struct gl_texture_object *tex_obj = _mesa_new_texture_object(ctx, 0, target); + buffer[0] = tex_obj->ImageFormatCompatibilityType; + _mesa_delete_texture_object(ctx, tex_obj); + + break; + } + + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST: + case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE: + case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE: + if (target == GL_RENDERBUFFER) + goto end; + + if (!_mesa_is_depthstencil_format(internalformat)) { + if (((pname == GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST || + pname == GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE) && + !_mesa_is_depth_format(internalformat)) || + ((pname == GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST || + pname == GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE) && + !_mesa_is_stencil_format(internalformat))) + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_TEXTURE_COMPRESSED: + buffer[0] = _mesa_is_compressed_format(ctx, internalformat); + break; + + case GL_TEXTURE_COMPRESSED_BLOCK_WIDTH: + case GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT: + case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: { + mesa_format mesaformat; + GLint block_size; + + mesaformat = _mesa_glenum_to_compressed_format(internalformat); + if (mesaformat == MESA_FORMAT_NONE) + goto end; + + block_size = _mesa_get_format_bytes(mesaformat); + assert(block_size > 0); + + if (pname == GL_TEXTURE_COMPRESSED_BLOCK_SIZE) { + buffer[0] = block_size; + } else { + GLuint bwidth, bheight; + + /* Returns the width and height in pixels. We return bytes */ + _mesa_get_format_block_size(mesaformat, &bwidth, &bheight); + assert(bwidth > 0 && bheight > 0); + + if (pname == GL_TEXTURE_COMPRESSED_BLOCK_WIDTH) + buffer[0] = block_size / bheight; + else + buffer[0] = block_size / bwidth; + } + break; + } + + case GL_CLEAR_BUFFER: + if (target != GL_TEXTURE_BUFFER) + goto end; + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + break; + + case GL_TEXTURE_VIEW: + case GL_VIEW_COMPATIBILITY_CLASS: + if (!_mesa_has_ARB_texture_view(ctx) || + target == GL_TEXTURE_BUFFER || + target == GL_RENDERBUFFER) + goto end; + + if (pname == GL_TEXTURE_VIEW) { + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); + } else { + GLenum view_class = _mesa_texture_view_lookup_view_class(ctx, + internalformat); + if (view_class == GL_FALSE) + goto end; + + buffer[0] = view_class; + } + break; + + default: + unreachable("bad param"); + } + + end: + if (bufSize != 0 && params == NULL) { + /* Emit a warning to aid application debugging, but go ahead and do the + * memcpy (and probably crash) anyway. + */ + _mesa_warning(ctx, + "glGetInternalformativ(bufSize = %d, but params = NULL)", + bufSize); + } + + /* Copy the data from the temporary buffer to the buffer supplied by the + * application. Clamp the size of the copy to the size supplied by the + * application. + */ + memcpy(params, buffer, MIN2(bufSize, 16) * sizeof(GLint)); + + return; +} + +void GLAPIENTRY +_mesa_GetInternalformati64v(GLenum target, GLenum internalformat, + GLenum pname, GLsizei bufSize, GLint64 *params) +{ + GLint params32[16]; + unsigned i; + GLsizei realSize = MIN2(bufSize, 16); + GLsizei callSize; + + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!_mesa_has_ARB_internalformat_query2(ctx)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInternalformati64v"); + return; + } + + /* For SAMPLES there are cases where params needs to remain unmodified. As + * no pname can return a negative value, we fill params32 with negative + * values as reference values, that can be used to know what copy-back to + * params */ + memset(params32, -1, 16); + + /* For GL_MAX_COMBINED_DIMENSIONS we need to get back 2 32-bit integers, + * and at the same time we only need 2. So for that pname, we call the + * 32-bit query with bufSize 2, except on the case of bufSize 0, that is + * basically like asking to not get the value, but that is a caller + * problem. */ + if (pname == GL_MAX_COMBINED_DIMENSIONS && bufSize > 0) + callSize = 2; + else + callSize = bufSize; + + _mesa_GetInternalformativ(target, internalformat, pname, callSize, params32); + + if (pname == GL_MAX_COMBINED_DIMENSIONS) { + memcpy(params, params32, sizeof(GLint64)); + } else { + for (i = 0; i < realSize; i++) { + /* We only copy back the values that changed */ + if (params32[i] < 0) + break; + params[i] = (GLint64) params32[i]; + } + } }