/* Work back from the specified level of the image to the baselevel and create a * miptree of that size. */ struct intel_mipmap_tree * intel_miptree_create_for_teximage(struct brw_context *brw, struct intel_texture_object *intelObj, struct intel_texture_image *intelImage, uint32_t layout_flags) { GLuint lastLevel; int width, height, depth; GLuint i; intel_miptree_get_dimensions_for_image(&intelImage->base.Base, &width, &height, &depth); DBG("%s\n", __func__); /* Figure out image dimensions at start level. */ for (i = intelImage->base.Base.Level; i > 0; i--) { width <<= 1; if (height != 1) height <<= 1; if (depth != 1) depth <<= 1; } /* Guess a reasonable value for lastLevel. This is probably going * to be wrong fairly often and might mean that we have to look at * resizable buffers, or require that buffers implement lazy * pagetable arrangements. */ if ((intelObj->base.Sampler.MinFilter == GL_NEAREST || intelObj->base.Sampler.MinFilter == GL_LINEAR) && intelImage->base.Base.Level == 0 && !intelObj->base.GenerateMipmap) { lastLevel = 0; } else { lastLevel = _mesa_get_tex_max_num_levels(intelObj->base.Target, width, height, depth) - 1; } return intel_miptree_create(brw, intelObj->base.Target, intelImage->base.Base.TexFormat, 0, lastLevel, width, height, depth, intelImage->base.Base.NumSamples, layout_flags | MIPTREE_LAYOUT_ALLOC_ANY_TILED); }
/** * Do error checking for calls to glTexStorage1/2/3D(). * If an error is found, record it with _mesa_error(), unless the target * is a proxy texture. * \return GL_TRUE if any error, GL_FALSE otherwise. */ static GLboolean tex_storage_error_check(struct gl_context *ctx, struct gl_texture_object *texObj, GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool dsa) { const char* suffix = dsa ? "ture" : ""; /* Legal format checking has been moved to texstorage and texturestorage in * order to allow meta functions to use legacy formats. */ /* size check */ if (!_mesa_valid_tex_storage_dim(width, height, depth)) { _mesa_error(ctx, GL_INVALID_VALUE, "glTex%sStorage%uD(width, height or depth < 1)", suffix, dims); return GL_TRUE; } if (_mesa_is_compressed_format(ctx, internalformat)) { GLenum err; if (!_mesa_target_can_be_compressed(ctx, target, internalformat, &err)) { _mesa_error(ctx, err, "glTex%sStorage%dD(internalformat = %s)", suffix, dims, _mesa_enum_to_string(internalformat)); return GL_TRUE; } } /* levels check */ if (levels < 1) { _mesa_error(ctx, GL_INVALID_VALUE, "glTex%sStorage%uD(levels < 1)", suffix, dims); return GL_TRUE; } /* check levels against maximum (note different error than above) */ if (levels > (GLint) _mesa_max_texture_levels(ctx, target)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(levels too large)", suffix, dims); return GL_TRUE; } /* check levels against width/height/depth */ if (levels > _mesa_get_tex_max_num_levels(target, width, height, depth)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(too many levels" " for max texture dimension)", suffix, dims); return GL_TRUE; } /* non-default texture object check */ if (!_mesa_is_proxy_texture(target) && (!texObj || (texObj->Name == 0))) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(texture object 0)", suffix, dims); return GL_TRUE; } /* Check if texObj->Immutable is set */ if (!_mesa_is_proxy_texture(target) && texObj->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(immutable)", suffix, dims); return GL_TRUE; } /* additional checks for depth textures */ if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalformat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(bad target for texture)", suffix, dims); return GL_TRUE; } return GL_FALSE; }
/* Work back from the specified level of the image to the baselevel and create a * miptree of that size. */ struct intel_mipmap_tree * intel_miptree_create_for_teximage(struct intel_context *intel, struct intel_texture_object *intelObj, struct intel_texture_image *intelImage, bool expect_accelerated_upload) { GLuint firstLevel; GLuint lastLevel; int width, height, depth; GLuint i; intel_miptree_get_dimensions_for_image(&intelImage->base.Base, &width, &height, &depth); DBG("%s\n", __FUNCTION__); if (intelImage->base.Base.Level > intelObj->base.BaseLevel && (width == 1 || (intelObj->base.Target != GL_TEXTURE_1D && height == 1) || (intelObj->base.Target == GL_TEXTURE_3D && depth == 1))) { /* For this combination, we're at some lower mipmap level and * some important dimension is 1. We can't extrapolate up to a * likely base level width/height/depth for a full mipmap stack * from this info, so just allocate this one level. */ firstLevel = intelImage->base.Base.Level; lastLevel = intelImage->base.Base.Level; } else { /* If this image disrespects BaseLevel, allocate from level zero. * Usually BaseLevel == 0, so it's unlikely to happen. */ if (intelImage->base.Base.Level < intelObj->base.BaseLevel) firstLevel = 0; else firstLevel = intelObj->base.BaseLevel; /* Figure out image dimensions at start level. */ for (i = intelImage->base.Base.Level; i > firstLevel; i--) { width <<= 1; if (height != 1) height <<= 1; if (depth != 1) depth <<= 1; } /* Guess a reasonable value for lastLevel. This is probably going * to be wrong fairly often and might mean that we have to look at * resizable buffers, or require that buffers implement lazy * pagetable arrangements. */ if ((intelObj->base.Sampler.MinFilter == GL_NEAREST || intelObj->base.Sampler.MinFilter == GL_LINEAR) && intelImage->base.Base.Level == firstLevel) { lastLevel = firstLevel; } else { lastLevel = (firstLevel + _mesa_get_tex_max_num_levels(intelObj->base.Target, width, height, depth) - 1); } } return intel_miptree_create(intel, intelObj->base.Target, intelImage->base.Base.TexFormat, firstLevel, lastLevel, width, height, depth, expect_accelerated_upload, INTEL_MIPTREE_TILING_ANY); }
/** * Try to allocate a pipe_resource object for the given st_texture_object. * * We use the given st_texture_image as a clue to determine the size of the * mipmap image at level=0. * * \return GL_TRUE for success, GL_FALSE if out of memory. */ static GLboolean guess_and_alloc_texture(struct st_context *st, struct st_texture_object *stObj, const struct st_texture_image *stImage) { GLuint lastLevel, width, height, depth; GLuint bindings; GLuint ptWidth, ptHeight, ptDepth, ptLayers; enum pipe_format fmt; DBG("%s\n", __FUNCTION__); assert(!stObj->pt); if (!guess_base_level_size(stObj->base.Target, stImage->base.Width2, stImage->base.Height2, stImage->base.Depth2, stImage->base.Level, &width, &height, &depth)) { /* we can't determine the image size at level=0 */ stObj->width0 = stObj->height0 = stObj->depth0 = 0; /* this is not an out of memory error */ return GL_TRUE; } /* At this point, (width x height x depth) is the expected size of * the level=0 mipmap image. */ /* Guess a reasonable value for lastLevel. With OpenGL we have no * idea how many mipmap levels will be in a texture until we start * to render with it. Make an educated guess here but be prepared * to re-allocating a texture buffer with space for more (or fewer) * mipmap levels later. */ if ((stObj->base.Sampler.MinFilter == GL_NEAREST || stObj->base.Sampler.MinFilter == GL_LINEAR || (stObj->base.BaseLevel == 0 && stObj->base.MaxLevel == 0) || stImage->base._BaseFormat == GL_DEPTH_COMPONENT || stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) && !stObj->base.GenerateMipmap && stImage->base.Level == 0) { /* only alloc space for a single mipmap level */ lastLevel = 0; } else { /* alloc space for a full mipmap */ lastLevel = _mesa_get_tex_max_num_levels(stObj->base.Target, width, height, depth) - 1; } /* Save the level=0 dimensions */ stObj->width0 = width; stObj->height0 = height; stObj->depth0 = depth; fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat); bindings = default_bindings(st, fmt); st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); stObj->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), fmt, lastLevel, ptWidth, ptHeight, ptDepth, ptLayers, bindings); stObj->lastLevel = lastLevel; DBG("%s returning %d\n", __FUNCTION__, (stObj->pt != NULL)); return stObj->pt != NULL; }
/** * Do error checking for calls to glTexStorage1/2/3D(). * If an error is found, record it with _mesa_error(), unless the target * is a proxy texture. * \return GL_TRUE if any error, GL_FALSE otherwise. */ static GLboolean tex_storage_error_check(struct gl_context *ctx, GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { struct gl_texture_object *texObj; GLboolean legalFormat; /* check internal format - note that only sized formats are allowed */ switch (internalformat) { case GL_ALPHA: case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: case GL_INTENSITY: case GL_RED: case GL_RG: case GL_RGB: case GL_RGBA: case GL_BGRA: case GL_DEPTH_COMPONENT: case GL_DEPTH_STENCIL: case GL_COMPRESSED_ALPHA: case GL_COMPRESSED_LUMINANCE_ALPHA: case GL_COMPRESSED_LUMINANCE: case GL_COMPRESSED_INTENSITY: case GL_COMPRESSED_RGB: case GL_COMPRESSED_RGBA: case GL_COMPRESSED_SRGB: case GL_COMPRESSED_SRGB_ALPHA: case GL_COMPRESSED_SLUMINANCE: case GL_COMPRESSED_SLUMINANCE_ALPHA: case GL_RED_INTEGER: case GL_GREEN_INTEGER: case GL_BLUE_INTEGER: case GL_ALPHA_INTEGER: case GL_RGB_INTEGER: case GL_RGBA_INTEGER: case GL_BGR_INTEGER: case GL_BGRA_INTEGER: case GL_LUMINANCE_INTEGER_EXT: case GL_LUMINANCE_ALPHA_INTEGER_EXT: /* these unsized formats are illegal */ legalFormat = GL_FALSE; break; default: legalFormat = _mesa_base_tex_format(ctx, internalformat) > 0; } if (!legalFormat) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexStorage%uD(internalformat = %s)", dims, _mesa_lookup_enum_by_nr(internalformat)); return GL_TRUE; } /* size check */ if (width < 1 || height < 1 || depth < 1) { _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(width, height or depth < 1)", dims); return GL_TRUE; } /* target check */ if (!legal_texobj_target(ctx, dims, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexStorage%uD(illegal target=%s)", dims, _mesa_lookup_enum_by_nr(target)); return GL_TRUE; } /* levels check */ if (levels < 1) { _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(levels < 1)", dims); return GL_TRUE; } /* check levels against maximum (note different error than above) */ if (levels > (GLint) _mesa_max_texture_levels(ctx, target)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(levels too large)", dims); return GL_TRUE; } /* check levels against width/height/depth */ if (levels > _mesa_get_tex_max_num_levels(target, width, height, depth)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(too many levels for max texture dimension)", dims); return GL_TRUE; } /* non-default texture object check */ texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj || (texObj->Name == 0)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(texture object 0)", dims); return GL_TRUE; } /* Check if texObj->Immutable is set */ if (texObj->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(immutable)", dims); return GL_TRUE; } return GL_FALSE; }
/** * Do error checking for calls to glTexStorage1/2/3D(). * If an error is found, record it with _mesa_error(), unless the target * is a proxy texture. * \return GL_TRUE if any error, GL_FALSE otherwise. */ static GLboolean tex_storage_error_check(struct gl_context *ctx, GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { struct gl_texture_object *texObj; if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexStorage%uD(internalformat = %s)", dims, _mesa_lookup_enum_by_nr(internalformat)); return GL_TRUE; } /* size check */ if (width < 1 || height < 1 || depth < 1) { _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(width, height or depth < 1)", dims); return GL_TRUE; } /* target check */ if (!legal_texobj_target(ctx, dims, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexStorage%uD(illegal target=%s)", dims, _mesa_lookup_enum_by_nr(target)); return GL_TRUE; } /* From section 3.8.6, page 146 of OpenGL ES 3.0 spec: * * "The ETC2/EAC texture compression algorithm supports only * two-dimensional images. If internalformat is an ETC2/EAC format, * CompressedTexImage3D will generate an INVALID_OPERATION error if * target is not TEXTURE_2D_ARRAY." * * This should also be applicable for glTexStorage3D(). */ if (_mesa_is_compressed_format(ctx, internalformat) && !_mesa_target_can_be_compressed(ctx, target, internalformat)) { _mesa_error(ctx, _mesa_is_desktop_gl(ctx)? GL_INVALID_ENUM : GL_INVALID_OPERATION, "glTexStorage3D(internalformat = %s)", _mesa_lookup_enum_by_nr(internalformat)); } /* levels check */ if (levels < 1) { _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(levels < 1)", dims); return GL_TRUE; } /* check levels against maximum (note different error than above) */ if (levels > (GLint) _mesa_max_texture_levels(ctx, target)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(levels too large)", dims); return GL_TRUE; } /* check levels against width/height/depth */ if (levels > _mesa_get_tex_max_num_levels(target, width, height, depth)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(too many levels for max texture dimension)", dims); return GL_TRUE; } /* non-default texture object check */ texObj = _mesa_get_current_tex_object(ctx, target); if (!_mesa_is_proxy_texture(target) && (!texObj || (texObj->Name == 0))) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(texture object 0)", dims); return GL_TRUE; } /* Check if texObj->Immutable is set */ if (!_mesa_is_proxy_texture(target) && texObj->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(immutable)", dims); return GL_TRUE; } /* additional checks for depth textures */ if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalformat, dims, "glTexStorage")) return GL_TRUE; return GL_FALSE; }
/* Work back from the specified level of the image to the baselevel and create a * miptree of that size. */ struct intel_mipmap_tree * intel_miptree_create_for_teximage(struct brw_context *brw, struct intel_texture_object *intelObj, struct intel_texture_image *intelImage, uint32_t layout_flags) { GLuint lastLevel; int width, height, depth; intel_get_image_dims(&intelImage->base.Base, &width, &height, &depth); DBG("%s\n", __func__); /* Figure out image dimensions at start level. */ switch(intelObj->base.Target) { case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_EXTERNAL_OES: assert(intelImage->base.Base.Level == 0); break; case GL_TEXTURE_3D: depth <<= intelImage->base.Base.Level; /* Fall through */ case GL_TEXTURE_2D: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP_ARRAY: height <<= intelImage->base.Base.Level; /* Fall through */ case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: width <<= intelImage->base.Base.Level; break; default: unreachable("Unexpected target"); } /* Guess a reasonable value for lastLevel. This is probably going * to be wrong fairly often and might mean that we have to look at * resizable buffers, or require that buffers implement lazy * pagetable arrangements. */ if ((intelObj->base.Sampler.MinFilter == GL_NEAREST || intelObj->base.Sampler.MinFilter == GL_LINEAR) && intelImage->base.Base.Level == 0 && !intelObj->base.GenerateMipmap) { lastLevel = 0; } else { lastLevel = _mesa_get_tex_max_num_levels(intelObj->base.Target, width, height, depth) - 1; } return intel_miptree_create(brw, intelObj->base.Target, intelImage->base.Base.TexFormat, 0, lastLevel, width, height, depth, intelImage->base.Base.NumSamples, layout_flags | MIPTREE_LAYOUT_TILING_ANY); }