diff options
Diffstat (limited to 'nx-X11/extras/Mesa/src/mesa/drivers/dri/i915/i915_texstate.c')
-rw-r--r-- | nx-X11/extras/Mesa/src/mesa/drivers/dri/i915/i915_texstate.c | 922 |
1 files changed, 922 insertions, 0 deletions
diff --git a/nx-X11/extras/Mesa/src/mesa/drivers/dri/i915/i915_texstate.c b/nx-X11/extras/Mesa/src/mesa/drivers/dri/i915/i915_texstate.c new file mode 100644 index 000000000..7a274bb69 --- /dev/null +++ b/nx-X11/extras/Mesa/src/mesa/drivers/dri/i915/i915_texstate.c @@ -0,0 +1,922 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#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 i915LayoutTextureImages( i915ContextPtr i915, + struct gl_texture_object *tObj ) +{ + const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; + i915TextureObjectPtr t = (i915TextureObjectPtr) tObj->DriverData; + GLint firstLevel, lastLevel, numLevels; + GLint i, total_height, pitch; + + /* 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; + if (t->intel.image[0][i].image->IsCompressed) + { + if (t->intel.image[0][i].image->Height > 4) + total_height += t->intel.image[0][i].image->Height/4; + else + total_height += 1; + } + else + 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; +} + + +static void i945LayoutTextureImages( i915ContextPtr i915, + struct gl_texture_object *tObj ) +{ + const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; + i915TextureObjectPtr t = (i915TextureObjectPtr) tObj->DriverData; + GLint firstLevel, lastLevel, numLevels; + GLint i, total_height, pitch, sz, max_offset = 0, offset; + + + /* 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; + + /* Depending on the size of the largest images, pitch can be + * determined either by the old-style packing of cubemap faces, + * or the final row of 4x4, 2x2 and 1x1 faces below this. + */ + if (dim > 32) { + pitch = dim * t->intel.texelBytes; + pitch *= 2; /* double pitch for cube layouts */ + pitch = (pitch + 3) & ~3; + } + else { + pitch = 14 * 8 * t->intel.texelBytes; /* determined by row of + * little maps at + * bottom */ + } + + total_height = dim * 4 + 4; + + for ( face = 0 ; face < 6 ; face++) { + GLuint x = initial_offsets[face][0] * dim; + GLuint y = initial_offsets[face][1] * dim; + GLuint d = dim; + + if (dim == 4 && face >= 4) { + y = total_height - 4; + x = (face - 4) * 8; + } + else if (dim < 4) { + y = total_height - 4; + x = face * 8; + } + + 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]; + assert(t->intel.image[face][i].image); + + t->intel.image[face][i].offset = + y * pitch + x * t->intel.texelBytes; + t->intel.image[face][i].internalFormat = baseImage->Format; + + d >>= 1; + + switch (d) { + case 4: + switch (face) { + case FACE_POS_X: + case FACE_NEG_X: + x += step_offsets[face][0] * d; + y += step_offsets[face][1] * d; + break; + case FACE_POS_Y: + case FACE_NEG_Y: + y += 12; + x -= 8; + break; + case FACE_POS_Z: + case FACE_NEG_Z: + y = total_height - 4; + x = (face - 4) * 8; + break; + } + + case 2: + y = total_height - 4; + x = 16 + face * 8; + break; + + case 1: + x += 48; + break; + + default: + x += step_offsets[face][0] * d; + y += step_offsets[face][1] * d; + break; + } + } + } + max_offset = total_height * pitch; + break; + } + case GL_TEXTURE_3D: { + GLuint depth_packing = 0, depth_pack_pitch; + GLuint tmp_numLevels = numLevels; + pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes; + pitch = (pitch + 3) & ~3; + depth_pack_pitch = pitch; + + t->intel.base.dirty_images[0] = ~0; + + + 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) + 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) * + MAX2((t->intel.image[0][i].image->Depth >> depth_packing), 1); + + /* When alignment dominates, can't increase depth packing? + * Or does pitch grow??? What are the alignment constraints, + * anyway? + */ + if (depth_pack_pitch > 4) { + depth_packing++; + depth_pack_pitch <<= 2; + } + } + + max_offset = total_height * pitch; + break; + } + default: + pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes; + pitch = (pitch + 3) & ~3; + t->intel.base.dirty_images[0] = ~0; + max_offset = 0; + + for ( offset = 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 = offset; + t->intel.image[0][i].internalFormat = baseImage->Format; + + if (t->intel.image[0][i].image->IsCompressed) + sz = MAX2(1, t->intel.image[0][i].image->Height/4) * pitch; + else + sz = MAX2(2, t->intel.image[0][i].image->Height) * pitch; + + /* Because the images are packed better, the final offset + * might not be the maximal one: + */ + max_offset = MAX2(max_offset, offset + sz); + + /* LPT change: step right after second mipmap. + */ + if (i == 1) + offset += pitch / 2; + else + offset += sz; + + } + break; + } + + t->intel.Pitch = pitch; + t->intel.base.totalSize = max_offset; + t->intel.max_level = numLevels-1; +} + + + + +static void i915SetTexImages( i915ContextPtr i915, + struct gl_texture_object *tObj ) +{ + GLuint textureFormat; + i915TextureObjectPtr t = (i915TextureObjectPtr) tObj->DriverData; + const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; + 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; + + case MESA_FORMAT_RGB_FXT1: + case MESA_FORMAT_RGBA_FXT1: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1); + break; + + case MESA_FORMAT_DEPTH_COMPONENT16: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_16BIT | MT_16BIT_L16); + break; + + case MESA_FORMAT_RGBA_DXT1: + case MESA_FORMAT_RGB_DXT1: + /* + * DXTn pitches are Width/4 * blocksize in bytes + * for DXT1: blocksize=8 so Width/4*8 = Width * 2 + * for DXT3/5: blocksize=16 so Width/4*16 = Width * 4 + */ + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1); + break; + + case MESA_FORMAT_RGBA_DXT3: + t->intel.texelBytes = 4; + textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3); + break; + + case MESA_FORMAT_RGBA_DXT5: + t->intel.texelBytes = 4; + textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5); + break; + +#if 0 + case MESA_FORMAT_DEPTH_COMPONENT_X8Z24: + t->intel.texelBytes = 4; + textureFormat = (MAPSURF_32BIT | MT_32BIT_xL824); + break; +#endif + + default: + fprintf(stderr, "%s: bad image format %x\n", __FUNCTION__, + baseImage->TexFormat->MesaFormat); + abort(); + } + + + if (i915->intel.intelScreen->deviceID == PCI_CHIP_I945_G) + i945LayoutTextureImages( i915, tObj ); + else + i915LayoutTextureImages( i915, tObj ); + + t->Setup[I915_TEXREG_MS3] = + (((tObj->Image[0][t->intel.base.firstLevel]->Height - 1) << MS3_HEIGHT_SHIFT) | + ((tObj->Image[0][t->intel.base.firstLevel]->Width - 1) << MS3_WIDTH_SHIFT) | + textureFormat | + MS3_USE_FENCE_REGS); + + t->Setup[I915_TEXREG_MS4] = + ((((t->intel.Pitch / 4) - 1) << MS4_PITCH_SHIFT) | + MS4_CUBE_FACE_ENA_MASK | + (((t->intel.max_level * 4)) << MS4_MAX_LOD_SHIFT) | + ((tObj->Image[0][t->intel.base.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, shadow = 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; + } + } + + if (texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB && + texObj->Target != GL_TEXTURE_3D) { + + shadow = SS2_SHADOW_ENABLE; + shadow |= intel_translate_compare_func( texObj->CompareFunc ); + + minFilt = FILTER_4X4_FLAT; + magFilt = FILTER_4X4_FLAT; + } + + + t->Setup[I915_TEXREG_SS2] &= ~(SS2_MIN_FILTER_MASK | + SS2_MIP_FILTER_MASK | + SS2_MAG_FILTER_MASK | + SS2_SHADOW_ENABLE | + SS2_SHADOW_FUNC_MASK); + t->Setup[I915_TEXREG_SS2] |= ((minFilt << SS2_MIN_FILTER_SHIFT) | + (mipFilt << SS2_MIP_FILTER_SHIFT) | + (magFilt << SS2_MAG_FILTER_SHIFT) | + shadow); + + { + 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 ); +} + + + |