-/* $Id: texstore.c,v 1.36 2002/04/04 16:59:05 brianp Exp $ */
-
/*
* Mesa 3-D graphics library
- * Version: 4.1
+ * Version: 5.1
*
- * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* Brian Paul
*/
+/*
+ * The GL texture image functions in teximage.c basically just do
+ * error checking and data structure allocation. They in turn call
+ * device driver functions which actually copy/convert/store the user's
+ * texture image data.
+ *
+ * However, most device drivers will be able to use the fallback functions
+ * in this file. That is, most drivers will have the following bit of
+ * code:
+ * ctx->Driver.TexImage1D = _mesa_store_teximage1d;
+ * ctx->Driver.TexImage2D = _mesa_store_teximage2d;
+ * ctx->Driver.TexImage3D = _mesa_store_teximage3d;
+ * etc...
+ *
+ * Texture image processing is actually kind of complicated. We have to do:
+ * Format/type conversions
+ * pixel unpacking
+ * pixel transfer (scale, bais, lookup, convolution!, etc)
+ *
+ * These functions can handle most everything, including processing full
+ * images and sub-images.
+ */
+
+
+#include "glheader.h"
#include "colormac.h"
#include "context.h"
#include "convolve.h"
#include "image.h"
#include "macros.h"
-#include "mem.h"
+#include "imports.h"
+#include "texcompress.h"
#include "texformat.h"
#include "teximage.h"
#include "texstore.h"
* corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE,
* GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA. Return the
* number of components for the format. Return -1 if invalid enum.
- *
- * GH: Do we really need this? We have the number of bytes per texel
- * in the texture format structures, so why don't we just use that?
*/
static GLint
components_in_intformat( GLint format )
case GL_DEPTH_COMPONENT24_SGIX:
case GL_DEPTH_COMPONENT32_SGIX:
return 1;
+ case GL_YCBCR_MESA:
+ return 2; /* Y + (Cb or Cr) */
default:
return -1; /* error */
}
* We also take care of all image transfer operations here, including
* convolution, scale/bias, colortables, etc.
*
- * The destination texel channel type is always GLchan.
+ * The destination texel type is always GLchan.
+ * The destination texel format is one of the 6 basic types.
*
* A hardware driver may use this as a helper routine to unpack and
* apply pixel transfer ops into a temporary image buffer. Then,
* convert the temporary image into the special hardware format.
*
- * Input:
+ * \param
* dimensions - 1, 2, or 3
- * texFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA,
- * GL_RGB or GL_RGBA
+ * texDestFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA,
+ * GL_RGB or GL_RGBA (the destination format)
* texDestAddr - destination image address
* srcWidth, srcHeight, srcDepth - size (in pixels) of src and dest images
* dstXoffset, dstYoffset, dstZoffset - position to store the image within
ASSERT(ctx);
ASSERT(dimensions >= 1 && dimensions <= 3);
+ ASSERT(texDestFormat == GL_LUMINANCE ||
+ texDestFormat == GL_INTENSITY ||
+ texDestFormat == GL_LUMINANCE_ALPHA ||
+ texDestFormat == GL_ALPHA ||
+ texDestFormat == GL_RGB ||
+ texDestFormat == GL_RGBA ||
+ texDestFormat == GL_COLOR_INDEX ||
+ texDestFormat == GL_DEPTH_COMPONENT);
ASSERT(texDestAddr);
- ASSERT(srcWidth >= 1);
- ASSERT(srcHeight >= 1);
- ASSERT(srcDepth >= 1);
+ ASSERT(srcWidth >= 0);
+ ASSERT(srcHeight >= 0);
+ ASSERT(srcDepth >= 0);
ASSERT(dstXoffset >= 0);
ASSERT(dstYoffset >= 0);
ASSERT(dstZoffset >= 0);
dest += dstImageStride;
}
}
+ else if (texDestFormat == GL_YCBCR_MESA) {
+ /* YCbCr texture */
+ GLint img, row;
+ GLushort *dest = (GLushort *) texDestAddr
+ + dstZoffset * (dstImageStride / sizeof(GLushort))
+ + dstYoffset * (dstRowStride / sizeof(GLushort))
+ + dstXoffset * texComponents;
+ ASSERT(ctx->Extensions.MESA_ycbcr_texture);
+ for (img = 0; img < srcDepth; img++) {
+ GLushort *destRow = dest;
+ for (row = 0; row < srcHeight; row++) {
+ const GLvoid *srcRow = _mesa_image_address(srcPacking,
+ srcAddr, srcWidth, srcHeight,
+ srcFormat, srcType, img, row, 0);
+ MEMCPY(destRow, srcRow, srcWidth * sizeof(GLushort));
+ destRow += (dstRowStride / sizeof(GLushort));
+ }
+ dest += dstImageStride / sizeof(GLushort);
+ }
+ }
else if (texDestFormat == GL_DEPTH_COMPONENT) {
/* Depth texture (shadow maps) */
GLint img, row;
* Transfer a texture image from user space to <destAddr> applying all
* needed image transfer operations and storing the result in the format
* specified by <dstFormat>. <dstFormat> may be any format from texformat.h.
- * Input:
+ * \param
* dimensions - 1, 2 or 3
* baseInternalFormat - base format of the internal texture format
* specified by the user. This is very important, see below.
* dstX/Y/Zoffset - as specified by glTexSubImage
* dstRowStride - stride between dest rows in bytes
* dstImageStride - stride between dest images in bytes
- * srcFormat, srcType - incoming image format and datatype
+ * srcFormat, srcType - incoming image format and data type
* srcAddr - source image address
* srcPacking - packing params of source image
*
GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
assert(baseInternalFormat > 0);
+ ASSERT(baseInternalFormat == GL_LUMINANCE ||
+ baseInternalFormat == GL_INTENSITY ||
+ baseInternalFormat == GL_LUMINANCE_ALPHA ||
+ baseInternalFormat == GL_ALPHA ||
+ baseInternalFormat == GL_RGB ||
+ baseInternalFormat == GL_RGBA ||
+ baseInternalFormat == GL_YCBCR_MESA ||
+ baseInternalFormat == GL_COLOR_INDEX ||
+ baseInternalFormat == GL_DEPTH_COMPONENT);
if (transferOps & IMAGE_CONVOLUTION_BIT) {
_mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
srcPacking, srcAddr,
dstAddr);
assert(b);
+ (void) b;
}
else if (dimensions == 2) {
GLboolean b;
srcPacking, srcAddr,
dstAddr);
assert(b);
+ (void) b;
}
else {
GLboolean b;
srcFormat, srcType,
srcPacking, srcAddr, dstAddr);
assert(b);
+ (void) b;
}
}
else {
}
+
+/**
+ * Given a user's uncompressed texture image, this function takes care of
+ * pixel unpacking, pixel transfer, format conversion and compression.
+ */
+static void
+transfer_compressed_teximage(GLcontext *ctx, GLuint dimensions,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum srcFormat, GLenum srcType,
+ const struct gl_pixelstore_attrib *unpacking,
+ const GLvoid *source,
+ const struct gl_texture_format *dstFormat,
+ GLubyte *dest,
+ GLint dstRowStride)
+{
+ GLchan *tempImage = NULL;
+ GLint srcRowStride;
+ GLenum baseFormat;
+
+ ASSERT(dimensions == 2);
+ /* TexelBytes is zero if and only if it's a compressed format */
+ ASSERT(dstFormat->TexelBytes == 0);
+
+ baseFormat = dstFormat->BaseFormat;
+
+ if (srcFormat != baseFormat || srcType != CHAN_TYPE ||
+ ctx->_ImageTransferState != 0 || unpacking->SwapBytes) {
+ /* need to convert user's image to texImage->Format, GLchan */
+ GLint comps = components_in_intformat(baseFormat);
+ GLint postConvWidth = width, postConvHeight = height;
+
+ /* XXX convolution untested */
+ if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
+ _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
+ &postConvHeight);
+ }
+
+ tempImage = (GLchan*) MALLOC(width * height * comps * sizeof(GLchan));
+ if (!tempImage) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+ return;
+ }
+ transfer_teximage(ctx, dimensions,
+ baseFormat, /* dest format */
+ tempImage, /* dst address */
+ width, height, depth, /* src size */
+ 0, 0, 0, /* x/y/zoffset */
+ comps * width, /* dst row stride */
+ comps * width * height, /* dst image stride */
+ srcFormat, srcType, /* src format, type */
+ source, unpacking, /* src and src packing */
+ ctx->_ImageTransferState);
+ source = tempImage;
+ width = postConvWidth;
+ height = postConvHeight;
+ srcRowStride = width;
+ }
+ else {
+ if (unpacking->RowLength)
+ srcRowStride = unpacking->RowLength;
+ else
+ srcRowStride = width;
+ }
+
+ _mesa_compress_teximage(ctx, width, height, baseFormat,
+ (const GLchan *) source, srcRowStride,
+ dstFormat, dest, dstRowStride);
+ if (tempImage) {
+ FREE(tempImage);
+ }
+}
+
+
+
/*
- * This is the software fallback for Driver.TexImage1D().
+ * This is the software fallback for Driver.TexImage1D()
+ * and Driver.CopyTexImage2D().
* The texture image type will be GLchan.
* The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
* GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
- *
*/
void
_mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
texelBytes = texImage->TexFormat->TexelBytes;
- /* Compute image size, in bytes */
- if (texImage->IsCompressed) {
- assert(ctx->Driver.CompressedTextureSize);
- sizeInBytes = ctx->Driver.CompressedTextureSize(ctx, texImage);
- assert(sizeInBytes > 0);
- texImage->CompressedSize = sizeInBytes;
- }
- else {
- sizeInBytes = postConvWidth * texelBytes;
- }
-
/* allocate memory */
+ if (texImage->IsCompressed)
+ sizeInBytes = texImage->CompressedSize;
+ else
+ sizeInBytes = postConvWidth * texelBytes;
texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
if (!texImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
return;
}
- if (pixels) {
- /* unpack image, apply transfer ops and store in texImage->Data */
+ if (!pixels)
+ return;
+
+ /* unpack image, apply transfer ops and store in texImage->Data */
+ if (texImage->IsCompressed) {
+ GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
+ width);
+ transfer_compressed_teximage(ctx, 1, width, 1, 1,
+ format, type, packing,
+ pixels, texImage->TexFormat,
+ (GLubyte *) texImage->Data, dstRowStride);
+ }
+ else {
_mesa_transfer_teximage(ctx, 1,
- _mesa_base_tex_format(ctx, internalFormat),
+ texImage->Format, /* base format */
texImage->TexFormat, texImage->Data,
- width, 1, 1, 0, 0, 0,
+ width, 1, 1, /* src size */
+ 0, 0, 0, /* dstX/Y/Zoffset */
0, /* dstRowStride */
0, /* dstImageStride */
format, type, pixels, packing);
+ }
- /* GL_SGIS_generate_mipmap */
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- _mesa_generate_mipmap(ctx,
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
- texObj);
- }
+ /* GL_SGIS_generate_mipmap */
+ if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+ _mesa_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ texObj);
}
}
/*
- * This is the software fallback for Driver.TexImage2D().
+ * This is the software fallback for Driver.TexImage2D()
+ * and Driver.CopyTexImage2D().
* The texture image type will be GLchan.
* The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
* GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
- *
- * NOTE: if real texture compression is supported, this whole function
- * will need to be overridden.
*/
void
_mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
texelBytes = texImage->TexFormat->TexelBytes;
- /* Compute image size, in bytes */
- if (texImage->IsCompressed) {
- assert(ctx->Driver.CompressedTextureSize);
- sizeInBytes = ctx->Driver.CompressedTextureSize(ctx, texImage);
- assert(sizeInBytes > 0);
- texImage->CompressedSize = sizeInBytes;
- }
- else {
- sizeInBytes = postConvWidth * postConvHeight * texelBytes;
- }
-
/* allocate memory */
+ if (texImage->IsCompressed)
+ sizeInBytes = texImage->CompressedSize;
+ else
+ sizeInBytes = postConvWidth * postConvHeight * texelBytes;
texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
if (!texImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
return;
}
- if (pixels) {
- /* unpack image, apply transfer ops and store in texImage->Data */
+ if (!pixels)
+ return;
+
+ /* unpack image, apply transfer ops and store in texImage->Data */
+ if (texImage->IsCompressed) {
+ GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
+ width);
+ transfer_compressed_teximage(ctx, 2, width, height, 1,
+ format, type, packing,
+ pixels, texImage->TexFormat,
+ (GLubyte *) texImage->Data, dstRowStride);
+ }
+ else {
_mesa_transfer_teximage(ctx, 2,
- _mesa_base_tex_format(ctx, internalFormat),
+ texImage->Format,
texImage->TexFormat, texImage->Data,
- width, height, 1, 0, 0, 0,
- texImage->Width * texelBytes,
+ width, height, 1, /* src size */
+ 0, 0, 0, /* dstX/Y/Zoffset */
+ texImage->Width * texelBytes, /* dstRowStride */
0, /* dstImageStride */
format, type, pixels, packing);
+ }
- /* GL_SGIS_generate_mipmap */
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- _mesa_generate_mipmap(ctx,
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
- texObj);
- }
+ /* GL_SGIS_generate_mipmap */
+ if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+ _mesa_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ texObj);
}
}
/*
- * This is the software fallback for Driver.TexImage3D().
+ * This is the software fallback for Driver.TexImage3D()
+ * and Driver.CopyTexImage3D().
* The texture image type will be GLchan.
* The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
* GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
- *
*/
void
_mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
texelBytes = texImage->TexFormat->TexelBytes;
- /* Compute image size, in bytes */
- if (texImage->IsCompressed) {
- assert(ctx->Driver.CompressedTextureSize);
- sizeInBytes = ctx->Driver.CompressedTextureSize(ctx, texImage);
- assert(sizeInBytes > 0);
- texImage->CompressedSize = sizeInBytes;
- }
- else {
- sizeInBytes = width * height * depth * texelBytes;
- }
-
/* allocate memory */
+ if (texImage->IsCompressed)
+ sizeInBytes = texImage->CompressedSize;
+ else
+ sizeInBytes = width * height * depth * texelBytes;
texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
if (!texImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
return;
}
- if (pixels) {
- /* unpack image, apply transfer ops and store in texImage->Data */
+ if (!pixels)
+ return;
+
+ /* unpack image, apply transfer ops and store in texImage->Data */
+ if (texImage->IsCompressed) {
+ GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
+ width);
+ transfer_compressed_teximage(ctx, 3, width, height, depth,
+ format, type, packing,
+ pixels, texImage->TexFormat,
+ (GLubyte *) texImage->Data, dstRowStride);
+ }
+ else {
_mesa_transfer_teximage(ctx, 3,
- _mesa_base_tex_format(ctx, internalFormat),
+ texImage->Format,
texImage->TexFormat, texImage->Data,
- width, height, depth, 0, 0, 0,
- texImage->Width * texelBytes,
+ width, height, depth, /* src size */
+ 0, 0, 0, /* dstX/Y/Zoffset */
+ texImage->Width * texelBytes, /* dstRowStride */
texImage->Width * texImage->Height * texelBytes,
format, type, pixels, packing);
+ }
- /* GL_SGIS_generate_mipmap */
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- _mesa_generate_mipmap(ctx,
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
- texObj);
- }
+ /* GL_SGIS_generate_mipmap */
+ if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+ _mesa_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ texObj);
}
}
/*
- * This is the software fallback for Driver.TexSubImage1D().
+ * This is the software fallback for Driver.TexSubImage1D()
+ * and Driver.CopyTexSubImage1D().
*/
void
_mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
- _mesa_transfer_teximage(ctx, 1,
- _mesa_base_tex_format(ctx, texImage->IntFormat),
- texImage->TexFormat, texImage->Data,
- width, 1, 1, /* src size */
- xoffset, 0, 0, /* dest offsets */
- 0, /* dstRowStride */
- 0, /* dstImageStride */
- format, type, pixels, packing);
+ if (texImage->IsCompressed) {
+ GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
+ texImage->Width);
+ GLubyte *dest = _mesa_compressed_image_address(xoffset, 0, 0,
+ texImage->IntFormat,
+ texImage->Width,
+ (GLubyte*) texImage->Data);
+ transfer_compressed_teximage(ctx, 1, /* dimensions */
+ width, 1, 1, /* size to replace */
+ format, type, /* source format/type */
+ packing, /* source packing */
+ pixels, /* source data */
+ texImage->TexFormat,/* dest format */
+ dest, dstRowStride);
+ }
+ else {
+ _mesa_transfer_teximage(ctx, 1,
+ texImage->Format,
+ texImage->TexFormat, texImage->Data,
+ width, 1, 1, /* src size */
+ xoffset, 0, 0, /* dest offsets */
+ 0, /* dstRowStride */
+ 0, /* dstImageStride */
+ format, type, pixels, packing);
+ }
/* GL_SGIS_generate_mipmap */
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- _mesa_generate_mipmap(ctx, &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ _mesa_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
+
/*
- * This is the software fallback for Driver.TexSubImage2D().
+ * This is the software fallback for Driver.TexSubImage2D()
+ * and Driver.CopyTexSubImage2D().
*/
void
_mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
- _mesa_transfer_teximage(ctx, 2,
- _mesa_base_tex_format(ctx, texImage->IntFormat),
- texImage->TexFormat, texImage->Data,
- width, height, 1, /* src size */
- xoffset, yoffset, 0, /* dest offsets */
- texImage->Width * texImage->TexFormat->TexelBytes,
- 0, /* dstImageStride */
- format, type, pixels, packing);
+ if (texImage->IsCompressed) {
+ GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
+ texImage->Width);
+ GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
+ texImage->IntFormat,
+ texImage->Width,
+ (GLubyte*) texImage->Data);
+ transfer_compressed_teximage(ctx, 2, /* dimensions */
+ width, height, 1, /* size to replace */
+ format, type, /* source format/type */
+ packing, /* source packing */
+ pixels, /* source data */
+ texImage->TexFormat,/* dest format */
+ dest, dstRowStride);
+ }
+ else {
+ _mesa_transfer_teximage(ctx, 2,
+ texImage->Format,
+ texImage->TexFormat, texImage->Data,
+ width, height, 1, /* src size */
+ xoffset, yoffset, 0, /* dest offsets */
+ texImage->Width *texImage->TexFormat->TexelBytes,
+ 0, /* dstImageStride */
+ format, type, pixels, packing);
+ }
/* GL_SGIS_generate_mipmap */
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- _mesa_generate_mipmap(ctx, &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ _mesa_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
/*
* This is the software fallback for Driver.TexSubImage3D().
+ * and Driver.CopyTexSubImage3D().
*/
void
_mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
- const GLint texelBytes = texImage->TexFormat->TexelBytes;
- _mesa_transfer_teximage(ctx, 3,
- _mesa_base_tex_format(ctx, texImage->IntFormat),
+ if (texImage->IsCompressed) {
+ GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
+ texImage->Width);
+ GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, zoffset,
+ texImage->IntFormat,
+ texImage->Width,
+ (GLubyte*) texImage->Data);
+ transfer_compressed_teximage(ctx, 3, /* dimensions */
+ width, height, depth,/* size to replace */
+ format, type, /* source format/type */
+ packing, /* source packing */
+ pixels, /* source data */
+ texImage->TexFormat,/* dest format */
+ dest, dstRowStride);
+ }
+ else {
+ const GLint texelBytes = texImage->TexFormat->TexelBytes;
+ _mesa_transfer_teximage(ctx, 3,
+ texImage->Format,
texImage->TexFormat, texImage->Data,
width, height, depth, /* src size */
- xoffset, yoffset, xoffset, /* dest offsets */
- texImage->Width * texelBytes,
+ xoffset, yoffset, zoffset, /* dest offsets */
+ texImage->Width * texelBytes, /* dst row stride */
texImage->Width * texImage->Height * texelBytes,
format, type, pixels, packing);
+ }
+
/* GL_SGIS_generate_mipmap */
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- _mesa_generate_mipmap(ctx, &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ _mesa_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
- /* Nothing here.
- * The device driver has to do it all.
- */
+ /* this space intentionally left blank */
}
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
- /* Nothing here.
- * The device driver has to do it all.
+ /* This is pretty simple, basically just do a memcpy without worrying
+ * about the usual image unpacking or image transfer operations.
*/
+ ASSERT(texObj);
+ ASSERT(texImage);
+ ASSERT(texImage->Width > 0);
+ ASSERT(texImage->Height > 0);
+ ASSERT(texImage->Depth == 1);
+ ASSERT(texImage->Data == NULL); /* was freed in glCompressedTexImage2DARB */
+
+ /* choose the texture format */
+ assert(ctx->Driver.ChooseTextureFormat);
+ texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
+ internalFormat, 0, 0);
+ assert(texImage->TexFormat);
+ texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
+
+ /* allocate storage */
+ texImage->Data = MESA_PBUFFER_ALLOC(imageSize);
+ if (!texImage->Data) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2DARB");
+ return;
+ }
+
+ /* copy the data */
+ ASSERT(texImage->CompressedSize == (GLuint) imageSize);
+ MEMCPY(texImage->Data, data, imageSize);
}
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
- /* Nothing here.
- * The device driver has to do it all.
- */
+ /* this space intentionally left blank */
}
-/*
- * Fallback for Driver.GetCompressedTexImage3D()
- * This will probably work find for hardware drivers. That is, hardware
- * drivers won't have to override this function, unless the compressed
- * texture must first be fetched from the TRAM.
+/**
+ * Fallback for Driver.CompressedTexSubImage1D()
*/
void
-_mesa_get_compressed_teximage(GLcontext *ctx, GLenum target,
- GLint level, void *image,
- const struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
+_mesa_store_compressed_texsubimage1d(GLcontext *ctx, GLenum target,
+ GLint level,
+ GLint xoffset, GLsizei width,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
{
- assert(texImage->IsCompressed);
- assert(texImage->CompressedSize > 0);
- MEMCPY(image, texImage->Data, texImage->CompressedSize);
+ /* this space intentionally left blank */
}
-
-/*
- * This is the fallback for Driver.TestProxyTexImage().
+/**
+ * Fallback for Driver.CompressedTexSubImage2D()
*/
-GLboolean
-_mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
- GLint internalFormat, GLenum format, GLenum type,
- GLint width, GLint height, GLint depth, GLint border)
+void
+_mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target,
+ GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
{
- struct gl_texture_unit *texUnit;
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
-
- (void) format;
- (void) type;
+ GLint bytesPerRow, destRowStride, srcRowStride;
+ GLint i, rows;
+ GLubyte *dest;
+ const GLubyte *src;
- texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- texObj = _mesa_select_tex_object(ctx, texUnit, target);
- texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
+ /* these should have been caught sooner */
+ ASSERT((width & 3) == 0 || width == 2 || width == 1);
+ ASSERT((height & 3) == 0 || height == 2 || height == 1);
+ ASSERT((xoffset & 3) == 0);
+ ASSERT((yoffset & 3) == 0);
+
+ srcRowStride = _mesa_compressed_row_stride(texImage->IntFormat, width);
+ src = (const GLubyte *) data;
+
+ destRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
+ texImage->Width);
+ dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
+ texImage->IntFormat,
+ texImage->Width,
+ (GLubyte*) texImage->Data);
+
+ bytesPerRow = srcRowStride;
+ rows = height / 4;
+
+ for (i = 0; i < rows; i++) {
+ MEMCPY(dest, src, bytesPerRow);
+ dest += destRowStride;
+ src += srcRowStride;
+ }
+}
- /* We always pass.
- * The core Mesa code will have already tested the image size, etc.
- * If a driver has more stringent texture limits to enforce it will
- * have to override this function.
- */
- /* choose the texture format */
- assert(ctx->Driver.ChooseTextureFormat);
- texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
- internalFormat, format, type);
- assert(texImage->TexFormat);
- return GL_TRUE;
+/**
+ * Fallback for Driver.CompressedTexSubImage3D()
+ */
+void
+_mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target,
+ GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ /* this space intentionally left blank */
}
-
/*
* Average together two rows of a source image to produce a single new
* row in the dest image. It's legal for the two source rows to point
const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
+ /* This assertion is no longer valid with non-power-of-2 textures
assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
+ */
switch (format->MesaFormat) {
case MESA_FORMAT_RGBA:
*/
/*
- printf("mip3d %d x %d x %d -> %d x %d x %d\n",
+ _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
*/
* Stop at texObj's MaxLevel or when we get to the 1x1 texture.
*/
void
-_mesa_generate_mipmap(GLcontext *ctx,
+_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
const struct gl_texture_unit *texUnit,
struct gl_texture_object *texObj)
{
- const GLenum targets1D[] = { GL_TEXTURE_1D, 0 };
- const GLenum targets2D[] = { GL_TEXTURE_2D, 0 };
- const GLenum targets3D[] = { GL_TEXTURE_3D, 0 };
- const GLenum targetsCube[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
- 0 };
- const GLenum *targets;
- GLint level;
- GLint maxLevels = 0;
+ const struct gl_texture_image *srcImage;
+ const struct gl_texture_format *convertFormat;
+ const GLubyte *srcData = NULL;
+ GLubyte *dstData = NULL;
+ GLint level, maxLevels;
ASSERT(texObj);
- ASSERT(texObj->Image[texObj->BaseLevel]);
-
- switch (texObj->Dimensions) {
- case 1:
- targets = targets1D;
- maxLevels = ctx->Const.MaxTextureLevels;
- break;
- case 2:
- targets = targets2D;
- maxLevels = ctx->Const.MaxTextureLevels;
- break;
- case 3:
- targets = targets3D;
- maxLevels = ctx->Const.Max3DTextureLevels;
- break;
- case 6:
- targets = targetsCube;
- maxLevels = ctx->Const.MaxCubeTextureLevels;
- break;
- default:
- _mesa_problem(ctx,
- "Bad texture object dimension in _mesa_generate_mipmaps");
- return;
+ srcImage = texObj->Image[texObj->BaseLevel];
+ ASSERT(srcImage);
+
+ maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
+ ASSERT(maxLevels > 0); /* bad target */
+
+ /* Find convertFormat - the format that do_row() will process */
+ if (srcImage->IsCompressed) {
+ /* setup for compressed textures */
+ GLuint row;
+ GLint components, size;
+ GLchan *dst;
+
+ assert(texObj->Target == GL_TEXTURE_2D);
+
+ if (srcImage->Format == GL_RGB) {
+ convertFormat = &_mesa_texformat_rgb;
+ components = 3;
+ }
+ else if (srcImage->Format == GL_RGBA) {
+ convertFormat = &_mesa_texformat_rgba;
+ components = 4;
+ }
+ else {
+ _mesa_problem(ctx, "bad srcImage->Format in _mesa_generate_mipmaps");
+ return;
+ }
+
+ /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
+ size = _mesa_bytes_per_pixel(srcImage->Format, CHAN_TYPE)
+ * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
+ /* 20 extra bytes, just be safe when calling last FetchTexel */
+ srcData = (GLubyte *) MALLOC(size);
+ if (!srcData) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
+ return;
+ }
+ dstData = (GLubyte *) MALLOC(size / 2); /* 1/4 would probably be OK */
+ if (!dstData) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
+ FREE((void *) srcData);
+ return;
+ }
+
+ /* decompress base image here */
+ dst = (GLchan *) srcData;
+ for (row = 0; row < srcImage->Height; row++) {
+ GLuint col;
+ for (col = 0; col < srcImage->Width; col++) {
+ (*srcImage->FetchTexel)(srcImage, col, row, 0, (GLvoid *) dst);
+ dst += components;
+ }
+ }
+ }
+ else {
+ /* uncompressed */
+ convertFormat = srcImage->TexFormat;
}
for (level = texObj->BaseLevel; level < texObj->MaxLevel
GLint srcWidth, srcHeight, srcDepth;
GLint dstWidth, dstHeight, dstDepth;
GLint border, bytesPerTexel;
- GLint t;
- srcImage = texObj->Image[level];
+ /* get src image parameters */
+ srcImage = _mesa_select_tex_image(ctx, texUnit, target, level);
ASSERT(srcImage);
srcWidth = srcImage->Width;
srcHeight = srcImage->Height;
srcDepth = srcImage->Depth;
border = srcImage->Border;
- bytesPerTexel = srcImage->TexFormat->TexelBytes;
/* compute next (level+1) image size */
if (srcWidth - 2 * border > 1) {
dstHeight == srcHeight &&
dstDepth == srcDepth) {
/* all done */
+ if (srcImage->IsCompressed) {
+ FREE((void *) srcData);
+ FREE(dstData);
+ }
return;
}
- /* Need this loop just because of cubemaps */
- for (t = 0; targets[t]; t++) {
- ASSERT(t < 6);
+ /* get dest gl_texture_image */
+ dstImage = _mesa_get_tex_image(ctx, texUnit, target, level + 1);
+ if (!dstImage) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+ return;
+ }
- dstImage = _mesa_select_tex_image(ctx, texUnit, targets[t], level+1);
- if (!dstImage) {
- dstImage = _mesa_alloc_texture_image();
- if (!dstImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
- return;
- }
- _mesa_set_tex_image(texObj, targets[t], level + 1, dstImage);
+ /* Free old image data */
+ if (dstImage->Data)
+ MESA_PBUFFER_FREE(dstImage->Data);
+
+ /* initialize new image */
+ _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
+ dstDepth, border, srcImage->IntFormat);
+ dstImage->DriverData = NULL;
+ dstImage->TexFormat = srcImage->TexFormat;
+ dstImage->FetchTexel = srcImage->FetchTexel;
+ ASSERT(dstImage->TexFormat);
+ ASSERT(dstImage->FetchTexel);
+
+ /* Alloc new teximage data buffer.
+ * Setup src and dest data pointers.
+ */
+ if (dstImage->IsCompressed) {
+ ASSERT(dstImage->CompressedSize > 0); /* set by init_teximage_fields*/
+ dstImage->Data = MESA_PBUFFER_ALLOC(dstImage->CompressedSize);
+ if (!dstImage->Data) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+ return;
}
-
- /* Free old image data */
- if (dstImage->Data)
- MESA_PBUFFER_FREE(dstImage->Data);
-
- /* initialize new image */
- _mesa_init_teximage_fields(ctx, dstImage, dstWidth, dstHeight,
- dstDepth, border, srcImage->Format);
- dstImage->DriverData = NULL;
- dstImage->TexFormat = srcImage->TexFormat;
- dstImage->FetchTexel = srcImage->FetchTexel;
- ASSERT(dstImage->TexFormat);
- ASSERT(dstImage->FetchTexel);
-
+ /* srcData and dstData are already set */
+ ASSERT(srcData);
+ ASSERT(dstData);
+ }
+ else {
+ bytesPerTexel = srcImage->TexFormat->TexelBytes;
ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
-
- /* alloc new image buffer */
dstImage->Data = MESA_PBUFFER_ALLOC(dstWidth * dstHeight * dstDepth
- * bytesPerTexel);
+ * bytesPerTexel);
if (!dstImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
return;
}
+ srcData = (const GLubyte *) srcImage->Data;
+ dstData = (GLubyte *) dstImage->Data;
+ }
- /*
- * We use simple 2x2 averaging to compute the next mipmap level.
- */
- switch (texObj->Dimensions) {
- case 1:
- make_1d_mipmap(srcImage->TexFormat, border,
- srcWidth, (const GLubyte *) srcImage->Data,
- dstWidth, (GLubyte *) dstImage->Data);
+ /*
+ * We use simple 2x2 averaging to compute the next mipmap level.
+ */
+ switch (target) {
+ case GL_TEXTURE_1D:
+ make_1d_mipmap(convertFormat, border,
+ srcWidth, srcData,
+ dstWidth, dstData);
break;
- case 2:
- case 6:
- make_2d_mipmap(srcImage->TexFormat, border,
- srcWidth, srcHeight, (const GLubyte *) srcImage->Data,
- dstWidth, dstHeight, (GLubyte *) dstImage->Data);
+ 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:
+ make_2d_mipmap(convertFormat, border,
+ srcWidth, srcHeight, srcData,
+ dstWidth, dstHeight, dstData);
break;
- case 3:
- make_3d_mipmap(srcImage->TexFormat, border,
- srcWidth, srcHeight, srcDepth, (const GLubyte *) srcImage->Data,
- dstWidth, dstHeight, dstDepth, (GLubyte *) dstImage->Data);
+ case GL_TEXTURE_3D:
+ make_3d_mipmap(convertFormat, border,
+ srcWidth, srcHeight, srcDepth, srcData,
+ dstWidth, dstHeight, dstDepth, dstData);
+ break;
+ case GL_TEXTURE_RECTANGLE_NV:
+ /* no mipmaps, do nothing */
break;
default:
_mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
return;
- }
- } /* loop over tex image targets */
- } /* loop over tex levels */
+ }
+
+ if (dstImage->IsCompressed) {
+ GLubyte *temp;
+ /* compress image from dstData into dstImage->Data */
+ const GLenum srcFormat = convertFormat->BaseFormat;
+ GLint dstRowStride = _mesa_compressed_row_stride(srcImage->IntFormat,
+ dstWidth);
+ ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
+ _mesa_compress_teximage(ctx,
+ dstWidth, dstHeight, /* size */
+ srcFormat, /* source format */
+ (const GLchan *) dstData, /* source buffer */
+ dstWidth, /* source row stride */
+ dstImage->TexFormat, /* dest format */
+ (GLubyte*) dstImage->Data, /* dest buffer */
+ dstRowStride ); /* dest row stride */
+
+ /* swap src and dest pointers */
+ temp = (GLubyte *) srcData;
+ srcData = dstData;
+ dstData = temp;
+ }
+
+ } /* loop over mipmap levels */
}