diff options
author | Keith Whitwell <keith@tungstengraphics.com> | 2004-06-10 12:48:07 +0000 |
---|---|---|
committer | Keith Whitwell <keith@tungstengraphics.com> | 2004-06-10 12:48:07 +0000 |
commit | 41b58954e1742493452b91d9ecdb761db5de3bed (patch) | |
tree | f170cda67626d1a0d4e7e51ea502553b0f144077 /src/mesa/drivers/dri/i915/i915_texstate.c | |
parent | d7f76c7c8830882d849b42777ca601859ffac15a (diff) |
New driver for i915 as well as older i830/i845/i865 chipsets.
Diffstat (limited to 'src/mesa/drivers/dri/i915/i915_texstate.c')
-rw-r--r-- | src/mesa/drivers/dri/i915/i915_texstate.c | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i915/i915_texstate.c b/src/mesa/drivers/dri/i915/i915_texstate.c new file mode 100644 index 0000000000..93656dd151 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_texstate.c @@ -0,0 +1,625 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "simple_list.h" +#include "enums.h" +#include "texformat.h" +#include "texstore.h" + +#include "mm.h" + +#include "intel_screen.h" +#include "intel_ioctl.h" +#include "intel_tex.h" + +#include "i915_context.h" +#include "i915_reg.h" + +static GLint initial_offsets[6][2] = { {0,0}, + {0,2}, + {1,0}, + {1,2}, + {1,1}, + {1,3} }; + + +static GLint step_offsets[6][2] = { {0,2}, + {0,2}, + {-1,2}, + {-1,2}, + {-1,1}, + {-1,1} }; + + +#define I915_TEX_UNIT_ENABLED(unit) (1<<unit) + +static void i915SetTexImages( i915ContextPtr i915, + struct gl_texture_object *tObj ) +{ + GLuint total_height, pitch, i, textureFormat; + i915TextureObjectPtr t = (i915TextureObjectPtr) tObj->DriverData; + const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; + GLint firstLevel, lastLevel, numLevels; + GLint ss2 = 0; + + switch( baseImage->TexFormat->MesaFormat ) { + case MESA_FORMAT_L8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_L8; + break; + + case MESA_FORMAT_I8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_I8; + break; + + case MESA_FORMAT_A8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_A8; + break; + + case MESA_FORMAT_AL88: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_AY88; + break; + + case MESA_FORMAT_RGB565: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_RGB565; + break; + + case MESA_FORMAT_ARGB1555: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB1555; + break; + + case MESA_FORMAT_ARGB4444: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB4444; + break; + + case MESA_FORMAT_ARGB8888: + t->intel.texelBytes = 4; + textureFormat = MAPSURF_32BIT | MT_32BIT_ARGB8888; + break; + + case MESA_FORMAT_YCBCR_REV: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_NORMAL); + ss2 |= SS2_COLORSPACE_CONVERSION; + break; + + case MESA_FORMAT_YCBCR: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_SWAPY); + ss2 |= SS2_COLORSPACE_CONVERSION; + break; + + default: + fprintf(stderr, "%s: bad image format\n", __FUNCTION__); + abort(); + } + + /* Compute which mipmap levels we really want to send to the hardware. + */ + driCalculateTextureFirstLastLevel( (driTextureObject *) t ); + + + /* Figure out the amount of memory required to hold all the mipmap + * levels. Choose the smallest pitch to accomodate the largest + * mipmap: + */ + firstLevel = t->intel.base.firstLevel; + lastLevel = t->intel.base.lastLevel; + numLevels = lastLevel - firstLevel + 1; + + + + /* All images must be loaded at this pitch. Count the number of + * lines required: + */ + switch (tObj->Target) { + case GL_TEXTURE_CUBE_MAP: { + const GLuint dim = tObj->Image[0][firstLevel]->Width; + GLuint face; + + pitch = dim * t->intel.texelBytes; + pitch *= 2; /* double pitch for cube layouts */ + pitch = (pitch + 3) & ~3; + + total_height = dim * 4; + + for ( face = 0 ; face < 6 ; face++) { + GLuint x = initial_offsets[face][0] * dim; + GLuint y = initial_offsets[face][1] * dim; + GLuint d = dim; + + t->intel.base.dirty_images[face] = ~0; + + assert(tObj->Image[face][firstLevel]->Width == dim); + assert(tObj->Image[face][firstLevel]->Height == dim); + + for (i = 0; i < numLevels; i++) { + t->intel.image[face][i].image = tObj->Image[face][firstLevel + i]; + if (!t->intel.image[face][i].image) { + fprintf(stderr, "no image %d %d\n", face, i); + break; /* can't happen */ + } + + t->intel.image[face][i].offset = + y * pitch + x * t->intel.texelBytes; + t->intel.image[face][i].internalFormat = baseImage->Format; + + d >>= 1; + x += step_offsets[face][0] * d; + y += step_offsets[face][1] * d; + } + } + break; + } + case GL_TEXTURE_3D: { + GLuint virtual_height; + GLuint tmp_numLevels = numLevels; + pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes; + pitch = (pitch + 3) & ~3; + t->intel.base.dirty_images[0] = ~0; + + /* Calculate the size of a single slice. Hardware demands a + * minimum of 8 mipmaps, some of which might ultimately not be + * used: + */ + if (tmp_numLevels < 9) + tmp_numLevels = 9; + + virtual_height = tObj->Image[0][firstLevel]->Height; + + for ( total_height = i = 0 ; i < tmp_numLevels ; i++ ) { + t->intel.image[0][i].image = tObj->Image[0][firstLevel + i]; + if (t->intel.image[0][i].image) { + t->intel.image[0][i].offset = total_height * pitch; + t->intel.image[0][i].internalFormat = baseImage->Format; + } + + total_height += MAX2(2, virtual_height); + virtual_height >>= 1; + } + + t->intel.depth_pitch = total_height * pitch; + + /* Multiply slice size by texture depth for total size. It's + * remarkable how wasteful of memory all the i8x0 texture + * layouts are. + */ + total_height *= t->intel.image[0][0].image->Depth; + break; + } + default: + pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes; + pitch = (pitch + 3) & ~3; + t->intel.base.dirty_images[0] = ~0; + + for ( total_height = i = 0 ; i < numLevels ; i++ ) { + t->intel.image[0][i].image = tObj->Image[0][firstLevel + i]; + if (!t->intel.image[0][i].image) + break; + + t->intel.image[0][i].offset = total_height * pitch; + t->intel.image[0][i].internalFormat = baseImage->Format; + total_height += MAX2(2, t->intel.image[0][i].image->Height); + } + break; + } + + t->intel.Pitch = pitch; + t->intel.base.totalSize = total_height*pitch; + t->intel.max_level = numLevels-1; + t->Setup[I915_TEXREG_MS3] = + (((tObj->Image[0][firstLevel]->Height - 1) << MS3_HEIGHT_SHIFT) | + ((tObj->Image[0][firstLevel]->Width - 1) << MS3_WIDTH_SHIFT) | + textureFormat | + MS3_USE_FENCE_REGS); + t->Setup[I915_TEXREG_MS4] = + ((((pitch / 4) - 1) << MS4_PITCH_SHIFT) | + MS4_CUBE_FACE_ENA_MASK | + (((t->intel.max_level * 4)) << MS4_MAX_LOD_SHIFT) | + ((tObj->Image[0][firstLevel]->Depth - 1) << MS4_VOLUME_DEPTH_SHIFT)); + + t->Setup[I915_TEXREG_SS2] &= ~SS2_COLORSPACE_CONVERSION; + t->Setup[I915_TEXREG_SS2] |= ss2; + + t->intel.dirty = I915_UPLOAD_TEX_ALL; +} + + +/* The i915 (and related graphics cores) do not support GL_CLAMP. The + * Intel drivers for "other operating systems" implement GL_CLAMP as + * GL_CLAMP_TO_EDGE, so the same is done here. + */ +static GLuint translate_wrap_mode( GLenum wrap ) +{ + switch( wrap ) { + case GL_REPEAT: return TEXCOORDMODE_WRAP; + case GL_CLAMP: return TEXCOORDMODE_CLAMP_EDGE; /* not quite correct */ + case GL_CLAMP_TO_EDGE: return TEXCOORDMODE_CLAMP_EDGE; + case GL_CLAMP_TO_BORDER: return TEXCOORDMODE_CLAMP_BORDER; + case GL_MIRRORED_REPEAT: return TEXCOORDMODE_MIRROR; + default: return TEXCOORDMODE_WRAP; + } +} + + +/** + */ +static void i915ImportTexObjState( struct gl_texture_object *texObj ) +{ + i915TextureObjectPtr t = (i915TextureObjectPtr)texObj->DriverData; + int minFilt = 0, mipFilt = 0, magFilt = 0; + + if(INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + switch (texObj->MinFilter) { + case GL_NEAREST: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_NONE; + break; + case GL_LINEAR: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_NEAREST; + break; + case GL_LINEAR_MIPMAP_NEAREST: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_LINEAR; + break; + default: + break; + } + + if ( texObj->MaxAnisotropy > 1.0 ) { + minFilt = FILTER_ANISOTROPIC; + magFilt = FILTER_ANISOTROPIC; + } + else { + switch (texObj->MagFilter) { + case GL_NEAREST: + magFilt = FILTER_NEAREST; + break; + case GL_LINEAR: + magFilt = FILTER_LINEAR; + break; + default: + break; + } + } + + t->Setup[I915_TEXREG_SS2] &= ~SS2_MIN_FILTER_MASK; + t->Setup[I915_TEXREG_SS2] &= ~SS2_MIP_FILTER_MASK; + t->Setup[I915_TEXREG_SS2] &= ~SS2_MAG_FILTER_MASK; + t->Setup[I915_TEXREG_SS2] |= ((minFilt << SS2_MIN_FILTER_SHIFT) | + (mipFilt << SS2_MIP_FILTER_SHIFT) | + (magFilt << SS2_MAG_FILTER_SHIFT)); + + { + GLuint ss3 = t->Setup[I915_TEXREG_SS3] & ~(SS3_TCX_ADDR_MODE_MASK | + SS3_TCY_ADDR_MODE_MASK | + SS3_TCZ_ADDR_MODE_MASK); + GLenum ws = texObj->WrapS; + GLenum wt = texObj->WrapT; + GLenum wr = texObj->WrapR; + + t->refs_border_color = 0; + + if (texObj->Target == GL_TEXTURE_3D && + (texObj->MinFilter != GL_NEAREST || + texObj->MagFilter != GL_NEAREST)) { + + /* Try to mimic GL_CLAMP functionality a little better - + * switch to CLAMP_TO_BORDER whenever a non-NEAREST filter is + * in use. Only do this for 3D textures at the moment -- + * doing it universally would fix the conform texbc.c + * failure, though. + */ + if (ws == GL_CLAMP) ws = GL_CLAMP_TO_BORDER; + if (wt == GL_CLAMP) wt = GL_CLAMP_TO_BORDER; + if (wr == GL_CLAMP) wr = GL_CLAMP_TO_BORDER; + + /* 3D textures don't seem to respect the border color. + * Fallback if there's ever a danger that they might refer to + * it. + */ + if (ws == GL_CLAMP_TO_BORDER) t->refs_border_color = 1; + if (wt == GL_CLAMP_TO_BORDER) t->refs_border_color = 1; + if (wr == GL_CLAMP_TO_BORDER) t->refs_border_color = 1; + } + + ss3 |= translate_wrap_mode(ws) << SS3_TCX_ADDR_MODE_SHIFT; + ss3 |= translate_wrap_mode(wt) << SS3_TCY_ADDR_MODE_SHIFT; + ss3 |= translate_wrap_mode(wr) << SS3_TCZ_ADDR_MODE_SHIFT; + + if (ss3 != t->Setup[I915_TEXREG_SS3]) { + t->intel.dirty = I915_UPLOAD_TEX_ALL; + t->Setup[I915_TEXREG_SS3] = ss3; + } + } + + { + const GLubyte *color = texObj->_BorderChan; + + t->Setup[I915_TEXREG_SS4] = INTEL_PACKCOLOR8888(color[0],color[1], + color[2],color[3]); + } +} + + + +static void i915_import_tex_unit( i915ContextPtr i915, + i915TextureObjectPtr t, + GLuint unit ) +{ + GLuint state[I915_TEX_SETUP_SIZE]; + + if(INTEL_DEBUG&DEBUG_TEXTURE) + fprintf(stderr, "%s unit(%d)\n", __FUNCTION__, unit); + + if (i915->intel.CurrentTexObj[unit]) + i915->intel.CurrentTexObj[unit]->base.bound &= ~(1U << unit); + + i915->intel.CurrentTexObj[unit] = (intelTextureObjectPtr)t; + t->intel.base.bound |= (1 << unit); + + if (t->intel.dirty & I915_UPLOAD_TEX(unit)) { + i915ImportTexObjState( t->intel.base.tObj ); + t->intel.dirty &= ~I915_UPLOAD_TEX(unit); + } + + state[I915_TEXREG_MS2] = t->intel.TextureOffset; + state[I915_TEXREG_MS3] = t->Setup[I915_TEXREG_MS3]; + state[I915_TEXREG_MS4] = t->Setup[I915_TEXREG_MS4]; + + state[I915_TEXREG_SS2] = (i915->state.Tex[unit][I915_TEXREG_SS2] & + SS2_LOD_BIAS_MASK); + state[I915_TEXREG_SS2] |= (t->Setup[I915_TEXREG_SS2] & ~SS2_LOD_BIAS_MASK); + + state[I915_TEXREG_SS3] = (i915->state.Tex[unit][I915_TEXREG_SS3] & + SS3_NORMALIZED_COORDS); + state[I915_TEXREG_SS3] |= (t->Setup[I915_TEXREG_SS3] & + ~(SS3_NORMALIZED_COORDS| + SS3_TEXTUREMAP_INDEX_MASK)); + + state[I915_TEXREG_SS3] |= (unit<<SS3_TEXTUREMAP_INDEX_SHIFT); + + state[I915_TEXREG_SS4] = t->Setup[I915_TEXREG_SS4]; + + + if (memcmp(state, i915->state.Tex[unit], sizeof(state)) != 0) { + I915_STATECHANGE( i915, I915_UPLOAD_TEX(unit) ); + memcpy(i915->state.Tex[unit], state, sizeof(state)); + } +} + + + +static GLboolean enable_tex_common( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + + if (0) fprintf(stderr, "%s %d\n", __FUNCTION__, unit); + + if (!(i915->state.active & I915_UPLOAD_TEX(unit))) { + I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_TRUE); + } + + /* Fallback if there's a texture border */ + if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) { + return GL_FALSE; + } + + + /* Update state if this is a different texture object to last + * time. + */ + if (i915->intel.CurrentTexObj[unit] != &t->intel || + (t->intel.dirty & I915_UPLOAD_TEX(unit))) { + i915_import_tex_unit( i915, t, unit); + i915->tex_program.translated = 0; + } + + return GL_TRUE; +} + +static GLboolean enable_tex_rect( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + GLuint ss3 = i915->state.Tex[unit][I915_TEXREG_SS3]; + + ss3 &= ~SS3_NORMALIZED_COORDS; + + if (ss3 != i915->state.Tex[unit][I915_TEXREG_SS3]) { + I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + i915->state.Tex[unit][I915_TEXREG_SS3] = ss3; + } + + /* Upload teximages (not pipelined) + */ + if (t->intel.base.dirty_images[0]) { + i915SetTexImages( i915, tObj ); + if (!intelUploadTexImages( &i915->intel, &t->intel, 0 )) { + return GL_FALSE; + } + } + + return GL_TRUE; +} + + +static GLboolean enable_tex_2d( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + GLuint ss3 = i915->state.Tex[unit][I915_TEXREG_SS3]; + + ss3 |= SS3_NORMALIZED_COORDS; + + if (ss3 != i915->state.Tex[unit][I915_TEXREG_SS3]) { + I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + i915->state.Tex[unit][I915_TEXREG_SS3] = ss3; + } + + /* Upload teximages (not pipelined) + */ + if (t->intel.base.dirty_images[0]) { + i915SetTexImages( i915, tObj ); + if (!intelUploadTexImages( &i915->intel, &t->intel, 0 )) { + return GL_FALSE; + } + } + + return GL_TRUE; +} + +static GLboolean enable_tex_cube( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + GLuint ss3 = i915->state.Tex[unit][I915_TEXREG_SS3]; + GLuint face; + + ss3 |= SS3_NORMALIZED_COORDS; + + if (ss3 != i915->state.Tex[unit][I915_TEXREG_SS3]) { + I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + i915->state.Tex[unit][I915_TEXREG_SS3] = ss3; + } + + /* Upload teximages (not pipelined) + */ + if ( t->intel.base.dirty_images[0] || t->intel.base.dirty_images[1] || + t->intel.base.dirty_images[2] || t->intel.base.dirty_images[3] || + t->intel.base.dirty_images[4] || t->intel.base.dirty_images[5] ) { + i915SetTexImages( i915, tObj ); + } + + /* upload (per face) */ + for (face = 0; face < 6; face++) { + if (t->intel.base.dirty_images[face]) { + if (!intelUploadTexImages( &i915->intel, &t->intel, face )) { + return GL_FALSE; + } + } + } + + + return GL_TRUE; +} + +static GLboolean enable_tex_3d( GLcontext *ctx, GLuint unit ) +{ + struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + + /* 3D textures on I915 seem to get bogus border colors, hence this + * fallback: + */ + if (t->refs_border_color) + return GL_FALSE; + + return GL_TRUE; +} + + + + +static GLboolean disable_tex( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + + if (i915->state.active & I915_UPLOAD_TEX(unit)) { + I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_FALSE); + } + + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + if ( i915->intel.CurrentTexObj[unit] != NULL ) { + i915->intel.CurrentTexObj[unit]->base.bound &= ~(1U << 0); + i915->intel.CurrentTexObj[unit] = NULL; + } + + return GL_TRUE; +} + +static GLboolean i915UpdateTexUnit( GLcontext *ctx, GLuint unit ) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + if (texUnit->_ReallyEnabled && + INTEL_CONTEXT(ctx)->intelScreen->textureSize < 2048 * 1024) + return GL_FALSE; + + switch (texUnit->_ReallyEnabled) { + case TEXTURE_1D_BIT: + case TEXTURE_2D_BIT: + return (enable_tex_2d( ctx, unit ) && + enable_tex_common( ctx, unit )); + case TEXTURE_RECT_BIT: + return (enable_tex_rect( ctx, unit ) && + enable_tex_common( ctx, unit )); + case TEXTURE_CUBE_BIT: + return (enable_tex_cube( ctx, unit ) && + enable_tex_common( ctx, unit )); + case TEXTURE_3D_BIT: + return (enable_tex_2d( ctx, unit ) && + enable_tex_common( ctx, unit ) && + enable_tex_3d( ctx, unit)); + case 0: + return disable_tex( ctx, unit ); + default: + return GL_FALSE; + } +} + + +void i915UpdateTextureState( intelContextPtr intel ) +{ + GLcontext *ctx = &intel->ctx; + GLboolean ok = GL_TRUE; + GLuint i; + + for (i = 0 ; i < I915_TEX_UNITS && ok ; i++) { + ok = i915UpdateTexUnit( ctx, i ); + } + + FALLBACK( intel, I915_FALLBACK_TEXTURE, !ok ); +} + + + |