summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/i915/i830_texstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/i915/i830_texstate.c')
-rw-r--r--src/mesa/drivers/dri/i915/i830_texstate.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i915/i830_texstate.c b/src/mesa/drivers/dri/i915/i830_texstate.c
new file mode 100644
index 0000000000..acf5cc9b2b
--- /dev/null
+++ b/src/mesa/drivers/dri/i915/i830_texstate.c
@@ -0,0 +1,333 @@
+/**************************************************************************
+ *
+ * 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 "i830_context.h"
+#include "i830_reg.h"
+
+
+#define I830_TEX_UNIT_ENABLED(unit) (1<<unit)
+
+static GLboolean i830SetTexImages( i830ContextPtr i830,
+ struct gl_texture_object *tObj )
+{
+ GLuint total_height, pitch, i, textureFormat;
+ i830TextureObjectPtr t = (i830TextureObjectPtr) tObj->DriverData;
+ const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel];
+ GLint firstLevel, lastLevel, numLevels;
+
+ 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_I8; /* Kludge -- check with conform, glean */
+ 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 |
+ TM0S1_COLORSPACE_CONVERSION);
+ break;
+
+ case MESA_FORMAT_YCBCR:
+ t->intel.texelBytes = 2;
+ textureFormat = (MAPSURF_422 | MT_422_YCRCB_SWAPY | /* ??? */
+ TM0S1_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.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ * Yes, this looks overly complicated, but it's all needed.
+ */
+ 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;
+
+ /* Pitch would be subject to additional rules if texture memory were
+ * tiled. Currently it isn't.
+ */
+ if (0) {
+ pitch = 128;
+ while (pitch < tObj->Image[0][firstLevel]->Width * t->intel.texelBytes)
+ pitch *= 2;
+ }
+ else {
+ pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes;
+ pitch = (pitch + 3) & ~3;
+ }
+
+
+ /* All images must be loaded at this pitch. Count the number of
+ * lines required:
+ */
+ 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);
+ }
+
+ t->intel.Pitch = pitch;
+ t->intel.base.totalSize = total_height*pitch;
+ t->intel.max_level = i-1;
+ t->Setup[I830_TEXREG_TM0S1] =
+ (((tObj->Image[0][firstLevel]->Height - 1) << TM0S1_HEIGHT_SHIFT) |
+ ((tObj->Image[0][firstLevel]->Width - 1) << TM0S1_WIDTH_SHIFT) |
+ textureFormat);
+ t->Setup[I830_TEXREG_TM0S2] =
+ (((pitch / 4) - 1) << TM0S2_PITCH_SHIFT);
+ t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MAX_MIP_MASK;
+ t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIN_MIP_MASK;
+ t->Setup[I830_TEXREG_TM0S3] |= ((numLevels - 1)*4) << TM0S3_MIN_MIP_SHIFT;
+ t->intel.dirty = I830_UPLOAD_TEX_ALL;
+
+ return intelUploadTexImages( &i830->intel, &t->intel, 0 );
+}
+
+
+static void i830_import_tex_unit( i830ContextPtr i830,
+ i830TextureObjectPtr t,
+ GLuint unit )
+{
+ if(INTEL_DEBUG&DEBUG_TEXTURE)
+ fprintf(stderr, "%s unit(%d)\n", __FUNCTION__, unit);
+
+ if (i830->intel.CurrentTexObj[unit])
+ i830->intel.CurrentTexObj[unit]->base.bound &= ~(1U << unit);
+
+ i830->intel.CurrentTexObj[unit] = (intelTextureObjectPtr)t;
+ t->intel.base.bound |= (1 << unit);
+
+ I830_STATECHANGE( i830, I830_UPLOAD_TEX(unit) );
+
+ i830->state.Tex[unit][I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+ (LOAD_TEXTURE_MAP0 << unit) | 4);
+ i830->state.Tex[unit][I830_TEXREG_TM0S0] = (TM0S0_USE_FENCE |
+ t->intel.TextureOffset);
+
+ i830->state.Tex[unit][I830_TEXREG_TM0S1] = t->Setup[I830_TEXREG_TM0S1];
+ i830->state.Tex[unit][I830_TEXREG_TM0S2] = t->Setup[I830_TEXREG_TM0S2];
+
+ i830->state.Tex[unit][I830_TEXREG_TM0S3] &= TM0S3_LOD_BIAS_MASK;
+ i830->state.Tex[unit][I830_TEXREG_TM0S3] |= (t->Setup[I830_TEXREG_TM0S3] &
+ ~TM0S3_LOD_BIAS_MASK);
+
+ i830->state.Tex[unit][I830_TEXREG_TM0S4] = t->Setup[I830_TEXREG_TM0S4];
+ i830->state.Tex[unit][I830_TEXREG_MCS] = (t->Setup[I830_TEXREG_MCS] &
+ ~MAP_UNIT_MASK);
+ i830->state.Tex[unit][I830_TEXREG_MCS] |= MAP_UNIT(unit);
+
+ t->intel.dirty &= ~I830_UPLOAD_TEX(unit);
+}
+
+
+
+static GLboolean enable_tex_common( GLcontext *ctx, GLuint unit )
+{
+ i830ContextPtr i830 = I830_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ struct gl_texture_object *tObj = texUnit->_Current;
+ i830TextureObjectPtr t = (i830TextureObjectPtr)tObj->DriverData;
+
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ /* Fallback if there's a texture border */
+ if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) {
+ fprintf(stderr, "Texture border\n");
+ return GL_FALSE;
+ }
+
+ /* Upload teximages (not pipelined)
+ */
+ if (t->intel.base.dirty_images[0]) {
+ if (!i830SetTexImages( i830, tObj )) {
+ return GL_FALSE;
+ }
+ }
+
+ /* Update state if this is a different texture object to last
+ * time.
+ */
+ if (i830->intel.CurrentTexObj[unit] != &t->intel ||
+ (t->intel.dirty & I830_UPLOAD_TEX(unit))) {
+ i830_import_tex_unit( i830, t, unit);
+ }
+
+ I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(unit), GL_TRUE);
+
+ return GL_TRUE;
+}
+
+static GLboolean enable_tex_rect( GLcontext *ctx, GLuint unit )
+{
+ i830ContextPtr i830 = I830_CONTEXT(ctx);
+ GLuint mcs = i830->state.Tex[unit][I830_TEXREG_MCS];
+
+ mcs &= ~TEXCOORDS_ARE_NORMAL;
+ mcs |= TEXCOORDS_ARE_IN_TEXELUNITS;
+
+ if (mcs != i830->state.Tex[unit][I830_TEXREG_MCS]) {
+ I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit));
+ i830->state.Tex[unit][I830_TEXREG_MCS] = mcs;
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean enable_tex_2d( GLcontext *ctx, GLuint unit )
+{
+ i830ContextPtr i830 = I830_CONTEXT(ctx);
+ GLuint mcs = i830->state.Tex[unit][I830_TEXREG_MCS];
+
+ mcs &= ~TEXCOORDS_ARE_IN_TEXELUNITS;
+ mcs |= TEXCOORDS_ARE_NORMAL;
+
+ if (mcs != i830->state.Tex[unit][I830_TEXREG_MCS]) {
+ I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit));
+ i830->state.Tex[unit][I830_TEXREG_MCS] = mcs;
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean disable_tex( GLcontext *ctx, GLuint unit )
+{
+ i830ContextPtr i830 = I830_CONTEXT(ctx);
+
+ /* This is happening too often. I need to conditionally send diffuse
+ * state to the card. Perhaps a diffuse dirty flag of some kind.
+ * Will need to change this logic if more than 2 texture units are
+ * used. We need to only do this up to the last unit enabled, or unit
+ * one if nothing is enabled.
+ */
+
+ if ( i830->intel.CurrentTexObj[unit] != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ i830->intel.CurrentTexObj[unit]->base.bound &= ~(1U << 0);
+ i830->intel.CurrentTexObj[unit] = NULL;
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean i830UpdateTexUnit( 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;
+
+ if (texUnit->_ReallyEnabled == TEXTURE_1D_BIT ||
+ texUnit->_ReallyEnabled == TEXTURE_2D_BIT) {
+ return (enable_tex_common( ctx, unit ) &&
+ enable_tex_2d( ctx, unit ));
+ }
+ else if (texUnit->_ReallyEnabled == TEXTURE_RECT_BIT) {
+ return (enable_tex_common( ctx, unit ) &&
+ enable_tex_rect( ctx, unit ));
+ }
+ else if (texUnit->_ReallyEnabled) {
+ return GL_FALSE;
+ }
+ else {
+ return disable_tex( ctx, unit );
+ }
+}
+
+
+void i830UpdateTextureState( intelContextPtr intel )
+{
+ i830ContextPtr i830 = I830_CONTEXT(intel);
+ GLcontext *ctx = &intel->ctx;
+ GLboolean ok;
+
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__);
+
+ I830_ACTIVESTATE(i830, I830_UPLOAD_TEX_ALL, GL_FALSE);
+
+ ok = (i830UpdateTexUnit( ctx, 0 ) &&
+ i830UpdateTexUnit( ctx, 1 ) &&
+ i830UpdateTexUnit( ctx, 2 ) &&
+ i830UpdateTexUnit( ctx, 3 ));
+
+ FALLBACK( intel, I830_FALLBACK_TEXTURE, !ok );
+
+ if (ok)
+ i830EmitTextureBlend( i830 );
+}
+
+
+