From 41b58954e1742493452b91d9ecdb761db5de3bed Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Thu, 10 Jun 2004 12:48:07 +0000 Subject: New driver for i915 as well as older i830/i845/i865 chipsets. --- src/mesa/drivers/dri/i915/intel_tex.c | 665 ++++++++++++++++++++++++++++++++++ 1 file changed, 665 insertions(+) create mode 100644 src/mesa/drivers/dri/i915/intel_tex.c (limited to 'src/mesa/drivers/dri/i915/intel_tex.c') diff --git a/src/mesa/drivers/dri/i915/intel_tex.c b/src/mesa/drivers/dri/i915/intel_tex.c new file mode 100644 index 0000000000..fac6efa96c --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_tex.c @@ -0,0 +1,665 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "mtypes.h" +#include "imports.h" +#include "simple_list.h" +#include "enums.h" +#include "image.h" +#include "texstore.h" +#include "texformat.h" +#include "teximage.h" +#include "texmem.h" +#include "texobj.h" +#include "swrast/swrast.h" + +#include "mm.h" + +#include "intel_screen.h" +#include "intel_batchbuffer.h" +#include "intel_context.h" +#include "intel_tex.h" +#include "intel_ioctl.h" + + + +static GLboolean +intelValidateClientStorage( intelContextPtr intel, GLenum target, + GLint internalFormat, + GLint srcWidth, GLint srcHeight, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) + +{ + GLcontext *ctx = &intel->ctx; + int texelBytes; + + if (0) + fprintf(stderr, "intformat %s format %s type %s\n", + _mesa_lookup_enum_by_nr( internalFormat ), + _mesa_lookup_enum_by_nr( format ), + _mesa_lookup_enum_by_nr( type )); + + if (!ctx->Unpack.ClientStorage) + return 0; + + if (ctx->_ImageTransferState || + texImage->IsCompressed || + texObj->GenerateMipmap) + return 0; + + + /* This list is incomplete + */ + switch ( internalFormat ) { + case GL_RGBA: + if ( format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV ) { + texImage->TexFormat = &_mesa_texformat_argb8888; + texelBytes = 4; + } + else + return 0; + break; + + case GL_RGB: + if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) { + texImage->TexFormat = &_mesa_texformat_rgb565; + texelBytes = 2; + } + else + return 0; + break; + + case GL_YCBCR_MESA: + if ( format == GL_YCBCR_MESA && + type == GL_UNSIGNED_SHORT_8_8_REV_APPLE ) { + texImage->TexFormat = &_mesa_texformat_ycbcr_rev; + texelBytes = 2; + } + else if ( format == GL_YCBCR_MESA && + (type == GL_UNSIGNED_SHORT_8_8_APPLE || + type == GL_UNSIGNED_BYTE)) { + texImage->TexFormat = &_mesa_texformat_ycbcr; + texelBytes = 2; + } + else + return 0; + break; + + + default: + return 0; + } + + /* Could deal with these packing issues, but currently don't: + */ + if (packing->SkipPixels || + packing->SkipRows || + packing->SwapBytes || + packing->LsbFirst) { + return 0; + } + + { + GLint srcRowStride = _mesa_image_row_stride(packing, srcWidth, + format, type); + + + if (0) + fprintf(stderr, "%s: srcRowStride %d/%x\n", + __FUNCTION__, srcRowStride, srcRowStride); + + /* Could check this later in upload, pitch restrictions could be + * relaxed, but would need to store the image pitch somewhere, + * as packing details might change before image is uploaded: + */ + if (!intelIsAgpMemory( intel, pixels, srcHeight * srcRowStride ) || + (srcRowStride & 63)) + return 0; + + + /* Have validated that _mesa_transfer_teximage would be a straight + * memcpy at this point. NOTE: future calls to TexSubImage will + * overwrite the client data. This is explicitly mentioned in the + * extension spec. + */ + texImage->Data = (void *)pixels; + texImage->IsClientData = GL_TRUE; + texImage->RowStride = srcRowStride / texelBytes; + return 1; + } +} + + + +static void intelTexImage1D( 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 ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert(t); + intelFlush( ctx ); + driSwapOutTextureObject( t ); + + texImage->IsClientData = GL_FALSE; + + _mesa_store_teximage1d( ctx, target, level, internalFormat, + width, border, format, type, + pixels, packing, texObj, texImage ); + + t->dirty_images[0] |= (1 << level); +} + +static void intelTexSubImage1D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert(t); + intelFlush( ctx ); + driSwapOutTextureObject( t ); + + _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, + format, type, pixels, packing, texObj, + texImage); +} + + +/* Handles 2D, CUBE, RECT: + */ +static void intelTexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, 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 ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + assert(t); + intelFlush( ctx ); + driSwapOutTextureObject( t ); + texImage->IsClientData = GL_FALSE; + + if (intelValidateClientStorage( INTEL_CONTEXT(ctx), target, + internalFormat, + width, height, + format, type, pixels, + packing, texObj, texImage)) { + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "%s: Using client storage\n", __FUNCTION__); + } + else { + _mesa_store_teximage2d( ctx, target, level, internalFormat, + width, height, border, format, type, + pixels, packing, texObj, texImage ); + + t->dirty_images[face] |= (1 << level); + } +} + +static void intelTexSubImage2D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + if (texImage->IsClientData && + (char *)pixels == (char *)texImage->Data + + ((xoffset + yoffset * texImage->RowStride) * + texImage->TexFormat->TexelBytes)) { + + /* Notification only - no upload required */ + } + else { + assert( t ); /* this _should_ be true */ + intelFlush( ctx ); + driSwapOutTextureObject( t ); + + _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, type, pixels, packing, texObj, + texImage); + + t->dirty_images[face] |= (1 << level); + } +} + + + +static void intelTexImage3D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint depth, + 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 ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert(t); + driSwapOutTextureObject( t ); + texImage->IsClientData = GL_FALSE; + + _mesa_store_teximage3d(ctx, target, level, internalFormat, + width, height, depth, border, + format, type, pixels, + &ctx->Unpack, texObj, texImage); + + t->dirty_images[0] |= (1 << level); +} + + +static void +intelTexSubImage3D( GLcontext *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert( t ); /* this _should_ be true */ + driSwapOutTextureObject( t ); + + _mesa_store_texsubimage3d(ctx, target, level, xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, packing, texObj, texImage); + + t->dirty_images[0] |= (1 << level); +} + + + + +static void intelDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj ) +{ + driTextureObject * t = (driTextureObject *) tObj->DriverData; + + if ( t != NULL ) { + intelFlush( ctx ); + driDestroyTextureObject( t ); + } + + /* Free mipmap images and the texture object itself */ + _mesa_delete_texture_object(ctx, tObj); +} + + +static const struct gl_texture_format * +intelChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + const GLboolean do32bpt = ( intel->intelScreen->cpp == 4 && + intel->intelScreen->textureSize > 4*1024*1024); + + switch ( internalFormat ) { + case 4: + case GL_RGBA: + case GL_COMPRESSED_RGBA: + if ( format == GL_BGRA ) { + if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) { + return &_mesa_texformat_argb8888; + } + else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) { + return &_mesa_texformat_argb4444; + } + else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) { + return &_mesa_texformat_argb1555; + } + } + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + + case 3: + case GL_RGB: + case GL_COMPRESSED_RGB: + if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) { + return &_mesa_texformat_rgb565; + } + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; + + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + + case GL_RGBA4: + case GL_RGBA2: + return &_mesa_texformat_argb4444; + + case GL_RGB5_A1: + return &_mesa_texformat_argb1555; + + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; + + case GL_RGB5: + case GL_RGB4: + case GL_R3_G3_B2: + return &_mesa_texformat_rgb565; + + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + case GL_COMPRESSED_ALPHA: +/* if (1 || intel->intelScreen->deviceID == PCI_CHIP_I915_G) */ + return &_mesa_texformat_a8; +/* else */ +/* return &_mesa_texformat_al88; */ + + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + case GL_COMPRESSED_LUMINANCE: + return &_mesa_texformat_l8; + + 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: + case GL_COMPRESSED_LUMINANCE_ALPHA: + return &_mesa_texformat_al88; + + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + case GL_COMPRESSED_INTENSITY: + return &_mesa_texformat_i8; + + case GL_YCBCR_MESA: + if (type == GL_UNSIGNED_SHORT_8_8_MESA || + type == GL_UNSIGNED_BYTE) + return &_mesa_texformat_ycbcr; + else + return &_mesa_texformat_ycbcr_rev; + + default: + fprintf(stderr, "unexpected texture format in %s\n", __FUNCTION__); + return NULL; + } + + return NULL; /* never get here */ +} + + + +void intelDestroyTexObj(intelContextPtr intel, intelTextureObjectPtr t) +{ + unsigned i; + + if ( intel == NULL ) + return; + + if ( t->age > intel->dirtyAge ) + intel->dirtyAge = t->age; + + for ( i = 0 ; i < MAX_TEXTURE_UNITS ; i++ ) { + if ( t == intel->CurrentTexObj[ i ] ) + intel->CurrentTexObj[ i ] = NULL; + } +} + + + +/* Upload an image from mesa's internal copy. Image may be 1D, 2D or + * 3D. Cubemaps are expanded elsewhere. + */ +static void intelUploadTexImage( intelContextPtr intel, + intelTextureObjectPtr t, + const struct gl_texture_image *image, + const GLuint offset ) +{ + + if (!image || !image->Data) + return; + + if (image->Depth == 1 && image->IsClientData) { + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "Blit uploading\n"); + + /* Do it with a blit. + */ + intelEmitCopyBlitLocked( intel, + image->TexFormat->TexelBytes, + image->RowStride, /* ? */ + intelGetMemoryOffsetMESA( NULL, 0, image->Data ), + t->Pitch / image->TexFormat->TexelBytes, + intelGetMemoryOffsetMESA( NULL, 0, t->BufAddr + offset ), + 0, 0, + 0, 0, + image->Width, + image->Height); + } + else { + GLuint row_len = image->Width * image->TexFormat->TexelBytes; + GLubyte *dst = (GLubyte *)(t->BufAddr + offset); + GLubyte *src = (GLubyte *)image->Data; + GLuint d, j; + + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, + "Upload image %dx%dx%d offset %xm row_len %x " + "pitch %x depth_pitch %x\n", + image->Width, image->Height, image->Depth, offset, + row_len, t->Pitch, t->depth_pitch); + + if (row_len == t->Pitch) { + for (d = 0; d < image->Depth; d++) { + memcpy( dst, src, t->Pitch * image->Height ); + dst += t->depth_pitch; + src += row_len * image->Height; + } + } + else { + for (d = 0 ; d < image->Depth ; d++) { + for (j = 0 ; j < image->Height ; j++) { + __memcpy(dst, src, row_len ); + src += row_len; + dst += t->Pitch; + } + + dst += t->depth_pitch - (t->Pitch * image->Height); + } + } + } +} + + + +int intelUploadTexImages( intelContextPtr intel, + intelTextureObjectPtr t, + GLuint face) +{ + const int numLevels = t->base.lastLevel - t->base.firstLevel + 1; + const struct gl_texture_image *firstImage = t->image[face][t->base.firstLevel].image; + int pitch = firstImage->RowStride * firstImage->TexFormat->TexelBytes; + + /* Can we texture out of the existing client data? */ + if ( numLevels == 1 && + firstImage->IsClientData && + (pitch & 3) == 0) { + + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "AGP texturing from client memory\n"); + + t->TextureOffset = intelAgpOffsetFromVirtual( intel, firstImage->Data ); + t->BufAddr = 0; + t->dirty = ~0; + return GL_TRUE; + } + else { + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "Uploading client data to agp\n"); + + INTEL_FIREVERTICES( intel ); + LOCK_HARDWARE( intel ); + + if ( t->base.memBlock == NULL ) { + int heap; + + heap = driAllocateTexture( intel->texture_heaps, intel->nr_heaps, + (driTextureObject *) t ); + if ( heap == -1 ) { + UNLOCK_HARDWARE( intel ); + return GL_FALSE; + } + + /* Set the base offset of the texture image */ + t->BufAddr = intel->intelScreen->tex.map + t->base.memBlock->ofs; + t->TextureOffset = intel->intelScreen->textureOffset + t->base.memBlock->ofs; + t->dirty = ~0; + } + + + /* Let the world know we've used this memory recently. + */ + driUpdateTextureLRU( (driTextureObject *) t ); + + + /* Upload any images that are new */ + if (t->base.dirty_images[face]) { + int i; + + intelWaitForIdle( intel ); + + for (i = 0 ; i < numLevels ; i++) { + int level = i + t->base.firstLevel; + + if (t->base.dirty_images[face] & (1<image[face][i].image; + GLuint offset = t->image[face][i].offset; + + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "upload level %d, offset %x\n", + level, offset); + + intelUploadTexImage( intel, t, image, offset ); + } + } + t->base.dirty_images[face] = 0; + intel->perf_boxes |= I830_BOX_TEXTURE_LOAD; + } + + UNLOCK_HARDWARE( intel ); + return GL_TRUE; + } +} + +/** + * Allocate a new texture object. + * Called via ctx->Driver.NewTextureObject. + * Note: this function will be called during context creation to + * allocate the default texture objects. + * Note: we could use containment here to 'derive' the driver-specific + * texture object from the core mesa gl_texture_object. Not done at this time. + */ +static struct gl_texture_object * +intelNewTextureObject( GLcontext *ctx, GLuint name, GLenum target ) +{ + struct gl_texture_object *obj = _mesa_new_texture_object(ctx, name, target); + INTEL_CONTEXT(ctx)->vtbl.alloc_tex_obj( obj ); + return obj; +} + + +void intelInitTextureFuncs( struct dd_function_table *functions ) +{ + functions->NewTextureObject = intelNewTextureObject; + functions->ChooseTextureFormat = intelChooseTextureFormat; + functions->TexImage1D = intelTexImage1D; + functions->TexImage2D = intelTexImage2D; + functions->TexImage3D = intelTexImage3D; + functions->TexSubImage1D = intelTexSubImage1D; + functions->TexSubImage2D = intelTexSubImage2D; + functions->TexSubImage3D = intelTexSubImage3D; + functions->CopyTexImage1D = _swrast_copy_teximage1d; + functions->CopyTexImage2D = _swrast_copy_teximage2d; + functions->CopyTexSubImage1D = _swrast_copy_texsubimage1d; + functions->CopyTexSubImage2D = _swrast_copy_texsubimage2d; + functions->CopyTexSubImage3D = _swrast_copy_texsubimage3d; + functions->DeleteTexture = intelDeleteTexture; + functions->UpdateTexturePalette = NULL; + functions->IsTextureResident = driIsTextureResident; + functions->TestProxyTexImage = _mesa_test_proxy_teximage; + functions->DeleteTexture = intelDeleteTexture; +} -- cgit v1.2.3