/* * Mesa 3-D graphics library * Version: 6.5.2 * * Copyright (C) 1999-2006 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"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Authors: * Brian Paul */ /* * The functions in this file are mostly related to software texture fallbacks. * This includes texture image transfer/packing and texel fetching. * Hardware drivers will likely override most of this. */ #include "main/glheader.h" #include "main/imports.h" #include "main/colormac.h" #include "main/context.h" #include "main/convolve.h" #include "main/image.h" #include "main/macros.h" #include "main/mipmap.h" #include "main/texformat.h" #include "main/teximage.h" #include "main/texstore.h" #include "s_context.h" #include "s_depth.h" #include "s_span.h" /** * Read an RGBA image from the frame buffer. * This is used by glCopyTex[Sub]Image[12]D(). * \param x window source x * \param y window source y * \param width image width * \param height image height * \param type datatype for returned GL_RGBA image * \return pointer to image */ static GLvoid * read_color_image( GLcontext *ctx, GLint x, GLint y, GLenum type, GLsizei width, GLsizei height ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; const GLint pixelSize = _mesa_bytes_per_pixel(GL_RGBA, type); const GLint stride = width * pixelSize; GLint row; GLubyte *image, *dst; image = (GLubyte *) _mesa_malloc(width * height * pixelSize); if (!image) return NULL; RENDER_START(swrast, ctx); dst = image; for (row = 0; row < height; row++) { _swrast_read_rgba_span(ctx, rb, width, x, y + row, type, dst); dst += stride; } RENDER_FINISH(swrast, ctx); return image; } /** * As above, but read data from depth buffer. Returned as GLuints. * \sa read_color_image */ static GLuint * read_depth_image( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_renderbuffer *rb = ctx->ReadBuffer->_DepthBuffer; SWcontext *swrast = SWRAST_CONTEXT(ctx); GLuint *image, *dst; GLint i; image = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); if (!image) return NULL; RENDER_START(swrast, ctx); dst = image; for (i = 0; i < height; i++) { _swrast_read_depth_span_uint(ctx, rb, width, x, y + i, dst); dst += width; } RENDER_FINISH(swrast, ctx); return image; } /** * As above, but read data from depth+stencil buffers. */ static GLuint * read_depth_stencil_image(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height) { struct gl_renderbuffer *depthRb = ctx->ReadBuffer->_DepthBuffer; struct gl_renderbuffer *stencilRb = ctx->ReadBuffer->_StencilBuffer; SWcontext *swrast = SWRAST_CONTEXT(ctx); GLuint *image, *dst; GLint i; ASSERT(depthRb); ASSERT(stencilRb); image = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); if (!image) return NULL; RENDER_START(swrast, ctx); /* read from depth buffer */ dst = image; if (depthRb->DataType == GL_UNSIGNED_INT) { for (i = 0; i < height; i++) { _swrast_get_row(ctx, depthRb, width, x, y + i, dst, sizeof(GLuint)); dst += width; } } else { GLushort z16[MAX_WIDTH]; ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT); for (i = 0; i < height; i++) { GLint j; _swrast_get_row(ctx, depthRb, width, x, y + i, z16, sizeof(GLushort)); /* convert GLushorts to GLuints */ for (j = 0; j < width; j++) { dst[j] = z16[j]; } dst += width; } } /* put depth values into bits 0xffffff00 */ if (ctx->ReadBuffer->Visual.depthBits == 24) { GLint j; for (j = 0; j < width * height; j++) { image[j] <<= 8; } } else if (ctx->ReadBuffer->Visual.depthBits == 16) { GLint j; for (j = 0; j < width * height; j++) { image[j] = (image[j] << 16) | (image[j] & 0xff00); } } else { /* this handles arbitrary depthBits >= 12 */ const GLint rShift = ctx->ReadBuffer->Visual.depthBits; const GLint lShift = 32 - rShift; GLint j; for (j = 0; j < width * height; j++) { GLuint z = (image[j] << lShift); image[j] = z | (z >> rShift); } } /* read stencil values and interleave into image array */ dst = image; for (i = 0; i < height; i++) { GLstencil stencil[MAX_WIDTH]; GLint j; ASSERT(8 * sizeof(GLstencil) == stencilRb->StencilBits); _swrast_get_row(ctx, stencilRb, width, x, y + i, stencil, sizeof(GLstencil)); for (j = 0; j < width; j++) { dst[j] = (dst[j] & 0xffffff00) | (stencil[j] & 0xff); } dst += width; } RENDER_FINISH(swrast, ctx); return image; } static GLboolean is_depth_format(GLenum format) { switch (format) { case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: return GL_TRUE; default: return GL_FALSE; } } static GLboolean is_depth_stencil_format(GLenum format) { switch (format) { case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: return GL_TRUE; default: return GL_FALSE; } } /* * Fallback for Driver.CopyTexImage1D(). */ void _swrast_copy_teximage1d( GLcontext *ctx, GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border ) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage1D); if (is_depth_format(internalFormat)) { /* read depth image from framebuffer */ GLuint *image = read_depth_image(ctx, x, y, width, 1); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); return; } /* call glTexImage1D to redefine the texture */ ctx->Driver.TexImage1D(ctx, target, level, internalFormat, width, border, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else if (is_depth_stencil_format(internalFormat)) { /* read depth/stencil image from framebuffer */ GLuint *image = read_depth_stencil_image(ctx, x, y, width, 1); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); return; } /* call glTexImage1D to redefine the texture */ ctx->Driver.TexImage1D(ctx, target, level, internalFormat, width, border, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else { /* read RGBA image from framebuffer */ const GLenum format = GL_RGBA; const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; GLvoid *image = read_color_image(ctx, x, y, type, width, 1); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); return; } /* call glTexImage1D to redefine the texture */ ctx->Driver.TexImage1D(ctx, target, level, internalFormat, width, border, format, type, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } /* GL_SGIS_generate_mipmap */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { ctx->Driver.GenerateMipmap(ctx, target, texObj); } } /** * Fallback for Driver.CopyTexImage2D(). * * We implement CopyTexImage by reading the image from the framebuffer * then passing it to the ctx->Driver.TexImage2D() function. * * Device drivers should try to implement direct framebuffer->texture copies. */ void _swrast_copy_teximage2d( GLcontext *ctx, GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage2D); if (is_depth_format(internalFormat)) { /* read depth image from framebuffer */ GLuint *image = read_depth_image(ctx, x, y, width, height); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); return; } /* call glTexImage2D to redefine the texture */ ctx->Driver.TexImage2D(ctx, target, level, internalFormat, width, height, border, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else if (is_depth_stencil_format(internalFormat)) { GLuint *image = read_depth_stencil_image(ctx, x, y, width, height); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); return; } /* call glTexImage2D to redefine the texture */ ctx->Driver.TexImage2D(ctx, target, level, internalFormat, width, height, border, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else { /* read RGBA image from framebuffer */ const GLenum format = GL_RGBA; const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; GLvoid *image = read_color_image(ctx, x, y, type, width, height); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); return; } /* call glTexImage2D to redefine the texture */ ctx->Driver.TexImage2D(ctx, target, level, internalFormat, width, height, border, format, type, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } /* GL_SGIS_generate_mipmap */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { ctx->Driver.GenerateMipmap(ctx, target, texObj); } } /* * Fallback for Driver.CopyTexSubImage1D(). */ void _swrast_copy_texsubimage1d( GLcontext *ctx, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage1D); if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) { /* read depth image from framebuffer */ GLuint *image = read_depth_image(ctx, x, y, width, 1); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D"); return; } /* call glTexSubImage1D to redefine the texture */ ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { /* read depth/stencil image from framebuffer */ GLuint *image = read_depth_stencil_image(ctx, x, y, width, 1); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D"); return; } /* call glTexImage1D to redefine the texture */ ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else { /* read RGBA image from framebuffer */ const GLenum format = GL_RGBA; const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; GLvoid *image = read_color_image(ctx, x, y, type, width, 1); if (!image) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D" ); return; } /* now call glTexSubImage1D to do the real work */ ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width, format, type, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } /* GL_SGIS_generate_mipmap */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { ctx->Driver.GenerateMipmap(ctx, target, texObj); } } /** * Fallback for Driver.CopyTexSubImage2D(). * * Read the image from the framebuffer then hand it * off to ctx->Driver.TexSubImage2D(). */ void _swrast_copy_texsubimage2d( GLcontext *ctx, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage2D); if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) { /* read depth image from framebuffer */ GLuint *image = read_depth_image(ctx, x, y, width, height); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D"); return; } /* call glTexImage2D to redefine the texture */ ctx->Driver.TexSubImage2D(ctx, target, level, xoffset, yoffset, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { /* read depth/stencil image from framebuffer */ GLuint *image = read_depth_stencil_image(ctx, x, y, width, height); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D"); return; } /* call glTexImage2D to redefine the texture */ ctx->Driver.TexSubImage2D(ctx, target, level, xoffset, yoffset, width, height, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else { /* read RGBA image from framebuffer */ const GLenum format = GL_RGBA; const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; GLvoid *image = read_color_image(ctx, x, y, type, width, height); if (!image) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D" ); return; } /* now call glTexSubImage2D to do the real work */ ctx->Driver.TexSubImage2D(ctx, target, level, xoffset, yoffset, width, height, format, type, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } /* GL_SGIS_generate_mipmap */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { ctx->Driver.GenerateMipmap(ctx, target, texObj); } } /* * Fallback for Driver.CopyTexSubImage3D(). */ void _swrast_copy_texsubimage3d( GLcontext *ctx, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); ASSERT(texObj); texImage = _mesa_select_tex_image(ctx, texObj, target, level); ASSERT(texImage); ASSERT(ctx->Driver.TexImage3D); if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) { /* read depth image from framebuffer */ GLuint *image = read_depth_image(ctx, x, y, width, height); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D"); return; } /* call glTexImage3D to redefine the texture */ ctx->Driver.TexSubImage3D(ctx, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { /* read depth/stencil image from framebuffer */ GLuint *image = read_depth_stencil_image(ctx, x, y, width, height); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D"); return; } /* call glTexImage3D to redefine the texture */ ctx->Driver.TexSubImage3D(ctx, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } else { /* read RGBA image from framebuffer */ const GLenum format = GL_RGBA; const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; GLvoid *image = read_color_image(ctx, x, y, type, width, height); if (!image) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D" ); return; } /* now call glTexSubImage3D to do the real work */ ctx->Driver.TexSubImage3D(ctx, target, level, xoffset, yoffset, zoffset, width, height, 1, format, type, image, &ctx->DefaultPacking, texObj, texImage); _mesa_free(image); } /* GL_SGIS_generate_mipmap */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { ctx->Driver.GenerateMipmap(ctx, target, texObj); } }