#include "imports.h"
#include "formats.h"
+#include "glformats.h"
#include "mipmap.h"
#include "mtypes.h"
#include "teximage.h"
+#include "texobj.h"
#include "texstore.h"
#include "image.h"
#include "macros.h"
GLuint *dst = (GLuint *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
- dst[i] = (GLfloat)(rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4);
+ dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
}
}
}
}
else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 3)) {
- DECLARE_ROW_POINTERS(GLhalfARB, 4);
+ DECLARE_ROW_POINTERS(GLhalfARB, 3);
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
}
}
else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 2)) {
- DECLARE_ROW_POINTERS(GLhalfARB, 4);
+ DECLARE_ROW_POINTERS(GLhalfARB, 2);
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
}
}
else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 1)) {
- DECLARE_ROW_POINTERS(GLhalfARB, 4);
+ DECLARE_ROW_POINTERS(GLhalfARB, 1);
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
}
}
+
+/**
+ * Helper function for mipmap generation.
+ * Make sure the specified destination mipmap level is the right size/format
+ * 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, gl_format format)
+{
+ const GLuint numFaces = _mesa_num_tex_faces(texObj->Target);
+ GLuint face;
+
+ if (texObj->Immutable) {
+ /* The texture was created with glTexStorage() so the number/size of
+ * mipmap levels is fixed and the storage for all images is already
+ * allocated.
+ */
+ if (!texObj->Image[0][level]) {
+ /* No more levels to create - we're done */
+ return GL_FALSE;
+ }
+ else {
+ /* Nothing to do - the texture memory must have already been
+ * allocated to the right size so we're all set.
+ */
+ return GL_TRUE;
+ }
+ }
+
+ 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;
+
+ dstImage = _mesa_get_tex_image(ctx, texObj, target, level);
+ if (!dstImage) {
+ /* out of memory */
+ return GL_FALSE;
+ }
+
+ if (dstImage->Width != width ||
+ dstImage->Height != height ||
+ dstImage->Depth != depth ||
+ dstImage->Border != border ||
+ dstImage->InternalFormat != intFormat ||
+ dstImage->TexFormat != format) {
+ /* need to (re)allocate image */
+ ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
+
+ _mesa_init_teximage_fields(ctx, dstImage,
+ width, height, depth,
+ border, intFormat, format);
+
+ ctx->Driver.AllocTextureImageBuffer(ctx, dstImage);
+
+ /* in case the mipmap level is part of an FBO: */
+ _mesa_update_fbo_texture(ctx, texObj, face, level);
+
+ ctx->NewState |= _NEW_TEXTURE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
static void
generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
struct gl_texture_object *texObj,
GLint slice;
GLboolean nextLevel;
GLubyte **srcMaps, **dstMaps;
+ GLboolean success = GL_TRUE;
/* get src image parameters */
srcImage = _mesa_select_tex_image(ctx, texObj, target, level);
if (!nextLevel)
return;
- /* get dest gl_texture_image */
- dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
- if (!dstImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+ if (!_mesa_prepare_mipmap_level(ctx, texObj, level + 1,
+ dstWidth, dstHeight, dstDepth,
+ border, srcImage->InternalFormat,
+ srcImage->TexFormat)) {
return;
}
- /* Free old image data */
- ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
-
- _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
- dstDepth, border, srcImage->InternalFormat,
- srcImage->TexFormat);
-
- /* Alloc storage for new texture image */
- if (!ctx->Driver.AllocTextureImageBuffer(ctx, dstImage,
- dstImage->TexFormat,
- dstWidth, dstHeight,
- dstDepth)) {
+ /* get dest gl_texture_image */
+ dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
+ if (!dstImage) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
return;
}
- ASSERT(dstImage->TexFormat);
-
if (target == GL_TEXTURE_1D_ARRAY) {
srcDepth = srcHeight;
dstDepth = dstHeight;
}
/* Map src texture image slices */
- srcMaps = (GLubyte **) malloc(srcDepth * sizeof(GLubyte *));
- for (slice = 0; slice < srcDepth; slice++) {
- ctx->Driver.MapTextureImage(ctx, srcImage, slice,
- 0, 0, srcWidth, srcHeight,
- GL_MAP_READ_BIT,
- &srcMaps[slice], &srcRowStride);
+ srcMaps = calloc(srcDepth, sizeof(GLubyte *));
+ if (srcMaps) {
+ for (slice = 0; slice < srcDepth; slice++) {
+ ctx->Driver.MapTextureImage(ctx, srcImage, slice,
+ 0, 0, srcWidth, srcHeight,
+ GL_MAP_READ_BIT,
+ &srcMaps[slice], &srcRowStride);
+ if (!srcMaps[slice]) {
+ success = GL_FALSE;
+ break;
+ }
+ }
+ }
+ else {
+ success = GL_FALSE;
}
/* Map dst texture image slices */
- dstMaps = (GLubyte **) malloc(dstDepth * sizeof(GLubyte *));
- for (slice = 0; slice < dstDepth; slice++) {
- ctx->Driver.MapTextureImage(ctx, dstImage, slice,
- 0, 0, dstWidth, dstHeight,
- GL_MAP_WRITE_BIT,
- &dstMaps[slice], &dstRowStride);
+ dstMaps = calloc(dstDepth, sizeof(GLubyte *));
+ if (dstMaps) {
+ for (slice = 0; slice < dstDepth; slice++) {
+ ctx->Driver.MapTextureImage(ctx, dstImage, slice,
+ 0, 0, dstWidth, dstHeight,
+ GL_MAP_WRITE_BIT,
+ &dstMaps[slice], &dstRowStride);
+ if (!dstMaps[slice]) {
+ success = GL_FALSE;
+ break;
+ }
+ }
+ }
+ else {
+ success = GL_FALSE;
}
- /* generate one mipmap level (for 1D/2D/3D/array/etc texture) */
- _mesa_generate_mipmap_level(target, datatype, comps, border,
- srcWidth, srcHeight, srcDepth,
- (const GLubyte **) srcMaps, srcRowStride,
- dstWidth, dstHeight, dstDepth,
- dstMaps, dstRowStride);
+ if (success) {
+ /* generate one mipmap level (for 1D/2D/3D/array/etc texture) */
+ _mesa_generate_mipmap_level(target, datatype, comps, border,
+ srcWidth, srcHeight, srcDepth,
+ (const GLubyte **) srcMaps, srcRowStride,
+ dstWidth, dstHeight, dstDepth,
+ dstMaps, dstRowStride);
+ }
/* Unmap src image slices */
- for (slice = 0; slice < srcDepth; slice++) {
- ctx->Driver.UnmapTextureImage(ctx, srcImage, slice);
+ if (srcMaps) {
+ for (slice = 0; slice < srcDepth; slice++) {
+ if (srcMaps[slice]) {
+ ctx->Driver.UnmapTextureImage(ctx, srcImage, slice);
+ }
+ }
+ free(srcMaps);
}
- free(srcMaps);
/* Unmap dst image slices */
- for (slice = 0; slice < dstDepth; slice++) {
- ctx->Driver.UnmapTextureImage(ctx, dstImage, slice);
+ if (dstMaps) {
+ for (slice = 0; slice < dstDepth; slice++) {
+ if (dstMaps[slice]) {
+ ctx->Driver.UnmapTextureImage(ctx, dstImage, slice);
+ }
+ }
+ free(dstMaps);
}
- free(dstMaps);
+ if (!success) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "mipmap generation");
+ break;
+ }
} /* loop over mipmap levels */
}
/* allocate storage for the temporary, uncompressed image */
/* 20 extra bytes, just be safe when calling last FetchTexel */
temp_src_stride = _mesa_format_row_stride(temp_format, srcImage->Width);
- temp_src = (GLubyte *) malloc(temp_src_stride * srcImage->Height + 20);
+ temp_src = malloc(temp_src_stride * srcImage->Height + 20);
if (!temp_src) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
return;
temp_dst_stride = _mesa_format_row_stride(temp_format, dstWidth);
if (!temp_dst) {
- temp_dst = (GLubyte *) malloc(temp_dst_stride * dstHeight);
+ temp_dst = malloc(temp_dst_stride * dstHeight);
if (!temp_dst) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
break;
dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
if (!dstImage) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+ free(temp_dst);
return;
}
- /* Free old image data */
- ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
-
+ /* rescale src image to dest image */
_mesa_generate_mipmap_level(target, temp_datatype, components, border,
srcWidth, srcHeight, srcDepth,
(const GLubyte **) &temp_src,
dstWidth, dstHeight, dstDepth,
&temp_dst, temp_dst_stride);
- /* initialize new image */
- _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
- dstDepth, border, srcImage->InternalFormat,
- srcImage->TexFormat);
-
- /* Free old dest texture image buffer */
- ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
+ if (!_mesa_prepare_mipmap_level(ctx, texObj, level + 1,
+ dstWidth, dstHeight, dstDepth,
+ border, srcImage->InternalFormat,
+ srcImage->TexFormat)) {
+ free(temp_dst);
+ return;
+ }
- ctx->Driver.TexImage2D(ctx, target, level + 1,
- srcImage->InternalFormat,
- dstWidth, dstHeight, border,
- temp_base_format, temp_datatype,
- temp_dst, &ctx->DefaultPacking, texObj, dstImage);
+ /* The image space was allocated above so use glTexSubImage now */
+ ctx->Driver.TexSubImage(ctx, 2, dstImage,
+ 0, 0, 0, dstWidth, dstHeight, 1,
+ temp_base_format, temp_datatype,
+ temp_dst, &ctx->DefaultPacking);
/* swap src and dest pointers */
{