#include "glheader.h"
#include "colormac.h"
#include "context.h"
#include "convolve.h"
#include "image.h"
#include "macros.h"
#include "imports.h"
#include "texcompress.h"
#include "texformat.h"
#include "teximage.h"
#include "texstore.h"
#include "texutil.h"
static GLint
components_in_intformat( GLint format )
{
switch (format) {
case GL_ALPHA:
case GL_ALPHA4:
case GL_ALPHA8:
case GL_ALPHA12:
case GL_ALPHA16:
return 1;
case 1:
case GL_LUMINANCE:
case GL_LUMINANCE4:
case GL_LUMINANCE8:
case GL_LUMINANCE12:
case GL_LUMINANCE16:
return 1;
case 2:
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE4_ALPHA4:
case GL_LUMINANCE6_ALPHA2:
case GL_LUMINANCE8_ALPHA8:
case GL_LUMINANCE12_ALPHA4:
case GL_LUMINANCE12_ALPHA12:
case GL_LUMINANCE16_ALPHA16:
return 2;
case GL_INTENSITY:
case GL_INTENSITY4:
case GL_INTENSITY8:
case GL_INTENSITY12:
case GL_INTENSITY16:
return 1;
case 3:
case GL_RGB:
case GL_R3_G3_B2:
case GL_RGB4:
case GL_RGB5:
case GL_RGB8:
case GL_RGB10:
case GL_RGB12:
case GL_RGB16:
return 3;
case 4:
case GL_RGBA:
case GL_RGBA2:
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGBA8:
case GL_RGB10_A2:
case GL_RGBA12:
case GL_RGBA16:
return 4;
case GL_COLOR_INDEX:
case GL_COLOR_INDEX1_EXT:
case GL_COLOR_INDEX2_EXT:
case GL_COLOR_INDEX4_EXT:
case GL_COLOR_INDEX8_EXT:
case GL_COLOR_INDEX12_EXT:
case GL_COLOR_INDEX16_EXT:
return 1;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16_SGIX:
case GL_DEPTH_COMPONENT24_SGIX:
case GL_DEPTH_COMPONENT32_SGIX:
return 1;
case GL_YCBCR_MESA:
return 2;
default:
return -1;
}
}
static void
transfer_teximage(GLcontext *ctx, GLuint dimensions,
GLenum texDestFormat, GLvoid *texDestAddr,
GLint srcWidth, GLint srcHeight, GLint srcDepth,
GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
GLint dstRowStride, GLint dstImageStride,
GLenum srcFormat, GLenum srcType,
const GLvoid *srcAddr,
const struct gl_pixelstore_attrib *srcPacking,
GLuint transferOps)
{
GLint texComponents;
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(dstXoffset >= 0);
ASSERT(dstYoffset >= 0);
ASSERT(dstZoffset >= 0);
ASSERT(dstRowStride >= 0);
ASSERT(dstImageStride >= 0);
ASSERT(srcAddr);
ASSERT(srcPacking);
texComponents = components_in_intformat(texDestFormat);
if (!transferOps && dimensions == 2 && srcType == CHAN_TYPE) {
if (srcFormat == texDestFormat) {
const GLchan *src = (const GLchan *) _mesa_image_address(
srcPacking, srcAddr, srcWidth, srcHeight,
srcFormat, srcType, 0, 0, 0);
const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
srcWidth, srcFormat, srcType);
const GLint widthInBytes = srcWidth * texComponents * sizeof(GLchan);
GLchan *dst = (GLchan *) texDestAddr
+ dstYoffset * (dstRowStride / sizeof(GLchan))
+ dstXoffset * texComponents;
if (srcRowStride == widthInBytes && dstRowStride == widthInBytes) {
MEMCPY(dst, src, srcHeight * widthInBytes);
}
else {
GLint i;
for (i = 0; i < srcHeight; i++) {
MEMCPY(dst, src, widthInBytes);
src += (srcRowStride / sizeof(GLchan));
dst += (dstRowStride / sizeof(GLchan));
}
}
return;
}
else if (srcFormat == GL_RGBA && texDestFormat == GL_RGB) {
const GLchan *src = (const GLchan *) _mesa_image_address(
srcPacking, srcAddr, srcWidth, srcHeight,
srcFormat, srcType, 0, 0, 0);
const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
srcWidth, srcFormat, srcType);
GLchan *dst = (GLchan *) texDestAddr
+ dstYoffset * (dstRowStride / sizeof(GLchan))
+ dstXoffset * texComponents;
GLint i, j;
for (i = 0; i < srcHeight; i++) {
const GLchan *s = src;
GLchan *d = dst;
for (j = 0; j < srcWidth; j++) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
s++;
}
src += (srcRowStride / sizeof(GLchan));
dst += (dstRowStride / sizeof(GLchan));
}
return;
}
}
if (texDestFormat == GL_COLOR_INDEX) {
const GLenum texType = CHAN_TYPE;
GLint img, row;
GLchan *dest = (GLchan *) texDestAddr
+ dstZoffset * (dstImageStride / sizeof(GLchan))
+ dstYoffset * (dstRowStride / sizeof(GLchan))
+ dstXoffset * texComponents;
for (img = 0; img < srcDepth; img++) {
GLchan *destRow = dest;
for (row = 0; row < srcHeight; row++) {
const GLvoid *src = _mesa_image_address(srcPacking,
srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
_mesa_unpack_index_span(ctx, srcWidth, texType, destRow,
srcType, src, srcPacking, transferOps);
destRow += (dstRowStride / sizeof(GLchan));
}
dest += dstImageStride;
}
}
else if (texDestFormat == GL_YCBCR_MESA) {
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) {
GLint img, row;
GLubyte *dest = (GLubyte *) texDestAddr
+ dstZoffset * dstImageStride
+ dstYoffset * (dstRowStride / sizeof(GLchan))
+ dstXoffset * texComponents;
for (img = 0; img < srcDepth; img++) {
GLubyte *destRow = dest;
for (row = 0; row < srcHeight; row++) {
const GLvoid *src = _mesa_image_address(srcPacking,
srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
_mesa_unpack_depth_span(ctx, srcWidth, (GLfloat *) destRow,
srcType, src, srcPacking);
destRow += (dstRowStride / sizeof(GLchan));
}
dest += dstImageStride;
}
}
else {
if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) ||
(dimensions >= 2 && ctx->Pixel.Convolution2DEnabled) ||
(dimensions >= 2 && ctx->Pixel.Separable2DEnabled)) {
GLint img, row;
GLint convWidth = srcWidth, convHeight = srcHeight;
GLfloat *tmpImage, *convImage;
tmpImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
if (!tmpImage) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
return;
}
convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
if (!convImage) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
FREE(tmpImage);
return;
}
for (img = 0; img < srcDepth; img++) {
const GLfloat *srcf;
GLfloat *dstf = tmpImage;
GLchan *dest;
for (row = 0; row < srcHeight; row++) {
const GLvoid *src = _mesa_image_address(srcPacking,
srcAddr, srcWidth, srcHeight,
srcFormat, srcType, img, row, 0);
_mesa_unpack_float_color_span(ctx, srcWidth, GL_RGBA, dstf,
srcFormat, srcType, src, srcPacking,
transferOps & IMAGE_PRE_CONVOLUTION_BITS,
GL_TRUE);
dstf += srcWidth * 4;
}
if (dimensions == 1) {
ASSERT(ctx->Pixel.Convolution1DEnabled);
_mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage);
}
else {
if (ctx->Pixel.Convolution2DEnabled) {
_mesa_convolve_2d_image(ctx, &convWidth, &convHeight,
tmpImage, convImage);
}
else {
ASSERT(ctx->Pixel.Separable2DEnabled);
_mesa_convolve_sep_image(ctx, &convWidth, &convHeight,
tmpImage, convImage);
}
}
srcf = convImage;
dest = (GLchan *) texDestAddr
+ (dstZoffset + img) * (dstImageStride / sizeof(GLchan))
+ dstYoffset * (dstRowStride / sizeof(GLchan));
for (row = 0; row < convHeight; row++) {
_mesa_pack_float_rgba_span(ctx, convWidth,
(const GLfloat (*)[4]) srcf,
texDestFormat, CHAN_TYPE,
dest, &_mesa_native_packing,
transferOps
& IMAGE_POST_CONVOLUTION_BITS);
srcf += convWidth * 4;
dest += (dstRowStride / sizeof(GLchan));
}
}
FREE(convImage);
FREE(tmpImage);
}
else {
GLint img, row;
GLchan *dest = (GLchan *) texDestAddr
+ dstZoffset * (dstImageStride / sizeof(GLchan))
+ dstYoffset * (dstRowStride / sizeof(GLchan))
+ dstXoffset * texComponents;
for (img = 0; img < srcDepth; img++) {
GLchan *destRow = dest;
for (row = 0; row < srcHeight; row++) {
const GLvoid *srcRow = _mesa_image_address(srcPacking,
srcAddr, srcWidth, srcHeight,
srcFormat, srcType, img, row, 0);
_mesa_unpack_chan_color_span(ctx, srcWidth, texDestFormat,
destRow, srcFormat, srcType, srcRow,
srcPacking, transferOps);
destRow += (dstRowStride / sizeof(GLchan));
}
dest += dstImageStride / sizeof(GLchan);
}
}
}
}
void
_mesa_transfer_teximage(GLcontext *ctx, GLuint dimensions,
GLenum baseInternalFormat,
const struct gl_texture_format *dstFormat,
GLvoid *dstAddr,
GLint srcWidth, GLint srcHeight, GLint srcDepth,
GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
GLint dstRowStride, GLint dstImageStride,
GLenum srcFormat, GLenum srcType,
const GLvoid *srcAddr,
const struct gl_pixelstore_attrib *srcPacking)
{
const GLint dstRowStridePixels = dstRowStride / dstFormat->TexelBytes;
const GLint dstImageStridePixels = dstImageStride / dstFormat->TexelBytes;
GLboolean makeTemp;
GLuint transferOps = ctx->_ImageTransferState;
GLboolean freeSourceData = GL_FALSE;
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_COLOR_INDEX ||
baseInternalFormat == GL_DEPTH_COMPONENT);
if (transferOps & IMAGE_CONVOLUTION_BIT) {
_mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
&postConvHeight);
}
if (dstFormat->BaseFormat != baseInternalFormat) {
const GLint texelSize = _mesa_components_in_format(baseInternalFormat)
* sizeof(GLchan);
const GLint bytes = texelSize * postConvWidth * postConvHeight *srcDepth;
const GLint tmpRowStride = texelSize * postConvWidth;
const GLint tmpImgStride = texelSize * postConvWidth * postConvHeight;
GLvoid *tmpImage = MALLOC(bytes);
if (!tmpImage)
return;
transfer_teximage(ctx, dimensions, baseInternalFormat, tmpImage,
srcWidth, srcHeight, srcDepth,
0, 0, 0,
tmpRowStride, tmpImgStride,
srcFormat, srcType, srcAddr, srcPacking, transferOps);
srcWidth = postConvWidth;
srcHeight = postConvHeight;
srcFormat = baseInternalFormat;
srcType = CHAN_TYPE;
srcAddr = tmpImage;
srcPacking = &_mesa_native_packing;
freeSourceData = GL_TRUE;
transferOps = 0;
}
if (_mesa_is_hardware_tex_format(dstFormat)) {
if (transferOps) {
makeTemp = GL_TRUE;
}
else {
if (dimensions == 1) {
makeTemp = !_mesa_convert_texsubimage1d(dstFormat->MesaFormat,
dstXoffset,
srcWidth,
srcFormat, srcType,
srcPacking, srcAddr,
dstAddr);
}
else if (dimensions == 2) {
makeTemp = !_mesa_convert_texsubimage2d(dstFormat->MesaFormat,
dstXoffset, dstYoffset,
srcWidth, srcHeight,
dstRowStridePixels,
srcFormat, srcType,
srcPacking, srcAddr,
dstAddr);
}
else {
assert(dimensions == 3);
makeTemp = !_mesa_convert_texsubimage3d(dstFormat->MesaFormat,
dstXoffset, dstYoffset, dstZoffset,
srcWidth, srcHeight, srcDepth,
dstRowStridePixels, dstImageStridePixels,
srcFormat, srcType,
srcPacking, srcAddr, dstAddr);
}
if (!makeTemp) {
if (freeSourceData)
FREE((void *) srcAddr);
return;
}
}
}
else {
makeTemp = GL_FALSE;
}
if (makeTemp) {
GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
GLenum tmpFormat;
GLuint tmpComps, tmpTexelSize;
GLint tmpRowStride, tmpImageStride;
GLubyte *tmpImage;
if (transferOps & IMAGE_CONVOLUTION_BIT) {
_mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
&postConvHeight);
}
tmpFormat = dstFormat->BaseFormat;
tmpComps = _mesa_components_in_format(tmpFormat);
tmpTexelSize = tmpComps * sizeof(GLchan);
tmpRowStride = postConvWidth * tmpTexelSize;
tmpImageStride = postConvWidth * postConvHeight * tmpTexelSize;
tmpImage = (GLubyte *) MALLOC(postConvWidth * postConvHeight *
srcDepth * tmpTexelSize);
if (!tmpImage) {
if (freeSourceData)
FREE((void *) srcAddr);
return;
}
transfer_teximage(ctx, dimensions, tmpFormat, tmpImage,
srcWidth, srcHeight, srcDepth,
0, 0, 0,
tmpRowStride, tmpImageStride,
srcFormat, srcType, srcAddr, srcPacking, transferOps);
if (freeSourceData)
FREE((void *) srcAddr);
srcWidth = postConvWidth;
srcHeight = postConvHeight;
srcFormat = tmpFormat;
srcType = CHAN_TYPE;
srcAddr = tmpImage;
srcPacking = &_mesa_native_packing;
freeSourceData = GL_TRUE;
}
if (_mesa_is_hardware_tex_format(dstFormat)) {
assert(makeTemp);
if (dimensions == 1) {
GLboolean b;
b = _mesa_convert_texsubimage1d(dstFormat->MesaFormat,
dstXoffset,
srcWidth,
srcFormat, srcType,
srcPacking, srcAddr,
dstAddr);
(void)b;
assert(b);
}
else if (dimensions == 2) {
GLboolean b;
b = _mesa_convert_texsubimage2d(dstFormat->MesaFormat,
dstXoffset, dstYoffset,
srcWidth, srcHeight,
dstRowStridePixels,
srcFormat, srcType,
srcPacking, srcAddr,
dstAddr);
(void)b;
assert(b);
}
else {
GLboolean b;
b = _mesa_convert_texsubimage3d(dstFormat->MesaFormat,
dstXoffset, dstYoffset, dstZoffset,
srcWidth, srcHeight, srcDepth,
dstRowStridePixels, dstImageStridePixels,
srcFormat, srcType,
srcPacking, srcAddr, dstAddr);
(void)b;
assert(b);
}
}
else {
assert(!makeTemp);
transfer_teximage(ctx, dimensions, dstFormat->BaseFormat, dstAddr,
srcWidth, srcHeight, srcDepth,
dstXoffset, dstYoffset, dstZoffset,
dstRowStride, dstImageStride,
srcFormat, srcType, srcAddr, srcPacking, transferOps);
}
if (freeSourceData)
FREE((void *) srcAddr);
}
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);
ASSERT(dstFormat->TexelBytes == 0);
baseFormat = dstFormat->BaseFormat;
if (srcFormat != baseFormat || srcType != CHAN_TYPE ||
ctx->_ImageTransferState != 0 || unpacking->SwapBytes) {
GLint comps = components_in_intformat(baseFormat);
GLint postConvWidth = width, postConvHeight = height;
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,
tempImage,
width, height, depth,
0, 0, 0,
comps * width,
comps * width * height,
srcFormat, srcType,
source, unpacking,
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);
}
}
void
_mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
GLint internalFormat,
GLint width, GLint border,
GLenum format, GLenum type, const GLvoid *pixels,
const struct gl_pixelstore_attrib *packing,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
GLint postConvWidth = width;
GLint texelBytes, sizeInBytes;
if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
_mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
}
assert(ctx->Driver.ChooseTextureFormat);
texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
internalFormat, format, type);
assert(texImage->TexFormat);
texImage->FetchTexel = texImage->TexFormat->FetchTexel1D;
texelBytes = texImage->TexFormat->TexelBytes;
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)
return;
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,
texImage->Format,
texImage->TexFormat, texImage->Data,
width, 1, 1,
0, 0, 0,
0,
0,
format, type, pixels, packing);
}
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
_mesa_generate_mipmap(ctx, target,
&ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
void
_mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
GLint internalFormat,
GLint width, GLint height, GLint border,
GLenum format, GLenum type, const void *pixels,
const struct gl_pixelstore_attrib *packing,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
GLint postConvWidth = width, postConvHeight = height;
GLint texelBytes, sizeInBytes;
if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
_mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
&postConvHeight);
}
assert(ctx->Driver.ChooseTextureFormat);
texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
internalFormat, format, type);
assert(texImage->TexFormat);
texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
texelBytes = texImage->TexFormat->TexelBytes;
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)
return;
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,
texImage->Format,
texImage->TexFormat, texImage->Data,
width, height, 1,
0, 0, 0,
texImage->Width * texelBytes,
0,
format, type, pixels, packing);
}
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
_mesa_generate_mipmap(ctx, target,
&ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
void
_mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
GLint internalFormat,
GLint width, GLint height, GLint depth, GLint border,
GLenum format, GLenum type, const void *pixels,
const struct gl_pixelstore_attrib *packing,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
GLint texelBytes, sizeInBytes;
assert(ctx->Driver.ChooseTextureFormat);
texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
internalFormat, format, type);
assert(texImage->TexFormat);
texImage->FetchTexel = texImage->TexFormat->FetchTexel3D;
texelBytes = texImage->TexFormat->TexelBytes;
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)
return;
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,
texImage->Format,
texImage->TexFormat, texImage->Data,
width, height, depth,
0, 0, 0,
texImage->Width * texelBytes,
texImage->Width * texImage->Height * texelBytes,
format, type, pixels, packing);
}
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
_mesa_generate_mipmap(ctx, target,
&ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
void
_mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
GLint xoffset, GLint width,
GLenum format, GLenum type, const void *pixels,
const struct gl_pixelstore_attrib *packing,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
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,
width, 1, 1,
format, type,
packing,
pixels,
texImage->TexFormat,
dest, dstRowStride);
}
else {
_mesa_transfer_teximage(ctx, 1,
texImage->Format,
texImage->TexFormat, texImage->Data,
width, 1, 1,
xoffset, 0, 0,
0,
0,
format, type, pixels, packing);
}
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
_mesa_generate_mipmap(ctx, target,
&ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
void
_mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
GLint xoffset, GLint yoffset,
GLint width, GLint height,
GLenum format, GLenum type, const void *pixels,
const struct gl_pixelstore_attrib *packing,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
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,
width, height, 1,
format, type,
packing,
pixels,
texImage->TexFormat,
dest, dstRowStride);
}
else {
_mesa_transfer_teximage(ctx, 2,
texImage->Format,
texImage->TexFormat, texImage->Data,
width, height, 1,
xoffset, yoffset, 0,
texImage->Width *texImage->TexFormat->TexelBytes,
0,
format, type, pixels, packing);
}
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
_mesa_generate_mipmap(ctx, target,
&ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
void
_mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLint width, GLint height, GLint depth,
GLenum format, GLenum type, const void *pixels,
const struct gl_pixelstore_attrib *packing,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
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,
width, height, depth,
format, type,
packing,
pixels,
texImage->TexFormat,
dest, dstRowStride);
}
else {
const GLint texelBytes = texImage->TexFormat->TexelBytes;
_mesa_transfer_teximage(ctx, 3,
texImage->Format,
texImage->TexFormat, texImage->Data,
width, height, depth,
xoffset, yoffset, zoffset,
texImage->Width * texelBytes,
texImage->Width * texImage->Height * texelBytes,
format, type, pixels, packing);
}
if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
_mesa_generate_mipmap(ctx, target,
&ctx->Texture.Unit[ctx->Texture.CurrentUnit],
texObj);
}
}
void
_mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level,
GLint internalFormat,
GLint width, GLint border,
GLsizei imageSize, const GLvoid *data,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
}
void
_mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level,
GLint internalFormat,
GLint width, GLint height, GLint border,
GLsizei imageSize, const GLvoid *data,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
ASSERT(texObj);
ASSERT(texImage);
ASSERT(texImage->Width > 0);
ASSERT(texImage->Height > 0);
ASSERT(texImage->Depth == 1);
ASSERT(texImage->Data == NULL);
assert(ctx->Driver.ChooseTextureFormat);
texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
internalFormat, 0, 0);
assert(texImage->TexFormat);
texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
texImage->Data = MESA_PBUFFER_ALLOC(imageSize);
if (!texImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2DARB");
return;
}
ASSERT(texImage->CompressedSize == imageSize);
MEMCPY(texImage->Data, data, imageSize);
}
void
_mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
GLint internalFormat,
GLint width, GLint height, GLint depth,
GLint border,
GLsizei imageSize, const GLvoid *data,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
}
void
_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)
{
}
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)
{
GLint bytesPerRow, destRowStride, srcRowStride;
GLint i, rows;
GLubyte *dest;
const GLubyte *src;
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;
}
}
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)
{
}
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)
{
struct gl_texture_unit *texUnit;
struct gl_texture_image *texImage;
(void) format;
(void) type;
texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
assert(ctx->Driver.ChooseTextureFormat);
texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
internalFormat, format, type);
assert(texImage->TexFormat);
return GL_TRUE;
}
static void
do_row(const struct gl_texture_format *format, GLint srcWidth,
const GLvoid *srcRowA, const GLvoid *srcRowB,
GLint dstWidth, GLvoid *dstRow)
{
const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
switch (format->MesaFormat) {
case MESA_FORMAT_RGBA:
{
GLuint i, j, k;
const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i][0] = (rowA[j][0] + rowA[k][0] +
rowB[j][0] + rowB[k][0]) / 4;
dst[i][1] = (rowA[j][1] + rowA[k][1] +
rowB[j][1] + rowB[k][1]) / 4;
dst[i][2] = (rowA[j][2] + rowA[k][2] +
rowB[j][2] + rowB[k][2]) / 4;
dst[i][3] = (rowA[j][3] + rowA[k][3] +
rowB[j][3] + rowB[k][3]) / 4;
}
}
return;
case MESA_FORMAT_RGB:
{
GLuint i, j, k;
const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i][0] = (rowA[j][0] + rowA[k][0] +
rowB[j][0] + rowB[k][0]) / 4;
dst[i][1] = (rowA[j][1] + rowA[k][1] +
rowB[j][1] + rowB[k][1]) / 4;
dst[i][2] = (rowA[j][2] + rowA[k][2] +
rowB[j][2] + rowB[k][2]) / 4;
}
}
return;
case MESA_FORMAT_ALPHA:
case MESA_FORMAT_LUMINANCE:
case MESA_FORMAT_INTENSITY:
case MESA_FORMAT_COLOR_INDEX:
{
GLuint i, j, k;
const GLchan *rowA = (const GLchan *) srcRowA;
const GLchan *rowB = (const GLchan *) srcRowB;
GLchan *dst = (GLchan *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
}
}
return;
case MESA_FORMAT_LUMINANCE_ALPHA:
{
GLuint i, j, k;
const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i][0] = (rowA[j][0] + rowA[k][0] +
rowB[j][0] + rowB[k][0]) / 4;
dst[i][1] = (rowA[j][1] + rowA[k][1] +
rowB[j][1] + rowB[k][1]) / 4;
}
}
return;
case MESA_FORMAT_DEPTH_COMPONENT:
{
GLuint i, j, k;
const GLfloat *rowA = (const GLfloat *) srcRowA;
const GLfloat *rowB = (const GLfloat *) srcRowB;
GLfloat *dst = (GLfloat *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
}
}
return;
case MESA_FORMAT_RGBA8888:
case MESA_FORMAT_ARGB8888:
{
GLuint i, j, k;
const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i][0] = (rowA[j][0] + rowA[k][0] +
rowB[j][0] + rowB[k][0]) / 4;
dst[i][1] = (rowA[j][1] + rowA[k][1] +
rowB[j][1] + rowB[k][1]) / 4;
dst[i][2] = (rowA[j][2] + rowA[k][2] +
rowB[j][2] + rowB[k][2]) / 4;
dst[i][3] = (rowA[j][3] + rowA[k][3] +
rowB[j][3] + rowB[k][3]) / 4;
}
}
return;
case MESA_FORMAT_RGB888:
{
GLuint i, j, k;
const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i][0] = (rowA[j][0] + rowA[k][0] +
rowB[j][0] + rowB[k][0]) / 4;
dst[i][1] = (rowA[j][1] + rowA[k][1] +
rowB[j][1] + rowB[k][1]) / 4;
dst[i][2] = (rowA[j][2] + rowA[k][2] +
rowB[j][2] + rowB[k][2]) / 4;
}
}
return;
case MESA_FORMAT_RGB565:
{
GLuint i, j, k;
const GLushort *rowA = (const GLushort *) srcRowA;
const GLushort *rowB = (const GLushort *) srcRowB;
GLushort *dst = (GLushort *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
const GLint rowAr0 = rowA[j] & 0x1f;
const GLint rowAr1 = rowA[k] & 0x1f;
const GLint rowBr0 = rowB[j] & 0x1f;
const GLint rowBr1 = rowB[k] & 0x1f;
const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
dst[i] = (blue << 11) | (green << 5) | red;
}
}
return;
case MESA_FORMAT_ARGB4444:
{
GLuint i, j, k;
const GLushort *rowA = (const GLushort *) srcRowA;
const GLushort *rowB = (const GLushort *) srcRowB;
GLushort *dst = (GLushort *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
const GLint rowAr0 = rowA[j] & 0xf;
const GLint rowAr1 = rowA[k] & 0xf;
const GLint rowBr0 = rowB[j] & 0xf;
const GLint rowBr1 = rowB[k] & 0xf;
const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
}
}
return;
case MESA_FORMAT_ARGB1555:
{
GLuint i, j, k;
const GLushort *rowA = (const GLushort *) srcRowA;
const GLushort *rowB = (const GLushort *) srcRowB;
GLushort *dst = (GLushort *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
const GLint rowAr0 = rowA[j] & 0x1f;
const GLint rowAr1 = rowA[k] & 0x1f;
const GLint rowBr0 = rowB[j] & 0x1f;
const GLint rowBr1 = rowB[k] & 0xf;
const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
}
}
return;
case MESA_FORMAT_AL88:
{
GLuint i, j, k;
const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i][0] = (rowA[j][0] + rowA[k][0] +
rowB[j][0] + rowB[k][0]) >> 2;
dst[i][1] = (rowA[j][1] + rowA[k][1] +
rowB[j][1] + rowB[k][1]) >> 2;
}
}
return;
case MESA_FORMAT_RGB332:
{
GLuint i, j, k;
const GLubyte *rowA = (const GLubyte *) srcRowA;
const GLubyte *rowB = (const GLubyte *) srcRowB;
GLubyte *dst = (GLubyte *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
const GLint rowAr0 = rowA[j] & 0x3;
const GLint rowAr1 = rowA[k] & 0x3;
const GLint rowBr0 = rowB[j] & 0x3;
const GLint rowBr1 = rowB[k] & 0x3;
const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
dst[i] = (blue << 5) | (green << 2) | red;
}
}
return;
case MESA_FORMAT_A8:
case MESA_FORMAT_L8:
case MESA_FORMAT_I8:
case MESA_FORMAT_CI8:
{
GLuint i, j, k;
const GLubyte *rowA = (const GLubyte *) srcRowA;
const GLubyte *rowB = (const GLubyte *) srcRowB;
GLubyte *dst = (GLubyte *) dstRow;
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
}
}
return;
default:
_mesa_problem(NULL, "bad format in do_row()");
}
}
static void
make_1d_mipmap(const struct gl_texture_format *format, GLint border,
GLint srcWidth, const GLubyte *srcPtr,
GLint dstWidth, GLubyte *dstPtr)
{
const GLint bpt = format->TexelBytes;
const GLubyte *src;
GLubyte *dst;
src = srcPtr + border * bpt;
dst = dstPtr + border * bpt;
do_row(format, srcWidth - 2 * border, src, src,
dstWidth - 2 * border, dst);
if (border) {
MEMCPY(dstPtr, srcPtr, bpt);
MEMCPY(dstPtr + (dstWidth - 1) * bpt,
srcPtr + (srcWidth - 1) * bpt,
bpt);
}
}
static void
make_2d_mipmap(const struct gl_texture_format *format, GLint border,
GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
{
const GLint bpt = format->TexelBytes;
const GLint srcWidthNB = srcWidth - 2 * border;
const GLint dstWidthNB = dstWidth - 2 * border;
const GLint dstHeightNB = dstHeight - 2 * border;
const GLint srcRowStride = bpt * srcWidth;
const GLint dstRowStride = bpt * dstWidth;
const GLubyte *srcA, *srcB;
GLubyte *dst;
GLint row;
srcA = srcPtr + border * ((srcWidth + 1) * bpt);
if (srcHeight > 1)
srcB = srcA + srcRowStride;
else
srcB = srcA;
dst = dstPtr + border * ((dstWidth + 1) * bpt);
for (row = 0; row < dstHeightNB; row++) {
do_row(format, srcWidthNB, srcA, srcB,
dstWidthNB, dst);
srcA += 2 * srcRowStride;
srcB += 2 * srcRowStride;
dst += dstRowStride;
}
if (border > 0) {
MEMCPY(dstPtr, srcPtr, bpt);
MEMCPY(dstPtr + (dstWidth - 1) * bpt,
srcPtr + (srcWidth - 1) * bpt, bpt);
MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
do_row(format, srcWidthNB,
srcPtr + bpt,
srcPtr + bpt,
dstWidthNB, dstPtr + bpt);
do_row(format, srcWidthNB,
srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
dstWidthNB,
dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
if (srcHeight == dstHeight) {
for (row = 1; row < srcHeight; row++) {
MEMCPY(dstPtr + dstWidth * row * bpt,
srcPtr + srcWidth * row * bpt, bpt);
MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
}
}
else {
for (row = 0; row < dstHeightNB; row += 2) {
do_row(format, 1,
srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
1, dstPtr + (dstWidth * row + 1) * bpt);
do_row(format, 1,
srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
}
}
}
}
static void
make_3d_mipmap(const struct gl_texture_format *format, GLint border,
GLint srcWidth, GLint srcHeight, GLint srcDepth,
const GLubyte *srcPtr,
GLint dstWidth, GLint dstHeight, GLint dstDepth,
GLubyte *dstPtr)
{
const GLint bpt = format->TexelBytes;
const GLint srcWidthNB = srcWidth - 2 * border;
const GLint srcDepthNB = srcDepth - 2 * border;
const GLint dstWidthNB = dstWidth - 2 * border;
const GLint dstHeightNB = dstHeight - 2 * border;
const GLint dstDepthNB = dstDepth - 2 * border;
GLvoid *tmpRowA, *tmpRowB;
GLint img, row;
GLint bytesPerSrcImage, bytesPerDstImage;
GLint bytesPerSrcRow, bytesPerDstRow;
GLint srcImageOffset, srcRowOffset;
(void) srcDepthNB;
tmpRowA = MALLOC(srcWidth * bpt);
if (!tmpRowA)
return;
tmpRowB = MALLOC(srcWidth * bpt);
if (!tmpRowB) {
FREE(tmpRowA);
return;
}
bytesPerSrcImage = srcWidth * srcHeight * bpt;
bytesPerDstImage = dstWidth * dstHeight * bpt;
bytesPerSrcRow = srcWidth * bpt;
bytesPerDstRow = dstWidth * bpt;
srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
for (img = 0; img < dstDepthNB; img++) {
const GLubyte *imgSrcA = srcPtr
+ (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
+ img * (bytesPerSrcImage + srcImageOffset);
const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
GLubyte *imgDst = dstPtr
+ (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
+ img * bytesPerDstImage;
const GLubyte *srcImgARowA = imgSrcA;
const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
const GLubyte *srcImgBRowA = imgSrcB;
const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
GLubyte *dstImgRow = imgDst;
for (row = 0; row < dstHeightNB; row++) {
do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
srcWidthNB, tmpRowA);
do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
srcWidthNB, tmpRowB);
do_row(format, srcWidthNB, tmpRowA, tmpRowB,
dstWidthNB, dstImgRow);
srcImgARowA += bytesPerSrcRow + srcRowOffset;
srcImgARowB += bytesPerSrcRow + srcRowOffset;
srcImgBRowA += bytesPerSrcRow + srcRowOffset;
srcImgBRowB += bytesPerSrcRow + srcRowOffset;
dstImgRow += bytesPerDstRow;
}
}
FREE(tmpRowA);
FREE(tmpRowB);
if (border > 0) {
make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
dstWidth, dstHeight, dstPtr);
make_2d_mipmap(format, 1, srcWidth, srcHeight,
srcPtr + bytesPerSrcImage * (srcDepth - 1),
dstWidth, dstHeight,
dstPtr + bytesPerDstImage * (dstDepth - 1));
if (srcDepth == dstDepth) {
for (img = 0; img < dstDepthNB; img++) {
const GLubyte *src;
GLubyte *dst;
src = srcPtr + (img + 1) * bytesPerSrcImage;
dst = dstPtr + (img + 1) * bytesPerDstImage;
MEMCPY(dst, src, bpt);
src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+ (srcHeight - 1) * bytesPerSrcRow;
dst = dstPtr + (img + 1) * bytesPerDstImage
+ (dstHeight - 1) * bytesPerDstRow;
MEMCPY(dst, src, bpt);
src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+ (srcWidth - 1) * bpt;
dst = dstPtr + (img + 1) * bytesPerDstImage
+ (dstWidth - 1) * bpt;
MEMCPY(dst, src, bpt);
src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+ (bytesPerSrcImage - bpt);
dst = dstPtr + (img + 1) * bytesPerDstImage
+ (bytesPerDstImage - bpt);
MEMCPY(dst, src, bpt);
}
}
else {
ASSERT(srcDepthNB == 2 * dstDepthNB);
for (img = 0; img < dstDepthNB; img++) {
const GLubyte *src;
GLubyte *dst;
src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
dst = dstPtr + (img + 1) * bytesPerDstImage;
do_row(format, 1, src, src + srcImageOffset, 1, dst);
src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+ (srcHeight - 1) * bytesPerSrcRow;
dst = dstPtr + (img + 1) * bytesPerDstImage
+ (dstHeight - 1) * bytesPerDstRow;
do_row(format, 1, src, src + srcImageOffset, 1, dst);
src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+ (srcWidth - 1) * bpt;
dst = dstPtr + (img + 1) * bytesPerDstImage
+ (dstWidth - 1) * bpt;
do_row(format, 1, src, src + srcImageOffset, 1, dst);
src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+ (bytesPerSrcImage - bpt);
dst = dstPtr + (img + 1) * bytesPerDstImage
+ (bytesPerDstImage - bpt);
do_row(format, 1, src, src + srcImageOffset, 1, dst);
}
}
}
}
void
_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
const struct gl_texture_unit *texUnit,
struct gl_texture_object *texObj)
{
const struct gl_texture_image *srcImage;
const struct gl_texture_format *convertFormat;
const GLubyte *srcData = NULL;
GLubyte *dstData = NULL;
GLint level, maxLevels;
ASSERT(texObj);
srcImage = texObj->Image[texObj->BaseLevel];
ASSERT(srcImage);
maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
ASSERT(maxLevels > 0);
if (srcImage->IsCompressed) {
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;
}
size = _mesa_bytes_per_pixel(srcImage->Format, CHAN_TYPE)
* srcImage->Width * srcImage->Height * srcImage->Depth + 20;
srcData = (GLubyte *) MALLOC(size);
if (!srcData) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
return;
}
dstData = (GLubyte *) MALLOC(size / 2);
if (!dstData) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
FREE((void *) srcData);
return;
}
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 {
convertFormat = srcImage->TexFormat;
}
for (level = texObj->BaseLevel; level < texObj->MaxLevel
&& level < maxLevels - 1; level++) {
const struct gl_texture_image *srcImage;
struct gl_texture_image *dstImage;
GLint srcWidth, srcHeight, srcDepth;
GLint dstWidth, dstHeight, dstDepth;
GLint border, bytesPerTexel;
srcImage = _mesa_select_tex_image(ctx, texUnit, target, level);
ASSERT(srcImage);
srcWidth = srcImage->Width;
srcHeight = srcImage->Height;
srcDepth = srcImage->Depth;
border = srcImage->Border;
if (srcWidth - 2 * border > 1) {
dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
}
else {
dstWidth = srcWidth;
}
if (srcHeight - 2 * border > 1) {
dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
}
else {
dstHeight = srcHeight;
}
if (srcDepth - 2 * border > 1) {
dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
}
else {
dstDepth = srcDepth;
}
if (dstWidth == srcWidth &&
dstHeight == srcHeight &&
dstDepth == srcDepth) {
if (srcImage->IsCompressed) {
FREE((void *) srcData);
FREE(dstData);
}
return;
}
dstImage = _mesa_select_tex_image(ctx, texUnit, target, 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, target, level + 1, dstImage);
}
if (dstImage->Data)
MESA_PBUFFER_FREE(dstImage->Data);
_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);
if (dstImage->IsCompressed) {
ASSERT(dstImage->CompressedSize > 0);
dstImage->Data = MESA_PBUFFER_ALLOC(dstImage->CompressedSize);
if (!dstImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
return;
}
ASSERT(srcData);
ASSERT(dstData);
}
else {
bytesPerTexel = srcImage->TexFormat->TexelBytes;
ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
dstImage->Data = MESA_PBUFFER_ALLOC(dstWidth * dstHeight * dstDepth
* bytesPerTexel);
if (!dstImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
return;
}
srcData = (const GLubyte *) srcImage->Data;
dstData = (GLubyte *) dstImage->Data;
}
switch (target) {
case GL_TEXTURE_1D:
make_1d_mipmap(convertFormat, border,
srcWidth, srcData,
dstWidth, dstData);
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:
make_2d_mipmap(convertFormat, border,
srcWidth, srcHeight, srcData,
dstWidth, dstHeight, dstData);
break;
case GL_TEXTURE_3D:
make_3d_mipmap(convertFormat, border,
srcWidth, srcHeight, srcDepth, srcData,
dstWidth, dstHeight, dstDepth, dstData);
break;
case GL_TEXTURE_RECTANGLE_NV:
break;
default:
_mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
return;
}
if (dstImage->IsCompressed) {
GLubyte *temp;
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,
srcFormat,
(const GLchan *) dstData,
dstWidth,
dstImage->TexFormat,
(GLubyte*) dstImage->Data,
dstRowStride );
temp = (GLubyte *) srcData;
srcData = dstData;
dstData = temp;
}
}
}