* \file mipmap.c mipmap generation and teximage resizing functions.
*/
-#include "imports.h"
+#include "errors.h"
+
#include "formats.h"
#include "glformats.h"
#include "mipmap.h"
#include "texstore.h"
#include "image.h"
#include "macros.h"
-#include "../../gallium/auxiliary/util/u_format_rgb9e5.h"
-#include "../../gallium/auxiliary/util/u_format_r11g11b10f.h"
+#include "util/half_float.h"
+#include "util/format_rgb9e5.h"
+#include "util/format_r11g11b10f.h"
+
+
+/**
+ * Compute the expected number of mipmap levels in the texture given
+ * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
+ * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap
+ * levels should be generated.
+ */
+unsigned
+_mesa_compute_num_levels(struct gl_context *ctx,
+ struct gl_texture_object *texObj,
+ GLenum target)
+{
+ const struct gl_texture_image *baseImage;
+ GLuint numLevels;
+
+ baseImage = _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel);
+ numLevels = texObj->BaseLevel + baseImage->MaxNumLevels;
+ numLevels = MIN2(numLevels, (GLuint) texObj->MaxLevel + 1);
+ if (texObj->Immutable)
+ numLevels = MIN2(numLevels, texObj->NumLevels);
+ assert(numLevels >= 1);
+ return numLevels;
+}
static GLint
bytes_per_pixel(GLenum datatype, GLuint comps)
}
else {
- _mesa_problem(NULL, "bad format in do_row()");
+ unreachable("bad format in do_row()");
}
}
}
else {
- _mesa_problem(NULL, "bad format in do_row()");
+ unreachable("bad format in do_row()");
}
}
static void
make_2d_mipmap(GLenum datatype, GLuint comps, GLint border,
GLint srcWidth, GLint srcHeight,
- const GLubyte *srcPtr, GLint srcRowStride,
+ const GLubyte *srcPtr, GLint srcRowStride,
GLint dstWidth, GLint dstHeight,
- GLubyte *dstPtr, GLint dstRowStride)
+ GLubyte *dstPtr, GLint dstRowStride)
{
const GLint bpt = bytes_per_pixel(datatype, comps);
const GLint srcWidthNB = srcWidth - 2 * border; /* sizes w/out border */
GLubyte *dstImgRow = imgDst;
for (row = 0; row < dstHeightNB; row++) {
- do_row_3D(datatype, comps, srcWidthNB,
+ do_row_3D(datatype, comps, srcWidthNB,
srcImgARowA, srcImgARowB,
srcImgBRowA, srcImgBRowB,
dstWidthNB, dstImgRow);
dstWidth, dstData[0]);
break;
case GL_TEXTURE_2D:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
make_2d_mipmap(datatype, comps, border,
srcWidth, srcHeight, srcData[0], srcRowStride,
dstWidth, dstHeight, dstData[0], dstRowStride);
assert(srcHeight == 1);
assert(dstHeight == 1);
for (i = 0; i < dstDepth; i++) {
- make_1d_mipmap(datatype, comps, border,
- srcWidth, srcData[i],
- dstWidth, dstData[i]);
+ make_1d_mipmap(datatype, comps, border,
+ srcWidth, srcData[i],
+ dstWidth, dstData[i]);
}
break;
case GL_TEXTURE_2D_ARRAY_EXT:
case GL_TEXTURE_CUBE_MAP_ARRAY:
for (i = 0; i < dstDepth; i++) {
- make_2d_mipmap(datatype, comps, border,
- srcWidth, srcHeight, srcData[i], srcRowStride,
- dstWidth, dstHeight, dstData[i], dstRowStride);
+ make_2d_mipmap(datatype, comps, border,
+ srcWidth, srcHeight, srcData[i], srcRowStride,
+ dstWidth, dstHeight, dstData[i], dstRowStride);
}
break;
case GL_TEXTURE_RECTANGLE_NV:
/* no mipmaps, do nothing */
break;
default:
- _mesa_problem(NULL, "bad tex target in _mesa_generate_mipmaps");
- return;
+ unreachable("bad tex target in _mesa_generate_mipmaps");
}
}
*dstWidth = srcWidth; /* can't go smaller */
}
- if ((srcHeight - 2 * border > 1) &&
- (target != GL_TEXTURE_1D_ARRAY_EXT)) {
+ if ((srcHeight - 2 * border > 1) &&
+ target != GL_TEXTURE_1D_ARRAY_EXT &&
+ target != GL_PROXY_TEXTURE_1D_ARRAY_EXT) {
*dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
}
else {
}
if ((srcDepth - 2 * border > 1) &&
- (target != GL_TEXTURE_2D_ARRAY_EXT &&
- target != GL_TEXTURE_CUBE_MAP_ARRAY)) {
+ target != GL_TEXTURE_2D_ARRAY_EXT &&
+ target != GL_PROXY_TEXTURE_2D_ARRAY_EXT &&
+ target != GL_TEXTURE_CUBE_MAP_ARRAY &&
+ target != GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) {
*dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
}
else {
* for mipmap generation. If not, (re) allocate it.
* \return GL_TRUE if successful, GL_FALSE if mipmap generation should stop
*/
-GLboolean
-_mesa_prepare_mipmap_level(struct gl_context *ctx,
- struct gl_texture_object *texObj, GLuint level,
- GLsizei width, GLsizei height, GLsizei depth,
- GLsizei border, GLenum intFormat, mesa_format format)
+static GLboolean
+prepare_mipmap_level(struct gl_context *ctx,
+ struct gl_texture_object *texObj, GLuint level,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLsizei border, GLenum intFormat, mesa_format format)
{
const GLuint numFaces = _mesa_num_tex_faces(texObj->Target);
GLuint face;
for (face = 0; face < numFaces; face++) {
struct gl_texture_image *dstImage;
- GLenum target;
-
- if (numFaces == 1)
- target = texObj->Target;
- else
- target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+ const GLenum target = _mesa_cube_face_target(texObj->Target, face);
dstImage = _mesa_get_tex_image(ctx, texObj, target, level);
if (!dstImage) {
/* in case the mipmap level is part of an FBO: */
_mesa_update_fbo_texture(ctx, texObj, face, level);
- ctx->NewState |= _NEW_TEXTURE;
+ ctx->NewState |= _NEW_TEXTURE_OBJECT;
}
}
}
+/**
+ * Prepare all mipmap levels beyond 'baseLevel' for mipmap generation.
+ * When finished, all the gl_texture_image structures for the smaller
+ * mipmap levels will be consistent with the base level (in terms of
+ * dimensions, format, etc).
+ */
+void
+_mesa_prepare_mipmap_levels(struct gl_context *ctx,
+ struct gl_texture_object *texObj,
+ unsigned baseLevel, unsigned maxLevel)
+{
+ const struct gl_texture_image *baseImage =
+ _mesa_select_tex_image(texObj, texObj->Target, baseLevel);
+ const GLint border = 0;
+ GLint width = baseImage->Width;
+ GLint height = baseImage->Height;
+ GLint depth = baseImage->Depth;
+ const GLenum intFormat = baseImage->InternalFormat;
+ const mesa_format texFormat = baseImage->TexFormat;
+ GLint newWidth, newHeight, newDepth;
+
+ /* Prepare baseLevel + 1, baseLevel + 2, ... */
+ for (unsigned level = baseLevel + 1; level <= maxLevel; level++) {
+ if (!_mesa_next_mipmap_level_size(texObj->Target, border,
+ width, height, depth,
+ &newWidth, &newHeight, &newDepth)) {
+ /* all done */
+ break;
+ }
+
+ if (!prepare_mipmap_level(ctx, texObj, level,
+ newWidth, newHeight, newDepth,
+ border, intFormat, texFormat)) {
+ break;
+ }
+
+ width = newWidth;
+ height = newHeight;
+ depth = newDepth;
+ }
+}
+
+
static void
generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj,
- const struct gl_texture_image *srcImage,
- GLuint maxLevel)
+ struct gl_texture_object *texObj,
+ const struct gl_texture_image *srcImage,
+ GLuint maxLevel)
{
GLuint level;
GLenum datatype;
GLint dstWidth, dstHeight, dstDepth;
GLint border;
GLint slice;
- GLboolean nextLevel;
GLubyte **srcMaps, **dstMaps;
GLboolean success = GL_TRUE;
srcDepth = srcImage->Depth;
border = srcImage->Border;
- nextLevel = _mesa_next_mipmap_level_size(target, border,
- srcWidth, srcHeight, srcDepth,
- &dstWidth, &dstHeight, &dstDepth);
- if (!nextLevel)
- return;
-
- if (!_mesa_prepare_mipmap_level(ctx, texObj, level + 1,
- dstWidth, dstHeight, dstDepth,
- border, srcImage->InternalFormat,
- srcImage->TexFormat)) {
- return;
- }
-
/* get dest gl_texture_image */
dstImage = _mesa_select_tex_image(texObj, target, level + 1);
- assert(dstImage);
+ if (!dstImage) {
+ break;
+ }
+ dstWidth = dstImage->Width;
+ dstHeight = dstImage->Height;
+ dstDepth = dstImage->Depth;
if (target == GL_TEXTURE_1D_ARRAY) {
- srcDepth = srcHeight;
- dstDepth = dstHeight;
- srcHeight = 1;
- dstHeight = 1;
+ srcDepth = srcHeight;
+ dstDepth = dstHeight;
+ srcHeight = 1;
+ dstHeight = 1;
}
/* Map src texture image slices */
static void
generate_mipmap_compressed(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj,
- struct gl_texture_image *srcImage,
- GLuint maxLevel)
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *srcImage,
+ GLuint maxLevel)
{
GLuint level;
mesa_format temp_format;
/* only two types of compressed textures at this time */
assert(texObj->Target == GL_TEXTURE_2D ||
- texObj->Target == GL_TEXTURE_2D_ARRAY ||
- texObj->Target == GL_TEXTURE_CUBE_MAP_ARB ||
+ texObj->Target == GL_TEXTURE_2D_ARRAY ||
+ texObj->Target == GL_TEXTURE_CUBE_MAP ||
texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY);
/*
GLint srcWidth, srcHeight, srcDepth;
GLint dstWidth, dstHeight, dstDepth;
GLint border;
- GLboolean nextLevel;
GLuint temp_dst_row_stride, temp_dst_img_stride; /* in bytes */
GLint i;
srcDepth = srcImage->Depth;
border = srcImage->Border;
- nextLevel = _mesa_next_mipmap_level_size(target, border,
- srcWidth, srcHeight, srcDepth,
- &dstWidth, &dstHeight, &dstDepth);
- if (!nextLevel)
- goto end;
-
- if (!_mesa_prepare_mipmap_level(ctx, texObj, level + 1,
- dstWidth, dstHeight, dstDepth,
- border, srcImage->InternalFormat,
- srcImage->TexFormat)) {
- /* all done */
- goto end;
- }
-
/* get dest gl_texture_image */
dstImage = _mesa_select_tex_image(texObj, target, level + 1);
- assert(dstImage);
+ if (!dstImage) {
+ break;
+ }
+ dstWidth = dstImage->Width;
+ dstHeight = dstImage->Height;
+ dstDepth = dstImage->Depth;
/* Compute dst image strides and alloc memory on first iteration */
temp_dst_row_stride = _mesa_format_row_stride(temp_format, dstWidth);
temp_dst_img_stride = _mesa_format_image_size(temp_format, dstWidth,
dstHeight, 1);
if (!temp_dst) {
- temp_dst = malloc(temp_dst_img_stride * dstDepth);
- if (!temp_dst) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
+ temp_dst = malloc(temp_dst_img_stride * dstDepth);
+ if (!temp_dst) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
goto end;
- }
+ }
}
/* for 2D arrays, setup array[depth] of slice pointers */
/* swap src and dest pointers */
{
- GLubyte *temp = temp_src;
- temp_src = temp_dst;
- temp_dst = temp;
+ GLubyte *temp = temp_src;
+ temp_src = temp_dst;
+ temp_dst = temp;
temp_src_row_stride = temp_dst_row_stride;
temp_src_img_stride = temp_dst_img_stride;
}
maxLevel = MIN2(maxLevel, texObj->MaxLevel);
+ _mesa_prepare_mipmap_levels(ctx, texObj, texObj->BaseLevel, maxLevel);
+
if (_mesa_is_format_compressed(srcImage->TexFormat)) {
generate_mipmap_compressed(ctx, target, texObj, srcImage, maxLevel);
} else {