X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fformatquery.c;h=3b0f6dafad7644835eae42fb6778b8bfba10635a;hb=70b6972140e74037109b7f8c57d442c8316d09dc;hp=14c69f629df365ef6d12ca3468a96dfa473bcc8f;hpb=e98a3c799f5db65966f87c5d59552ae22a001084;p=mesa.git diff --git a/src/mesa/main/formatquery.c b/src/mesa/main/formatquery.c index 14c69f629df..3b0f6dafad7 100644 --- a/src/mesa/main/formatquery.c +++ b/src/mesa/main/formatquery.c @@ -30,6 +30,12 @@ #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" static bool _is_renderable(struct gl_context *ctx, GLenum internalformat) @@ -210,6 +216,8 @@ _legal_parameters(struct gl_context *ctx, GLenum target, GLenum internalformat, case GL_CLEAR_BUFFER: case GL_TEXTURE_VIEW: case GL_VIEW_COMPATIBILITY_CLASS: + case GL_NUM_TILING_TYPES_EXT: + case GL_TILING_TYPES_EXT: /* The ARB_internalformat_query spec says: * * "If the parameter to GetInternalformativ is not SAMPLES @@ -278,9 +286,16 @@ _set_default_response(GLenum pname, GLint buffer[16]) */ switch(pname) { case GL_SAMPLES: + case GL_TILING_TYPES_EXT: break; 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: @@ -297,6 +312,7 @@ _set_default_response(GLenum pname, GLint buffer[16]) case GL_TEXTURE_COMPRESSED_BLOCK_WIDTH: case GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT: case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: + case GL_NUM_TILING_TYPES_EXT: buffer[0] = 0; break; @@ -375,29 +391,27 @@ _is_target_supported(struct gl_context *ctx, GLenum target) * "if a particular type of is not supported by the * implementation the "unsupported" answer should be given. * This is not an error." + * + * Note that legality of targets has already been verified. */ switch(target){ + case GL_TEXTURE_1D: 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))) + if (!_mesa_has_EXT_texture_array(ctx)) return false; break; case GL_TEXTURE_CUBE_MAP: - if (!_mesa_has_ARB_texture_cube_map(ctx)) + if (ctx->API != API_OPENGL_CORE && !_mesa_has_ARB_texture_cube_map(ctx)) return false; break; @@ -407,7 +421,7 @@ _is_target_supported(struct gl_context *ctx, GLenum target) break; case GL_TEXTURE_RECTANGLE: - if (!_mesa_has_NV_texture_rectangle(ctx)) + if (!_mesa_has_ARB_texture_rectangle(ctx)) return false; break; @@ -487,8 +501,7 @@ _is_resource_supported(struct gl_context *ctx, GLenum target, /* 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))) + !_mesa_target_can_be_compressed(ctx, target, internalformat, NULL)) return false; break; @@ -544,15 +557,29 @@ _is_internalformat_supported(struct gl_context *ctx, GLenum target, * implementation accepts it for any texture specification commands, and * - unsized or base internal format, if the implementation accepts * it for texture or image specification. + * + * But also: + * "If the particualar and combination do not make + * sense, or if a particular type of is not supported by the + * implementation the "unsupported" answer should be given. This is not an + * error. */ GLint buffer[1]; - /* 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; + if (target == GL_RENDERBUFFER) { + if (_mesa_base_fbo_format(ctx, internalformat) == 0) { + return false; + } + } else if (target == GL_TEXTURE_BUFFER) { + if (_mesa_validate_texbuffer_format(ctx, internalformat) == + MESA_FORMAT_NONE) { + return false; + } + } else { + if (_mesa_base_tex_format(ctx, internalformat) < 0) { + return false; + } + } /* Let the driver have the final word */ ctx->Driver.QueryInternalFormat(ctx, target, internalformat, @@ -561,6 +588,34 @@ _is_internalformat_supported(struct gl_context *ctx, GLenum target, 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. */ @@ -569,9 +624,7 @@ _mesa_query_internal_format_default(struct gl_context *ctx, GLenum target, GLenum internalFormat, GLenum pname, GLint *params) { - (void) ctx; (void) target; - (void) internalFormat; switch (pname) { case GL_SAMPLES: @@ -587,12 +640,213 @@ _mesa_query_internal_format_default(struct gl_context *ctx, GLenum target, 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: + /* + * TODO seems a tad optimistic just saying yes to everything here. + * Even for combinations which make no sense... + * And things like TESS_CONTROL_TEXTURE should definitely default to + * NONE if the driver doesn't even support tessellation... + */ + params[0] = GL_FULL_SUPPORT; + break; + case GL_NUM_TILING_TYPES_EXT: + params[0] = 2; + break; + case GL_TILING_TYPES_EXT: + params[0] = GL_OPTIMAL_TILING_EXT; + params[1] = GL_LINEAR_TILING_EXT; + 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 +_equivalent_size_pname(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) @@ -651,6 +905,9 @@ _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, * "Since multisampling is not supported for signed and unsigned * integer internal formats, the value of NUM_SAMPLE_COUNTS will be * zero for such formats. + * + * Since OpenGL ES 3.1 adds support for multisampled integer formats, we + * have to check the version for 30 exactly. */ if (pname == GL_NUM_SAMPLE_COUNTS && ctx->API == API_OPENGLES2 && ctx->Version == 30 && _mesa_is_enum_format_integer(internalformat)) { @@ -676,7 +933,10 @@ _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, * format for representing resources of the specified is * returned in . * - * Therefore, we let the driver answer. + * Therefore, we let the driver answer. Note that if we reach this + * point, it means that the internalformat is supported, so the driver + * is called just to try to get a preferred format. If not supported, + * GL_NONE was already returned and the driver is not called. */ ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); @@ -699,9 +959,6 @@ _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, 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); @@ -722,10 +979,7 @@ _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, * 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) { + if (texformat == MESA_FORMAT_R9G9B9E5_FLOAT) { buffer[0] = 5; } goto end; @@ -736,7 +990,8 @@ _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, switch (pname) { case GL_INTERNALFORMAT_DEPTH_SIZE: - if (!_mesa_has_ARB_depth_texture(ctx) && + if (ctx->API != API_OPENGL_CORE && + !_mesa_has_ARB_depth_texture(ctx) && target != GL_RENDERBUFFER && target != GL_TEXTURE_BUFFER) goto end; @@ -768,232 +1023,534 @@ _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, 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: - /* @TODO */ - break; - case GL_MAX_HEIGHT: - /* @TODO */ - break; + case GL_MAX_DEPTH: { + GLenum get_pname; + GLint dimensions; + GLint min_dimensions; - case GL_MAX_DEPTH: - /* @TODO */ + /* 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 = _equivalent_size_pname(target, pname); + if (get_pname == 0) + goto end; + + _mesa_GetIntegerv(get_pname, buffer); break; + } case GL_MAX_LAYERS: - /* @TODO */ - break; + if (!_mesa_has_EXT_texture_array(ctx)) + goto end; - case GL_MAX_COMBINED_DIMENSIONS: - /* @TODO */ + 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: - /* @TODO */ + /* 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: - /* @TODO */ + /* 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: - /* @TODO */ + /* 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: - /* @TODO */ - break; - case GL_DEPTH_RENDERABLE: - /* @TODO */ - break; - case GL_STENCIL_RENDERABLE: - /* @TODO */ - break; + if (!_is_renderable(ctx, internalformat)) + goto end; - case GL_FRAMEBUFFER_RENDERABLE: - /* @TODO */ - break; + 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; + } - case GL_FRAMEBUFFER_RENDERABLE_LAYERED: - /* @TODO */ + 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: - /* @TODO */ - break; + if (!_mesa_has_ARB_framebuffer_object(ctx)) + goto end; - case GL_READ_PIXELS: - /* @TODO */ - break; + if (target == GL_TEXTURE_BUFFER || + !_is_renderable(ctx, internalformat)) + goto end; - case GL_READ_PIXELS_FORMAT: - /* @TODO */ + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); break; + case GL_READ_PIXELS: + case GL_READ_PIXELS_FORMAT: case GL_READ_PIXELS_TYPE: - /* @TODO */ + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); break; case GL_TEXTURE_IMAGE_FORMAT: - /* @TODO */ - break; - - case GL_TEXTURE_IMAGE_TYPE: - /* @TODO */ - break; - case GL_GET_TEXTURE_IMAGE_FORMAT: - /* @TODO */ - break; - + case GL_TEXTURE_IMAGE_TYPE: case GL_GET_TEXTURE_IMAGE_TYPE: - /* @TODO */ + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); break; case GL_MIPMAP: - /* @TODO */ - break; - case GL_MANUAL_GENERATE_MIPMAP: - /* @TODO */ - break; - case GL_AUTO_GENERATE_MIPMAP: - /* @TODO */ + 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: - /* @TODO */ + 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: - /* @TODO */ + 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: - /* @TODO */ + if (!ctx->Extensions.EXT_sRGB || + !_mesa_is_color_format(internalformat)) { + goto end; + } + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); break; case GL_SRGB_DECODE_ARB: - /* @TODO */ + /* 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: - /* @TODO */ - break; + /* 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; - case GL_VERTEX_TEXTURE: - /* @TODO */ - break; + if (_mesa_is_enum_format_integer(internalformat)) + goto end; - case GL_TESS_CONTROL_TEXTURE: - /* @TODO */ - break; + if (target == GL_TEXTURE_BUFFER) + goto end; - case GL_TESS_EVALUATION_TEXTURE: - /* @TODO */ + /* 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: - /* @TODO */ - break; - case GL_FRAGMENT_TEXTURE: - /* @TODO */ - break; - case GL_COMPUTE_TEXTURE: - /* @TODO */ - break; + if (target == GL_RENDERBUFFER) + goto end; - case GL_TEXTURE_SHADOW: - /* @TODO */ - break; + if ((pname == GL_TESS_CONTROL_TEXTURE || + pname == GL_TESS_EVALUATION_TEXTURE) && + !_mesa_has_tessellation(ctx)) + goto end; - case GL_TEXTURE_GATHER: - /* @TODO */ + 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: - /* @TODO */ - break; + if (!_mesa_has_ARB_texture_gather(ctx)) + goto end; - case GL_SHADER_IMAGE_LOAD: - /* @TODO */ + /* 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: - /* @TODO */ + 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: - /* @TODO */ + 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: - /* @TODO */ + 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: - /* @TODO */ - break; + if (!_mesa_has_ARB_shader_image_load_store(ctx) || + target == GL_RENDERBUFFER) + goto end; - case GL_IMAGE_PIXEL_FORMAT: - /* @TODO */ + buffer[0] = _mesa_get_image_format_class(internalformat); break; - case GL_IMAGE_PIXEL_TYPE: - /* @TODO */ - break; + case GL_IMAGE_PIXEL_FORMAT: { + GLint base_format; - case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: - /* @TODO */ - break; + if (!_mesa_has_ARB_shader_image_load_store(ctx) || + target == GL_RENDERBUFFER || + !_mesa_is_shader_image_format_supported(ctx, internalformat)) + goto end; - case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST: - /* @TODO */ + 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_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST: - /* @TODO */ + 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; + + /* As pointed by the spec quote below, this pname query should return + * the same value that GetTexParameter. So if the target is not valid + * for GetTexParameter we return the unsupported value. The check below + * is the same target check used by GetTexParameter. + */ + int targetIndex = _mesa_tex_target_to_index(ctx, target); + if (targetIndex < 0 || targetIndex == TEXTURE_BUFFER_INDEX) + 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); - case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE: - /* @TODO */ 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: - /* @TODO */ + 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: - /* @TODO */ + buffer[0] = _mesa_is_compressed_format(ctx, internalformat); break; case GL_TEXTURE_COMPRESSED_BLOCK_WIDTH: - /* @TODO */ - break; - case GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT: - /* @TODO */ - break; + case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: { + mesa_format mesaformat; + GLint block_size; - case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: - /* @TODO */ + 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: - /* @TODO */ + if (target != GL_TEXTURE_BUFFER) + goto end; + + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); break; case GL_TEXTURE_VIEW: - /* @TODO */ + 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; - case GL_VIEW_COMPATIBILITY_CLASS: - /* @TODO */ + case GL_NUM_TILING_TYPES_EXT: + case GL_TILING_TYPES_EXT: + ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, + buffer); break; default: @@ -1026,6 +1583,7 @@ _mesa_GetInternalformati64v(GLenum target, GLenum internalformat, GLint params32[16]; unsigned i; GLsizei realSize = MIN2(bufSize, 16); + GLsizei callSize; GET_CURRENT_CONTEXT(ctx); @@ -1040,14 +1598,29 @@ _mesa_GetInternalformati64v(GLenum target, GLenum internalformat, * 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); - - _mesa_GetInternalformativ(target, internalformat, pname, realSize, params32); - - for (i = 0; i < realSize; i++) { - /* We only copy back the values that changed */ - if (params32[i] < 0) - break; - params[i] = (GLint64) params32[i]; + for (i = 0; i < realSize; i++) + params32[i] = -1; + + /* 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]; + } } }