Port texture allocation code from R200.
authorVladimir Dergachev <volodya@freedesktop.org>
Mon, 3 Jan 2005 05:44:20 +0000 (05:44 +0000)
committerVladimir Dergachev <volodya@freedesktop.org>
Mon, 3 Jan 2005 05:44:20 +0000 (05:44 +0000)
Hook it up, so lesson06 displays red colored textures.

src/mesa/drivers/dri/r300/Makefile
src/mesa/drivers/dri/r300/r300_cmdbuf.c
src/mesa/drivers/dri/r300/r300_context.c
src/mesa/drivers/dri/r300/r300_context.h
src/mesa/drivers/dri/r300/r300_ioctl.c
src/mesa/drivers/dri/r300/r300_ioctl.h
src/mesa/drivers/dri/r300/r300_render.c
src/mesa/drivers/dri/r300/r300_tex.c [new file with mode: 0644]
src/mesa/drivers/dri/r300/r300_tex.h [new file with mode: 0644]
src/mesa/drivers/dri/r300/r300_texmem.c [new file with mode: 0644]
src/mesa/drivers/dri/r300/r300_texstate.c [new file with mode: 0644]

index ef25526..cfe8176 100644 (file)
@@ -33,6 +33,9 @@ DRIVER_SOURCES = \
                 r300_state.c \
                 r300_render.c \
                 r300_lib.c \
+                r300_texmem.c \
+                r300_tex.c \
+                r300_texstate.c \
                 \
                 r200_context.c \
                 r200_ioctl.c \
@@ -52,6 +55,7 @@ DRIVER_SOURCES = \
                 r200_vtxfmt_sse.c \
                 r200_vtxfmt_x86.c
 
+
 C_SOURCES = $(COMMON_SOURCES) $(DRIVER_SOURCES)
 
 X86_SOURCES = r200_vtxtmp_x86.S
index 82ad315..e2bb270 100644 (file)
@@ -46,6 +46,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "radeon_ioctl.h"
 #include "r300_context.h"
 #include "r300_ioctl.h"
+#include "radeon_reg.h"
 #include "r300_reg.h"
 #include "r300_cmdbuf.h"
 
@@ -545,3 +546,65 @@ void r300DestroyCmdBuf(r300ContextPtr r300)
        }
 }
 
+void r300EmitBlit(r300ContextPtr rmesa,
+                 GLuint color_fmt,
+                 GLuint src_pitch,
+                 GLuint src_offset,
+                 GLuint dst_pitch,
+                 GLuint dst_offset,
+                 GLint srcx, GLint srcy,
+                 GLint dstx, GLint dsty, GLuint w, GLuint h)
+{
+       drm_radeon_cmd_header_t *cmd;
+
+       if (RADEON_DEBUG & DEBUG_IOCTL)
+               fprintf(stderr,
+                       "%s src %x/%x %d,%d dst: %x/%x %d,%d sz: %dx%d\n",
+                       __FUNCTION__, src_pitch, src_offset, srcx, srcy,
+                       dst_pitch, dst_offset, dstx, dsty, w, h);
+
+       assert((src_pitch & 63) == 0);
+       assert((dst_pitch & 63) == 0);
+       assert((src_offset & 1023) == 0);
+       assert((dst_offset & 1023) == 0);
+       assert(w < (1 << 16));
+       assert(h < (1 << 16));
+
+       cmd =
+           (drm_radeon_cmd_header_t *) r200AllocCmdBuf(rmesa, 8 * sizeof(int),
+                                                       __FUNCTION__);
+
+       cmd[0].header.cmd_type = RADEON_CMD_PACKET3;
+       cmd[1].i = R200_CP_CMD_BITBLT_MULTI | (5 << 16);
+       cmd[2].i = (RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+                   RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+                   RADEON_GMC_BRUSH_NONE |
+                   (color_fmt << 8) |
+                   RADEON_GMC_SRC_DATATYPE_COLOR |
+                   RADEON_ROP3_S |
+                   RADEON_DP_SRC_SOURCE_MEMORY |
+                   RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
+
+       cmd[3].i = ((src_pitch / 64) << 22) | (src_offset >> 10);
+       cmd[4].i = ((dst_pitch / 64) << 22) | (dst_offset >> 10);
+       cmd[5].i = (srcx << 16) | srcy;
+       cmd[6].i = (dstx << 16) | dsty; /* dst */
+       cmd[7].i = (w << 16) | h;
+}
+
+void r300EmitWait(r300ContextPtr rmesa, GLuint flags)
+{
+       if (rmesa->radeon.dri.drmMinor >= 6) {
+               drm_radeon_cmd_header_t *cmd;
+
+               assert(!(flags & ~(RADEON_WAIT_2D | RADEON_WAIT_3D)));
+
+               cmd =
+                   (drm_radeon_cmd_header_t *) r200AllocCmdBuf(rmesa,
+                                                               1 * sizeof(int),
+                                                               __FUNCTION__);
+               cmd[0].i = 0;
+               cmd[0].wait.cmd_type = RADEON_CMD_WAIT;
+               cmd[0].wait.flags = flags;
+       }
+}
index 9831dc6..88a67ce 100644 (file)
@@ -57,6 +57,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "r300_cmdbuf.h"
 #include "r300_state.h"
 #include "r300_ioctl.h"
+#include "r300_tex.h"
 
 #include "vblank.h"
 #include "utils.h"
@@ -147,7 +148,7 @@ GLboolean r300CreateContext(const __GLcontextModes * glVisual,
        struct dd_function_table functions;
        r300ContextPtr r300;
        GLcontext *ctx;
-       int tcl_mode;
+       int tcl_mode, i;
 
        assert(glVisual);
        assert(driContextPriv);
@@ -171,7 +172,7 @@ GLboolean r300CreateContext(const __GLcontextModes * glVisual,
        _mesa_init_driver_functions(&functions);
        r300InitIoctlFuncs(&functions);
        r300InitStateFuncs(&functions);
-       //r200InitTextureFuncs(&functions);
+       r300InitTextureFuncs(&functions);
 
        if (!radeonInitContext(&r300->radeon, &functions,
                               glVisual, driContextPriv, sharedContextPrivate)) {
@@ -180,6 +181,35 @@ GLboolean r300CreateContext(const __GLcontextModes * glVisual,
        }
 
        /* Init r300 context data */
+       r300->dma.buf0_address = r300->radeon.radeonScreen->buffers->list[0].address;
+
+       (void)memset(r300->texture_heaps, 0, sizeof(r300->texture_heaps));
+       make_empty_list(&r300->swapped);
+
+       r300->nr_heaps = 1 /* screen->numTexHeaps */ ;
+       assert(r300->nr_heaps < R200_NR_TEX_HEAPS);
+       for (i = 0; i < r300->nr_heaps; i++) {
+               r300->texture_heaps[i] = driCreateTextureHeap(i, r300,
+                                                              screen->
+                                                              texSize[i], 12,
+                                                              RADEON_NR_TEX_REGIONS,
+                                                              (drmTextureRegionPtr)
+                                                              r300->radeon.sarea->
+                                                              tex_list[i],
+                                                              &r300->radeon.sarea->
+                                                              tex_age[i],
+                                                              &r300->swapped,
+                                                              sizeof
+                                                              (r300TexObj),
+                                                              (destroy_texture_object_t
+                                                               *)
+                                                              r300DestroyTexObj);
+       }
+       r300->texture_depth = driQueryOptioni(&r300->radeon.optionCache,
+                                              "texture_depth");
+       if (r300->texture_depth == DRI_CONF_TEXTURE_DEPTH_FB)
+               r300->texture_depth = (screen->cpp == 4) ?
+                   DRI_CONF_TEXTURE_DEPTH_32 : DRI_CONF_TEXTURE_DEPTH_16;
 
        /* Set the maximum texture size small enough that we can guarentee that
         * all texture units can bind a maximal texture and have them both in
@@ -239,8 +269,8 @@ GLboolean r300CreateContext(const __GLcontextModes * glVisual,
 #if 0
        /* plug in a few more device driver functions */
        /* XXX these should really go right after _mesa_init_driver_functions() */
-       r200InitPixelFuncs(ctx);
-       r200InitSwtcl(ctx);
+       r300InitPixelFuncs(ctx);
+       r300InitSwtcl(ctx);
 #endif
        TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;
 
index b5d8212..54826ea 100644 (file)
@@ -66,6 +66,44 @@ static __inline__ uint32_t r300PackFloat32(float fl)
        return u.u;
 }
 
+
+/************ DMA BUFFERS **************/
+
+/* Need refcounting on dma buffers:
+ */
+struct r300_dma_buffer {
+       int refcount;           /* the number of retained regions in buf */
+       drmBufPtr buf;
+};
+
+#define GET_START(rvb) (rmesa->radeon.radeonScreen->gart_buffer_offset +               \
+                       (rvb)->address - rmesa->dma.buf0_address +      \
+                       (rvb)->start)
+
+/* A retained region, eg vertices for indexed vertices.
+ */
+struct r300_dma_region {
+       struct r300_dma_buffer *buf;
+       char *address;          /* == buf->address */
+       int start, end, ptr;    /* offsets from start of buf */
+       int aos_start;
+       int aos_stride;
+       int aos_size;
+};
+
+struct r300_dma {
+       /* Active dma region.  Allocations for vertices and retained
+        * regions come from here.  Also used for emitting random vertices,
+        * these may be flushed by calling flush_current();
+        */
+       struct r300_dma_region current;
+
+       void (*flush) (r300ContextPtr);
+
+       char *buf0_address;     /* start of buf[0], for index calcs */
+       GLuint nr_released_bufs;        /* flush after so many buffers released */
+};
+
        /* Texture related */
 
 #define TEX_0   0x1
@@ -74,8 +112,8 @@ static __inline__ uint32_t r300PackFloat32(float fl)
 #define TEX_3  0x8
 #define TEX_4  0x10
 #define TEX_5  0x20
-#define TEX_6  0x20
-#define TEX_7  0x20
+#define TEX_6  0x40
+#define TEX_7  0x80
 #define TEX_ALL 0xff
 
 typedef struct r300_tex_obj r300TexObj, *r300TexObjPtr;
@@ -114,6 +152,17 @@ struct r300_tex_obj {
        GLboolean border_fallback;
 };
 
+struct r300_texture_env_state {
+       r300TexObjPtr texobj;
+       GLenum format;
+       GLenum envMode;
+};
+
+#define R300_MAX_TEXTURE_UNITS 6
+
+struct r300_texture_state {
+       struct r300_texture_env_state unit[R300_MAX_TEXTURE_UNITS];
+};
 
 /**
  * A block of hardware state.
@@ -402,6 +451,7 @@ struct r300_depthbuffer_state {
 
 struct r300_state {
        struct r300_depthbuffer_state depth;
+       struct r300_texture_state texture;
 };
 
 
@@ -419,6 +469,38 @@ struct r300_context {
        int elt_count;  /* size of the buffer for vertices */
        int attrib_count; /* size of the buffer for vertex attributes.. Somehow it can be different ? */
        
+
+       /* Vertex buffers
+        */
+       #if 0 /* we'll need it later, but not now */
+       struct r300_ioctl ioctl;
+       #endif
+       struct r300_dma dma;
+       GLboolean save_on_next_unlock;
+
+       /* Texture object bookkeeping
+        */
+       unsigned nr_heaps;
+       driTexHeap *texture_heaps[R200_NR_TEX_HEAPS];
+       driTextureObject swapped;
+       int texture_depth;
+       float initialMaxAnisotropy;
+
+       /* Clientdata textures;
+        */
+       GLuint prefer_gart_client_texturing;
+
+       /* TCL stuff
+        */
+       GLmatrix TexGenMatrix[R300_MAX_TEXTURE_UNITS];
+       GLboolean recheck_texgen[R300_MAX_TEXTURE_UNITS];
+       GLboolean TexGenNeedNormals[R300_MAX_TEXTURE_UNITS];
+       GLuint TexMatEnabled;
+       GLuint TexMatCompSel;
+       GLuint TexGenEnabled;
+       GLuint TexGenInputs;
+       GLuint TexGenCompSel;
+       GLmatrix tmpmat;
 };
 
 #define R300_CONTEXT(ctx)              ((r300ContextPtr)(ctx->DriverCtx))
index 63a7d54..ffadaff 100644 (file)
@@ -282,6 +282,195 @@ void r300Flush(GLcontext * ctx)
                r300FlushCmdBuf(r300, __FUNCTION__);
 }
 
+void r300RefillCurrentDmaRegion(r300ContextPtr rmesa)
+{
+       struct r200_dma_buffer *dmabuf;
+       int fd = rmesa->radeon.dri.fd;
+       int index = 0;
+       int size = 0;
+       drmDMAReq dma;
+       int ret;
+
+       if (RADEON_DEBUG & (DEBUG_IOCTL | DEBUG_DMA))
+               fprintf(stderr, "%s\n", __FUNCTION__);
+
+       if (rmesa->dma.flush) {
+               rmesa->dma.flush(rmesa);
+       }
+
+       if (rmesa->dma.current.buf)
+               r300ReleaseDmaRegion(rmesa, &rmesa->dma.current, __FUNCTION__);
+
+       if (rmesa->dma.nr_released_bufs > 4)
+               r300FlushCmdBuf(rmesa, __FUNCTION__);
+
+       dma.context = rmesa->radeon.dri.hwContext;
+       dma.send_count = 0;
+       dma.send_list = NULL;
+       dma.send_sizes = NULL;
+       dma.flags = 0;
+       dma.request_count = 1;
+       dma.request_size = RADEON_BUFFER_SIZE;
+       dma.request_list = &index;
+       dma.request_sizes = &size;
+       dma.granted_count = 0;
+
+       LOCK_HARDWARE(&rmesa->radeon);  /* no need to validate */
+
+       while (1) {
+               ret = drmDMA(fd, &dma);
+               if (ret == 0)
+                       break;
+
+               if (rmesa->dma.nr_released_bufs) {
+                       r200FlushCmdBufLocked(rmesa, __FUNCTION__);
+               }
+
+               if (rmesa->radeon.do_usleeps) {
+                       UNLOCK_HARDWARE(&rmesa->radeon);
+                       DO_USLEEP(1);
+                       LOCK_HARDWARE(&rmesa->radeon);
+               }
+       }
+
+       UNLOCK_HARDWARE(&rmesa->radeon);
+
+       if (RADEON_DEBUG & DEBUG_DMA)
+               fprintf(stderr, "Allocated buffer %d\n", index);
+
+       dmabuf = CALLOC_STRUCT(r300_dma_buffer);
+       dmabuf->buf = &rmesa->radeon.radeonScreen->buffers->list[index];
+       dmabuf->refcount = 1;
+
+       rmesa->dma.current.buf = dmabuf;
+       rmesa->dma.current.address = dmabuf->buf->address;
+       rmesa->dma.current.end = dmabuf->buf->total;
+       rmesa->dma.current.start = 0;
+       rmesa->dma.current.ptr = 0;
+}
+
+void r300ReleaseDmaRegion(r300ContextPtr rmesa,
+                         struct r300_dma_region *region, const char *caller)
+{
+       if (RADEON_DEBUG & DEBUG_IOCTL)
+               fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
+
+       if (!region->buf)
+               return;
+
+       if (rmesa->dma.flush)
+               rmesa->dma.flush(rmesa);
+
+       if (--region->buf->refcount == 0) {
+               drm_radeon_cmd_header_t *cmd;
+
+               if (RADEON_DEBUG & (DEBUG_IOCTL | DEBUG_DMA))
+                       fprintf(stderr, "%s -- DISCARD BUF %d\n", __FUNCTION__,
+                               region->buf->buf->idx);
+
+               cmd =
+                   (drm_radeon_cmd_header_t *) r300AllocCmdBuf(rmesa,
+                                                               sizeof(*cmd),
+                                                               __FUNCTION__);
+               cmd->dma.cmd_type = RADEON_CMD_DMA_DISCARD;
+               cmd->dma.buf_idx = region->buf->buf->idx;
+               FREE(region->buf);
+               rmesa->dma.nr_released_bufs++;
+       }
+
+       region->buf = 0;
+       region->start = 0;
+}
+
+/* Allocates a region from rmesa->dma.current.  If there isn't enough
+ * space in current, grab a new buffer (and discard what was left of current)
+ */
+void r300AllocDmaRegion(r300ContextPtr rmesa,
+                       struct r300_dma_region *region,
+                       int bytes, int alignment)
+{
+       if (RADEON_DEBUG & DEBUG_IOCTL)
+               fprintf(stderr, "%s %d\n", __FUNCTION__, bytes);
+
+       if (rmesa->dma.flush)
+               rmesa->dma.flush(rmesa);
+
+       if (region->buf)
+               r300ReleaseDmaRegion(rmesa, region, __FUNCTION__);
+
+       alignment--;
+       rmesa->dma.current.start = rmesa->dma.current.ptr =
+           (rmesa->dma.current.ptr + alignment) & ~alignment;
+
+       if (rmesa->dma.current.ptr + bytes > rmesa->dma.current.end)
+               r300RefillCurrentDmaRegion(rmesa);
+
+       region->start = rmesa->dma.current.start;
+       region->ptr = rmesa->dma.current.start;
+       region->end = rmesa->dma.current.start + bytes;
+       region->address = rmesa->dma.current.address;
+       region->buf = rmesa->dma.current.buf;
+       region->buf->refcount++;
+
+       rmesa->dma.current.ptr += bytes;        /* bug - if alignment > 7 */
+       rmesa->dma.current.start =
+           rmesa->dma.current.ptr = (rmesa->dma.current.ptr + 0x7) & ~0x7;
+
+       assert(rmesa->dma.current.ptr <= rmesa->dma.current.end);
+}
+
+/* Called via glXGetMemoryOffsetMESA() */
+GLuint r300GetMemoryOffsetMESA(__DRInativeDisplay * dpy, int scrn,
+                              const GLvoid * pointer)
+{
+       GET_CURRENT_CONTEXT(ctx);
+       r300ContextPtr rmesa;
+       GLuint card_offset;
+
+       if (!ctx || !(rmesa = R300_CONTEXT(ctx))) {
+               fprintf(stderr, "%s: no context\n", __FUNCTION__);
+               return ~0;
+       }
+
+       if (!r300IsGartMemory(rmesa, pointer, 0))
+               return ~0;
+
+       if (rmesa->radeon.dri.drmMinor < 6)
+               return ~0;
+
+       card_offset = r300GartOffsetFromVirtual(rmesa, pointer);
+
+       return card_offset - rmesa->radeon.radeonScreen->gart_base;
+}
+
+GLboolean r300IsGartMemory(r300ContextPtr rmesa, const GLvoid * pointer,
+                          GLint size)
+{
+       int offset =
+           (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
+       int valid = (size >= 0 && offset >= 0
+                    && offset + size < rmesa->radeon.radeonScreen->gartTextures.size);
+
+       if (RADEON_DEBUG & DEBUG_IOCTL)
+               fprintf(stderr, "r300IsGartMemory( %p ) : %d\n", pointer,
+                       valid);
+
+       return valid;
+}
+
+GLuint r300GartOffsetFromVirtual(r300ContextPtr rmesa, const GLvoid * pointer)
+{
+       int offset =
+           (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
+
+       fprintf(stderr, "offset=%08x\n", offset);
+
+       if (offset < 0 || offset > rmesa->radeon.radeonScreen->gartTextures.size)
+               return ~0;
+       else
+               return rmesa->radeon.radeonScreen->gart_texture_offset + offset;
+}
+
 void r300InitIoctlFuncs(struct dd_function_table *functions)
 {
        functions->Clear = r300Clear;
index 26ca07c..9a2ece5 100644 (file)
@@ -36,6 +36,18 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #ifndef __R300_IOCTL_H__
 #define __R300_IOCTL_H__
 
+#include "r300_context.h"
+#include "radeon_drm.h"
+
+extern GLuint r300GetMemoryOffsetMESA(__DRInativeDisplay * dpy, int scrn,
+                                     const GLvoid * pointer);
+
+extern GLboolean r300IsGartMemory(r300ContextPtr rmesa, const GLvoid * pointer,
+                                 GLint size);
+
+extern GLuint r300GartOffsetFromVirtual(r300ContextPtr rmesa,
+                                       const GLvoid * pointer);
+
 extern void r300Flush(GLcontext * ctx);
 extern void r300InitIoctlFuncs(struct dd_function_table *functions);
 
index dbc18a8..c16a960 100644 (file)
@@ -458,12 +458,14 @@ static void r300_render_tex_primitive(r300ContextPtr rmesa,
                
    type=r300_get_primitive_type(rmesa, ctx, start, end, prim);
                
+               #if 1
                fprintf(stderr,"ObjPtr: size=%d stride=%d\n", 
                        VB->ObjPtr->size, VB->ObjPtr->stride);
                fprintf(stderr,"ColorPtr[0]: size=%d stride=%d\n", 
                        VB->ColorPtr[0]->size, VB->ColorPtr[0]->stride);
                fprintf(stderr,"TexCoordPtr[0]: size=%d stride=%d\n", 
                        VB->TexCoordPtr[0]->size, VB->TexCoordPtr[0]->stride);
+               #endif
    
    if(type<0)return;
 
@@ -508,16 +510,21 @@ static GLboolean r300_run_tex_render(GLcontext *ctx,
    AOS_DATA vb_arrays[3];
    /* Only do 2d textures */
    struct gl_texture_object *to=ctx->Texture.Unit[0].Current2D;
-   radeonScreenPtr rsp=rmesa->radeon.radeonScreen;
+   r300TexObjPtr t=to->DriverData;
    LOCAL_VARS
        
    
+   /* Update texture state - needs to be done only when actually changed..
+      All the time for now.. */
+   r300UpdateTextureState(ctx);
+   
    /* Flush state - make sure command buffer is nice and large */
    r300Flush(ctx);
    
    //fprintf(stderr, "You can enable texture drawing in %s:%s \n", __FILE__, __FUNCTION__);
    //return GL_TRUE;
-   
+
+
        if (RADEON_DEBUG == DEBUG_PRIMS)
                fprintf(stderr, "%s\n", __FUNCTION__);
 
@@ -549,8 +556,6 @@ static GLboolean r300_run_tex_render(GLcontext *ctx,
    vb_arrays[2].ncomponents=4;
    vb_arrays[2].reg=REG_TEX0;
 
-   /* Fill texture with some random data */
-   for(i=0;i<100000;i++)((int *)(rsp->gartTextures.map))[i]=rand();
      
    /* needed before starting 3d operation .. */
    reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
@@ -578,8 +583,16 @@ static GLboolean r300_run_tex_render(GLcontext *ctx,
    SINGLE_TEXTURE_PIPELINE.vertex_shader.unknown2.body.f[2]=1.0;
    SINGLE_TEXTURE_PIPELINE.vertex_shader.unknown2.body.f[3]=0.0;
 
-   /* Put it in the beginning of texture memory */
-   SINGLE_TEXTURE_PIPELINE.texture_unit[0].offset=rsp->gartTextures.handle;
+   /* Use actual texture offset */
+   
+   SINGLE_TEXTURE_PIPELINE.texture_unit[0].offset=rmesa->radeon.radeonScreen->fbLocation+t->offset;
+   #if 0
+   SINGLE_TEXTURE_PIPELINE.texture_unit[0].format=t->format;
+   SINGLE_TEXTURE_PIPELINE.texture_unit[0].size=t->size;
+   #endif
+   SINGLE_TEXTURE_PIPELINE.texture_unit[0].filter=t->filter;
+   SINGLE_TEXTURE_PIPELINE.texture_unit[0].unknown1=t->pitch; /* Unknown 1 is pitch ! */
+   SINGLE_TEXTURE_PIPELINE.texture_unit[0].filter=t->filter;
    
    
    /* Upload texture, a hack, really  we can do a lot better */
@@ -644,6 +657,7 @@ reg_start(R300_RS_INTERP_0,7);
    reg_start(0x4f18,0);
        e32(0x00000003);
          
+//   exit(-1);
    fprintf(stderr, "\n");
    return GL_FALSE;
 }
@@ -671,7 +685,7 @@ static GLboolean r300_run_render(GLcontext *ctx,
         if(ctx->Texture.Unit[0].Enabled)
                return r300_run_tex_render(ctx, stage);
                else
-               return r300_run_flat_render(ctx, stage);
+               return r300_run_vb_flat_render(ctx, stage);
    #else
        return GL_TRUE;
    #endif
diff --git a/src/mesa/drivers/dri/r300/r300_tex.c b/src/mesa/drivers/dri/r300/r300_tex.c
new file mode 100644 (file)
index 0000000..bdbdc0b
--- /dev/null
@@ -0,0 +1,1055 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r300/r300_tex.c,v 1.2 2002/11/05 17:46:08 tsi Exp $ */
+/*
+Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
+
+The Weather Channel (TM) funded Tungsten Graphics to develop the
+initial release of the Radeon 8500 driver under the XFree86 license.
+This notice must be preserved.
+
+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 (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 NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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.
+*/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "colormac.h"
+#include "context.h"
+#include "enums.h"
+#include "image.h"
+#include "simple_list.h"
+#include "texformat.h"
+#include "texstore.h"
+#include "texmem.h"
+#include "teximage.h"
+#include "texobj.h"
+
+#include "r300_context.h"
+#include "r300_state.h"
+#include "r300_ioctl.h"
+//#include "r300_swtcl.h"
+#include "r300_tex.h"
+
+#include "xmlpool.h"
+
+/**
+ * Set the texture wrap modes.
+ *
+ * \param t Texture object whose wrap modes are to be set
+ * \param swrap Wrap mode for the \a s texture coordinate
+ * \param twrap Wrap mode for the \a t texture coordinate
+ */
+
+static void r300SetTexWrap(r300TexObjPtr t, GLenum swrap, GLenum twrap,
+                          GLenum rwrap)
+{
+       GLboolean is_clamp = GL_FALSE;
+       GLboolean is_clamp_to_border = GL_FALSE;
+
+       t->filter &=
+           ~(R200_CLAMP_S_MASK | R200_CLAMP_T_MASK | R200_BORDER_MODE_D3D);
+
+       switch (swrap) {
+       case GL_REPEAT:
+               t->filter |= R200_CLAMP_S_WRAP;
+               break;
+       case GL_CLAMP:
+               t->filter |= R200_CLAMP_S_CLAMP_GL;
+               is_clamp = GL_TRUE;
+               break;
+       case GL_CLAMP_TO_EDGE:
+               t->filter |= R200_CLAMP_S_CLAMP_LAST;
+               break;
+       case GL_CLAMP_TO_BORDER:
+               t->filter |= R200_CLAMP_S_CLAMP_GL;
+               is_clamp_to_border = GL_TRUE;
+               break;
+       case GL_MIRRORED_REPEAT:
+               t->filter |= R200_CLAMP_S_MIRROR;
+               break;
+       case GL_MIRROR_CLAMP_EXT:
+               t->filter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
+               is_clamp = GL_TRUE;
+               break;
+       case GL_MIRROR_CLAMP_TO_EDGE_EXT:
+               t->filter |= R200_CLAMP_S_MIRROR_CLAMP_LAST;
+               break;
+       case GL_MIRROR_CLAMP_TO_BORDER_EXT:
+               t->filter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
+               is_clamp_to_border = GL_TRUE;
+               break;
+       default:
+               _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
+       }
+
+       switch (twrap) {
+       case GL_REPEAT:
+               t->filter |= R200_CLAMP_T_WRAP;
+               break;
+       case GL_CLAMP:
+               t->filter |= R200_CLAMP_T_CLAMP_GL;
+               is_clamp = GL_TRUE;
+               break;
+       case GL_CLAMP_TO_EDGE:
+               t->filter |= R200_CLAMP_T_CLAMP_LAST;
+               break;
+       case GL_CLAMP_TO_BORDER:
+               t->filter |= R200_CLAMP_T_CLAMP_GL | R200_BORDER_MODE_D3D;
+               is_clamp_to_border = GL_TRUE;
+               break;
+       case GL_MIRRORED_REPEAT:
+               t->filter |= R200_CLAMP_T_MIRROR;
+               break;
+       case GL_MIRROR_CLAMP_EXT:
+               t->filter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
+               is_clamp = GL_TRUE;
+               break;
+       case GL_MIRROR_CLAMP_TO_EDGE_EXT:
+               t->filter |= R200_CLAMP_T_MIRROR_CLAMP_LAST;
+               break;
+       case GL_MIRROR_CLAMP_TO_BORDER_EXT:
+               t->filter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
+               is_clamp_to_border = GL_TRUE;
+               break;
+       default:
+               _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
+       }
+
+       #if 0 /* Which field is this ? */
+       t->pp_txformat_x &= ~R200_CLAMP_Q_MASK;
+
+       switch (rwrap) {
+       case GL_REPEAT:
+               t->pp_txformat_x |= R200_CLAMP_Q_WRAP;
+               break;
+       case GL_CLAMP:
+               t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
+               is_clamp = GL_TRUE;
+               break;
+       case GL_CLAMP_TO_EDGE:
+               t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_LAST;
+               break;
+       case GL_CLAMP_TO_BORDER:
+               t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
+               is_clamp_to_border = GL_TRUE;
+               break;
+       case GL_MIRRORED_REPEAT:
+               t->pp_txformat_x |= R200_CLAMP_Q_MIRROR;
+               break;
+       case GL_MIRROR_CLAMP_EXT:
+               t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
+               is_clamp = GL_TRUE;
+               break;
+       case GL_MIRROR_CLAMP_TO_EDGE_EXT:
+               t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_LAST;
+               break;
+       case GL_MIRROR_CLAMP_TO_BORDER_EXT:
+               t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
+               is_clamp_to_border = GL_TRUE;
+               break;
+       default:
+               _mesa_problem(NULL, "bad R wrap mode in %s", __FUNCTION__);
+       }
+       #endif
+       
+       if (is_clamp_to_border) {
+               t->filter |= R200_BORDER_MODE_D3D;
+       }
+
+       t->border_fallback = (is_clamp && is_clamp_to_border);
+}
+
+static void r300SetTexMaxAnisotropy(r300TexObjPtr t, GLfloat max)
+{
+       t->filter &= ~R200_MAX_ANISO_MASK;
+
+       if (max == 1.0) {
+               t->filter |= R200_MAX_ANISO_1_TO_1;
+       } else if (max <= 2.0) {
+               t->filter |= R200_MAX_ANISO_2_TO_1;
+       } else if (max <= 4.0) {
+               t->filter |= R200_MAX_ANISO_4_TO_1;
+       } else if (max <= 8.0) {
+               t->filter |= R200_MAX_ANISO_8_TO_1;
+       } else {
+               t->filter |= R200_MAX_ANISO_16_TO_1;
+       }
+}
+
+/**
+ * Set the texture magnification and minification modes.
+ *
+ * \param t Texture whose filter modes are to be set
+ * \param minf Texture minification mode
+ * \param magf Texture magnification mode
+ */
+
+static void r300SetTexFilter(r300TexObjPtr t, GLenum minf, GLenum magf)
+{
+       GLuint anisotropy = (t->filter & R200_MAX_ANISO_MASK);
+
+       t->filter &= ~(R200_MIN_FILTER_MASK | R200_MAG_FILTER_MASK);
+       #if 0
+       t->pp_txformat_x &= ~R200_VOLUME_FILTER_MASK;
+       #endif
+       
+       if (anisotropy == R200_MAX_ANISO_1_TO_1) {
+               switch (minf) {
+               case GL_NEAREST:
+                       t->filter |= R200_MIN_FILTER_NEAREST;
+                       break;
+               case GL_LINEAR:
+                       t->filter |= R200_MIN_FILTER_LINEAR;
+                       break;
+               case GL_NEAREST_MIPMAP_NEAREST:
+                       t->filter |= R200_MIN_FILTER_NEAREST_MIP_NEAREST;
+                       break;
+               case GL_NEAREST_MIPMAP_LINEAR:
+                       t->filter |= R200_MIN_FILTER_LINEAR_MIP_NEAREST;
+                       break;
+               case GL_LINEAR_MIPMAP_NEAREST:
+                       t->filter |= R200_MIN_FILTER_NEAREST_MIP_LINEAR;
+                       break;
+               case GL_LINEAR_MIPMAP_LINEAR:
+                       t->filter |= R200_MIN_FILTER_LINEAR_MIP_LINEAR;
+                       break;
+               }
+       } else {
+               switch (minf) {
+               case GL_NEAREST:
+                       t->filter |= R200_MIN_FILTER_ANISO_NEAREST;
+                       break;
+               case GL_LINEAR:
+                       t->filter |= R200_MIN_FILTER_ANISO_LINEAR;
+                       break;
+               case GL_NEAREST_MIPMAP_NEAREST:
+               case GL_LINEAR_MIPMAP_NEAREST:
+                       t->filter |=
+                           R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
+                       break;
+               case GL_NEAREST_MIPMAP_LINEAR:
+               case GL_LINEAR_MIPMAP_LINEAR:
+                       t->filter |=
+                           R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
+                       break;
+               }
+       }
+
+       /* Note we don't have 3D mipmaps so only use the mag filter setting
+        * to set the 3D texture filter mode.
+        */
+       switch (magf) {
+       case GL_NEAREST:
+               t->filter |= R200_MAG_FILTER_NEAREST;
+               #if 0
+               t->pp_txformat_x |= R200_VOLUME_FILTER_NEAREST;
+               #endif
+               break;
+       case GL_LINEAR:
+               t->filter |= R200_MAG_FILTER_LINEAR;
+               #if 0
+               t->pp_txformat_x |= R200_VOLUME_FILTER_LINEAR;
+               #endif
+               break;
+       }
+}
+
+static void r300SetTexBorderColor(r300TexObjPtr t, GLubyte c[4])
+{
+       #if 0
+       t->pp_border_color = radeonPackColor(4, c[0], c[1], c[2], c[3]);
+       #endif
+}
+
+/**
+ * Allocate space for and load the mesa images into the texture memory block.
+ * This will happen before drawing with a new texture, or drawing with a
+ * texture after it was swapped out or teximaged again.
+ */
+
+static r300TexObjPtr r300AllocTexObj(struct gl_texture_object *texObj)
+{
+       r300TexObjPtr t;
+
+       t = CALLOC_STRUCT(r300_tex_obj);
+       texObj->DriverData = t;
+       if (t != NULL) {
+               if (RADEON_DEBUG & DEBUG_TEXTURE) {
+                       fprintf(stderr, "%s( %p, %p )\n", __FUNCTION__,
+                               (void *)texObj, (void *)t);
+               }
+
+               /* Initialize non-image-dependent parts of the state:
+                */
+               t->base.tObj = texObj;
+               t->border_fallback = GL_FALSE;
+
+               make_empty_list(&t->base);
+
+               r300SetTexWrap(t, texObj->WrapS, texObj->WrapT, texObj->WrapR);
+               r300SetTexMaxAnisotropy(t, texObj->MaxAnisotropy);
+               r300SetTexFilter(t, texObj->MinFilter, texObj->MagFilter);
+               r300SetTexBorderColor(t, texObj->_BorderChan);
+       }
+
+       return t;
+}
+
+static const struct gl_texture_format *r300ChooseTextureFormat(GLcontext * ctx,
+                                                              GLint
+                                                              internalFormat,
+                                                              GLenum format,
+                                                              GLenum type)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       const GLboolean do32bpt =
+           (rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32);
+       const GLboolean force16bpt =
+           (rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16);
+       (void)format;
+
+       switch (internalFormat) {
+       case 4:
+       case GL_RGBA:
+       case GL_COMPRESSED_RGBA:
+               switch (type) {
+               case GL_UNSIGNED_INT_10_10_10_2:
+               case GL_UNSIGNED_INT_2_10_10_10_REV:
+                       return do32bpt ? _dri_texformat_argb8888 :
+                           _dri_texformat_argb1555;
+               case GL_UNSIGNED_SHORT_4_4_4_4:
+               case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+                       return _dri_texformat_argb4444;
+               case GL_UNSIGNED_SHORT_5_5_5_1:
+               case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+                       return _dri_texformat_argb1555;
+               default:
+                       return do32bpt ? _dri_texformat_rgba8888 :
+                           _dri_texformat_argb4444;
+               }
+
+       case 3:
+       case GL_RGB:
+       case GL_COMPRESSED_RGB:
+               switch (type) {
+               case GL_UNSIGNED_SHORT_4_4_4_4:
+               case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+                       return _dri_texformat_argb4444;
+               case GL_UNSIGNED_SHORT_5_5_5_1:
+               case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+                       return _dri_texformat_argb1555;
+               case GL_UNSIGNED_SHORT_5_6_5:
+               case GL_UNSIGNED_SHORT_5_6_5_REV:
+                       return _dri_texformat_rgb565;
+               default:
+                       return do32bpt ? _dri_texformat_rgba8888 :
+                           _dri_texformat_rgb565;
+               }
+
+       case GL_RGBA8:
+       case GL_RGB10_A2:
+       case GL_RGBA12:
+       case GL_RGBA16:
+               return !force16bpt ?
+                   _dri_texformat_rgba8888 : _dri_texformat_argb4444;
+
+       case GL_RGBA4:
+       case GL_RGBA2:
+               return _dri_texformat_argb4444;
+
+       case GL_RGB5_A1:
+               return _dri_texformat_argb1555;
+
+       case GL_RGB8:
+       case GL_RGB10:
+       case GL_RGB12:
+       case GL_RGB16:
+               return !force16bpt ? _dri_texformat_rgba8888 :
+                   _dri_texformat_rgb565;
+
+       case GL_RGB5:
+       case GL_RGB4:
+       case GL_R3_G3_B2:
+               return _dri_texformat_rgb565;
+
+       case GL_ALPHA:
+       case GL_ALPHA4:
+       case GL_ALPHA8:
+       case GL_ALPHA12:
+       case GL_ALPHA16:
+       case GL_COMPRESSED_ALPHA:
+               return _dri_texformat_a8;
+
+       case 1:
+       case GL_LUMINANCE:
+       case GL_LUMINANCE4:
+       case GL_LUMINANCE8:
+       case GL_LUMINANCE12:
+       case GL_LUMINANCE16:
+       case GL_COMPRESSED_LUMINANCE:
+               return _dri_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 _dri_texformat_al88;
+
+       case GL_INTENSITY:
+       case GL_INTENSITY4:
+       case GL_INTENSITY8:
+       case GL_INTENSITY12:
+       case GL_INTENSITY16:
+       case GL_COMPRESSED_INTENSITY:
+               return _dri_texformat_i8;
+
+       case GL_YCBCR_MESA:
+               if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
+                   type == GL_UNSIGNED_BYTE)
+                       return &_mesa_texformat_ycbcr;
+               else
+                       return &_mesa_texformat_ycbcr_rev;
+
+       default:
+               _mesa_problem(ctx,
+                             "unexpected internalFormat 0x%x in r300ChooseTextureFormat",
+                             (int)internalFormat);
+               return NULL;
+       }
+
+       return NULL;            /* never get here */
+}
+
+static GLboolean
+r300ValidateClientStorage(GLcontext * ctx, 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)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+
+       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, may be different on ppc???
+        */
+       switch (internalFormat) {
+       case GL_RGBA:
+               if (format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
+                       texImage->TexFormat = _dri_texformat_argb8888;
+               } else
+                       return 0;
+               break;
+
+       case GL_RGB:
+               if (format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5) {
+                       texImage->TexFormat = _dri_texformat_rgb565;
+               } 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;
+               } else if (format == GL_YCBCR_MESA &&
+                          (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
+                           type == GL_UNSIGNED_BYTE)) {
+                       texImage->TexFormat = &_mesa_texformat_ycbcr;
+               } 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 (!r300IsGartMemory(rmesa, 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 / texImage->TexFormat->TexelBytes;
+
+               return 1;
+       }
+}
+
+static void r300TexImage1D(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;
+
+       if (t) {
+               driSwapOutTextureObject(t);
+       } else {
+               t = (driTextureObject *) r300AllocTexObj(texObj);
+               if (!t) {
+                       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
+                       return;
+               }
+       }
+
+       /* Note, this will call ChooseTextureFormat */
+       _mesa_store_teximage1d(ctx, target, level, internalFormat,
+                              width, border, format, type, pixels,
+                              &ctx->Unpack, texObj, texImage);
+
+       t->dirty_images[0] |= (1 << level);
+}
+
+static void r300TexSubImage1D(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);              /* this _should_ be true */
+       if (t) {
+               driSwapOutTextureObject(t);
+       } else {
+               t = (driTextureObject *) r300AllocTexObj(texObj);
+               if (!t) {
+                       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
+                       return;
+               }
+       }
+
+       _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
+                                 format, type, pixels, packing, texObj,
+                                 texImage);
+
+       t->dirty_images[0] |= (1 << level);
+}
+
+static void r300TexImage2D(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;
+       }
+
+       if (t != NULL) {
+               driSwapOutTextureObject(t);
+       } else {
+               t = (driTextureObject *) r300AllocTexObj(texObj);
+               if (!t) {
+                       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+                       return;
+               }
+       }
+
+       texImage->IsClientData = GL_FALSE;
+
+       if (r300ValidateClientStorage(ctx, target,
+                                     internalFormat,
+                                     width, height,
+                                     format, type, pixels,
+                                     packing, texObj, texImage)) {
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr, "%s: Using client storage\n",
+                               __FUNCTION__);
+       } else {
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr, "%s: Using normal storage\n",
+                               __FUNCTION__);
+
+               /* Normal path: copy (to cached memory) and eventually upload
+                * via another copy to GART memory and then a blit...  Could
+                * eliminate one copy by going straight to (permanent) GART.
+                *
+                * Note, this will call r300ChooseTextureFormat.
+                */
+               _mesa_store_teximage2d(ctx, target, level, internalFormat,
+                                      width, height, border, format, type,
+                                      pixels, &ctx->Unpack, texObj, texImage);
+
+               t->dirty_images[face] |= (1 << level);
+       }
+}
+
+static void r300TexSubImage2D(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;
+       }
+
+       assert(t);              /* this _should_ be true */
+       if (t) {
+               driSwapOutTextureObject(t);
+       } else {
+               t = (driTextureObject *) r300AllocTexObj(texObj);
+               if (!t) {
+                       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
+                       return;
+               }
+       }
+
+       _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
+                                 height, format, type, pixels, packing, texObj,
+                                 texImage);
+
+       t->dirty_images[face] |= (1 << level);
+}
+
+#if ENABLE_HW_3D_TEXTURE
+static void r300TexImage3D(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;
+
+       if (t) {
+               driSwapOutTextureObject(t);
+       } else {
+               t = (driTextureObject *) r300AllocTexObj(texObj);
+               if (!t) {
+                       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
+                       return;
+               }
+       }
+
+       texImage->IsClientData = GL_FALSE;
+
+#if 0
+       if (r300ValidateClientStorage(ctx, target,
+                                     internalFormat,
+                                     width, height,
+                                     format, type, pixels,
+                                     packing, texObj, texImage)) {
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr, "%s: Using client storage\n",
+                               __FUNCTION__);
+       } else
+#endif
+       {
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr, "%s: Using normal storage\n",
+                               __FUNCTION__);
+
+               /* Normal path: copy (to cached memory) and eventually upload
+                * via another copy to GART memory and then a blit...  Could
+                * eliminate one copy by going straight to (permanent) GART.
+                *
+                * Note, this will call r300ChooseTextureFormat.
+                */
+               _mesa_store_teximage3d(ctx, target, level, internalFormat,
+                                      width, height, depth, border,
+                                      format, type, pixels,
+                                      &ctx->Unpack, texObj, texImage);
+
+               t->dirty_images[0] |= (1 << level);
+       }
+}
+#endif
+
+#if ENABLE_HW_3D_TEXTURE
+static void
+r300TexSubImage3D(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;
+
+/*     fprintf(stderr, "%s\n", __FUNCTION__); */
+
+       assert(t);              /* this _should_ be true */
+       if (t) {
+               driSwapOutTextureObject(t);
+       } else {
+               t = (driTextureObject *) r300AllocTexObj(texObj);
+               if (!t) {
+                       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage3D");
+                       return;
+               }
+               texObj->DriverData = 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);
+}
+#endif
+
+static void r300TexEnv(GLcontext * ctx, GLenum target,
+                      GLenum pname, const GLfloat * param)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       GLuint unit = ctx->Texture.CurrentUnit;
+       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+       if (RADEON_DEBUG & DEBUG_STATE) {
+               fprintf(stderr, "%s( %s )\n",
+                       __FUNCTION__, _mesa_lookup_enum_by_nr(pname));
+       }
+
+       fprintf(stderr, "%s:%s I am broken - Fixme !\n", __FILE__, __FUNCTION__);
+       
+       #if 0
+       /* This is incorrect: Need to maintain this data for each of
+        * GL_TEXTURE_{123}D, GL_TEXTURE_RECTANGLE_NV, etc, and switch
+        * between them according to _ReallyEnabled.
+        */
+       switch (pname) {
+       case GL_TEXTURE_ENV_COLOR:{
+                       GLubyte c[4];
+                       GLuint envColor;
+                       UNCLAMPED_FLOAT_TO_RGBA_CHAN(c, texUnit->EnvColor);
+                       envColor = radeonPackColor(4, c[0], c[1], c[2], c[3]);
+                       if (rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] != envColor) {
+                               R200_STATECHANGE(rmesa, tf);
+                               rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] =
+                                   envColor;
+                       }
+                       break;
+               }
+
+       case GL_TEXTURE_LOD_BIAS_EXT:{
+                       GLfloat bias, min;
+                       GLuint b;
+                       const int fixed_one = 0x8000000;
+
+                       /* The R200's LOD bias is a signed 2's complement value with a
+                        * range of -16.0 <= bias < 16.0.
+                        *
+                        * NOTE: Add a small bias to the bias for conform mipsel.c test.
+                        */
+                       bias = *param + .01;
+                       min =
+                           driQueryOptionb(&rmesa->radeon.optionCache,
+                                           "no_neg_lod_bias") ? 0.0 : -16.0;
+                       bias = CLAMP(bias, min, 16.0);
+                       b = (int)(bias * fixed_one) & R200_LOD_BIAS_MASK;
+
+                       if ((rmesa->hw.tex[unit].
+                            cmd[TEX_PP_TXFORMAT_X] & R200_LOD_BIAS_MASK) !=
+                           b) {
+                               R200_STATECHANGE(rmesa, tex[unit]);
+                               rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] &=
+                                   ~R200_LOD_BIAS_MASK;
+                               rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] |= b;
+                       }
+                       break;
+               }
+
+       default:
+               return;
+       }
+       #endif
+}
+
+/**
+ * Changes variables and flags for a state update, which will happen at the
+ * next UpdateTextureState
+ */
+
+static void r300TexParameter(GLcontext * ctx, GLenum target,
+                            struct gl_texture_object *texObj,
+                            GLenum pname, const GLfloat * params)
+{
+       r300TexObjPtr t = (r300TexObjPtr) texObj->DriverData;
+
+       if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) {
+               fprintf(stderr, "%s( %s )\n", __FUNCTION__,
+                       _mesa_lookup_enum_by_nr(pname));
+       }
+
+       switch (pname) {
+       case GL_TEXTURE_MIN_FILTER:
+       case GL_TEXTURE_MAG_FILTER:
+       case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+               r300SetTexMaxAnisotropy(t, texObj->MaxAnisotropy);
+               r300SetTexFilter(t, texObj->MinFilter, texObj->MagFilter);
+               break;
+
+       case GL_TEXTURE_WRAP_S:
+       case GL_TEXTURE_WRAP_T:
+       case GL_TEXTURE_WRAP_R:
+               r300SetTexWrap(t, texObj->WrapS, texObj->WrapT, texObj->WrapR);
+               break;
+
+       case GL_TEXTURE_BORDER_COLOR:
+               r300SetTexBorderColor(t, texObj->_BorderChan);
+               break;
+
+       case GL_TEXTURE_BASE_LEVEL:
+       case GL_TEXTURE_MAX_LEVEL:
+       case GL_TEXTURE_MIN_LOD:
+       case GL_TEXTURE_MAX_LOD:
+               /* This isn't the most efficient solution but there doesn't appear to
+                * be a nice alternative.  Since there's no LOD clamping,
+                * we just have to rely on loading the right subset of mipmap levels
+                * to simulate a clamped LOD.
+                */
+               driSwapOutTextureObject((driTextureObject *) t);
+               break;
+
+       default:
+               return;
+       }
+
+       /* Mark this texobj as dirty (one bit per tex unit)
+        */
+       t->dirty_state = TEX_ALL;
+}
+
+static void r300BindTexture(GLcontext * ctx, GLenum target,
+                           struct gl_texture_object *texObj)
+{
+       if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) {
+               fprintf(stderr, "%s( %p ) unit=%d\n", __FUNCTION__,
+                       (void *)texObj, ctx->Texture.CurrentUnit);
+       }
+
+       if ((target == GL_TEXTURE_1D)
+           || (target == GL_TEXTURE_2D)
+#if ENABLE_HW_3D_TEXTURE
+           || (target == GL_TEXTURE_3D)
+#endif
+           || (target == GL_TEXTURE_CUBE_MAP)
+           || (target == GL_TEXTURE_RECTANGLE_NV)) {
+               assert(texObj->DriverData != NULL);
+       }
+}
+
+static void r300DeleteTexture(GLcontext * ctx, struct gl_texture_object *texObj)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       driTextureObject *t = (driTextureObject *) texObj->DriverData;
+
+       if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) {
+               fprintf(stderr, "%s( %p (target = %s) )\n", __FUNCTION__,
+                       (void *)texObj,
+                       _mesa_lookup_enum_by_nr(texObj->Target));
+       }
+
+       if (t != NULL) {
+               if (rmesa) {
+                       R300_FIREVERTICES(rmesa);
+               }
+
+               driDestroyTextureObject(t);
+       }
+       /* Free mipmap images and the texture object itself */
+       _mesa_delete_texture_object(ctx, texObj);
+}
+
+/* Need:
+ *  - Same GEN_MODE for all active bits
+ *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
+ *  - STRQ presumably all supported (matrix means incoming R values
+ *    can end up in STQ, this has implications for vertex support,
+ *    presumably ok if maos is used, though?)
+ *
+ * Basically impossible to do this on the fly - just collect some
+ * basic info & do the checks from ValidateState().
+ */
+static void r300TexGen(GLcontext * ctx,
+                      GLenum coord, GLenum pname, const GLfloat * params)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       GLuint unit = ctx->Texture.CurrentUnit;
+       #if 0 /* Disable this for now - looks like we will be recalculating everything
+                anyway */
+       rmesa->recheck_texgen[unit] = GL_TRUE;
+       #endif
+}
+
+/**
+ * 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.
+ * Fixup MaxAnisotropy according to user preference.
+ */
+static struct gl_texture_object *r300NewTextureObject(GLcontext * ctx,
+                                                     GLuint name,
+                                                     GLenum target)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct gl_texture_object *obj;
+       obj = _mesa_new_texture_object(ctx, name, target);
+       if (!obj)
+               return NULL;
+       obj->MaxAnisotropy = rmesa->initialMaxAnisotropy;
+       r300AllocTexObj(obj);
+       return obj;
+}
+
+void r300InitTextureFuncs(struct dd_function_table *functions)
+{
+       /* Note: we only plug in the functions we implement in the driver
+        * since _mesa_init_driver_functions() was already called.
+        */
+       functions->ChooseTextureFormat = r300ChooseTextureFormat;
+       functions->TexImage1D = r300TexImage1D;
+       functions->TexImage2D = r300TexImage2D;
+#if ENABLE_HW_3D_TEXTURE
+       functions->TexImage3D = r300TexImage3D;
+#else
+       functions->TexImage3D = _mesa_store_teximage3d;
+#endif
+       functions->TexSubImage1D = r300TexSubImage1D;
+       functions->TexSubImage2D = r300TexSubImage2D;
+#if ENABLE_HW_3D_TEXTURE
+       functions->TexSubImage3D = r300TexSubImage3D;
+#else
+       functions->TexSubImage3D = _mesa_store_texsubimage3d;
+#endif
+       functions->NewTextureObject = r300NewTextureObject;
+       functions->BindTexture = r300BindTexture;
+       functions->DeleteTexture = r300DeleteTexture;
+       functions->IsTextureResident = driIsTextureResident;
+
+       functions->TexEnv = r300TexEnv;
+       functions->TexParameter = r300TexParameter;
+       functions->TexGen = r300TexGen;
+
+       driInitTextureFormats();
+
+#if 000
+       /* moved or obsolete code */
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       driInitTextureObjects(ctx, &rmesa->swapped,
+                             DRI_TEXMGR_DO_TEXTURE_1D
+                             | DRI_TEXMGR_DO_TEXTURE_2D);
+
+       /* Hack: r300NewTextureObject is not yet installed when the
+        * default textures are created. Therefore set MaxAnisotropy of the
+        * default 2D texture now. */
+       ctx->Shared->Default2D->MaxAnisotropy =
+           driQueryOptionf(&rmesa->optionCache, "def_max_anisotropy");
+#endif
+}
diff --git a/src/mesa/drivers/dri/r300/r300_tex.h b/src/mesa/drivers/dri/r300/r300_tex.h
new file mode 100644 (file)
index 0000000..a18ff0e
--- /dev/null
@@ -0,0 +1,51 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r300/r300_tex.h,v 1.1 2002/10/30 12:51:53 alanh Exp $ */
+/*
+Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
+
+The Weather Channel (TM) funded Tungsten Graphics to develop the
+initial release of the Radeon 8500 driver under the XFree86 license.
+This notice must be preserved.
+
+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 (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 NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#ifndef __r300_TEX_H__
+#define __r300_TEX_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+extern void r300UpdateTextureState(GLcontext * ctx);
+
+extern int r300UploadTexImages(r300ContextPtr rmesa, r300TexObjPtr t,
+                              GLuint face);
+
+extern void r300DestroyTexObj(r300ContextPtr rmesa, r300TexObjPtr t);
+
+extern void r300InitTextureFuncs(struct dd_function_table *functions);
+
+#endif
+#endif                         /* __r300_TEX_H__ */
diff --git a/src/mesa/drivers/dri/r300/r300_texmem.c b/src/mesa/drivers/dri/r300/r300_texmem.c
new file mode 100644 (file)
index 0000000..78c077f
--- /dev/null
@@ -0,0 +1,490 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r300/r300_texmem.c,v 1.5 2002/12/17 00:32:56 dawes Exp $ */
+/**************************************************************************
+
+Copyright (C) Tungsten Graphics 2002.  All Rights Reserved.
+The Weather Channel, Inc. funded Tungsten Graphics to develop the
+initial release of the Radeon 8500 driver under the XFree86
+license. This notice must be preserved.
+
+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 on 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 ATI, VA LINUX SYSTEMS AND/OR THEIR
+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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Kevin E. Martin <martin@valinux.com>
+ *   Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include <errno.h>
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "colormac.h"
+#include "macros.h"
+#include "simple_list.h"
+#include "radeon_reg.h"                /* gets definition for usleep */
+#include "r300_context.h"
+#include "r300_state.h"
+#include "radeon_ioctl.h"
+/*
+#include "r300_swtcl.h"
+*/
+#include "r300_tex.h"
+
+#include <unistd.h>            /* for usleep() */
+
+/**
+ * Destroy any device-dependent state associated with the texture.  This may
+ * include NULLing out hardware state that points to the texture.
+ */
+void r300DestroyTexObj(r300ContextPtr rmesa, r300TexObjPtr t)
+{
+       if (RADEON_DEBUG & DEBUG_TEXTURE) {
+               fprintf(stderr, "%s( %p, %p )\n", __FUNCTION__,
+                       (void *)t, (void *)t->base.tObj);
+       }
+
+       if (rmesa != NULL) {
+               unsigned i;
+
+               for (i = 0; i < rmesa->radeon.glCtx->Const.MaxTextureUnits; i++) {
+                       if (t == rmesa->state.texture.unit[i].texobj) {
+                               rmesa->state.texture.unit[i].texobj = NULL;
+                               /* This code below is meant to shorten state
+                                  pushed to the hardware by not programming 
+                                  unneeded units.
+                                  
+                                  This does not appear to be worthwhile on R300 */
+                               #if 0
+                               remove_from_list(&rmesa->hw.tex[i]);
+                               make_empty_list(&rmesa->hw.tex[i]);
+                               remove_from_list(&rmesa->hw.cube[i]);
+                               make_empty_list(&rmesa->hw.cube[i]);
+                               #endif
+                       }
+               }
+       }
+}
+
+/* ------------------------------------------------------------
+ * Texture image conversions
+ */
+
+static void r300UploadGARTClientSubImage(r300ContextPtr rmesa,
+                                        r300TexObjPtr t,
+                                        struct gl_texture_image *texImage,
+                                        GLint hwlevel,
+                                        GLint x, GLint y,
+                                        GLint width, GLint height)
+{
+       const struct gl_texture_format *texFormat = texImage->TexFormat;
+       GLuint srcPitch, dstPitch;
+       int blit_format;
+       int srcOffset;
+
+       /*
+        * XXX it appears that we always upload the full image, not a subimage.
+        * I.e. x==0, y==0, width=texWidth, height=texWidth.  If this is ever
+        * changed, the src pitch will have to change.
+        */
+       switch (texFormat->TexelBytes) {
+       case 1:
+               blit_format = R200_CP_COLOR_FORMAT_CI8;
+               srcPitch = t->image[0][0].width * texFormat->TexelBytes;
+               dstPitch = t->image[0][0].width * texFormat->TexelBytes;
+               break;
+       case 2:
+               blit_format = R200_CP_COLOR_FORMAT_RGB565;
+               srcPitch = t->image[0][0].width * texFormat->TexelBytes;
+               dstPitch = t->image[0][0].width * texFormat->TexelBytes;
+               break;
+       case 4:
+               blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
+               srcPitch = t->image[0][0].width * texFormat->TexelBytes;
+               dstPitch = t->image[0][0].width * texFormat->TexelBytes;
+               break;
+       default:
+               return;
+       }
+
+       t->image[0][hwlevel].data = texImage->Data;
+       srcOffset = r300GartOffsetFromVirtual(rmesa, texImage->Data);
+
+       assert(srcOffset != ~0);
+
+       /* Don't currently need to cope with small pitches?
+        */
+       width = texImage->Width;
+       height = texImage->Height;
+
+       r300EmitWait(rmesa, RADEON_WAIT_3D);
+
+       r300EmitBlit(rmesa, blit_format,
+                    srcPitch,
+                    srcOffset,
+                    dstPitch,
+                    t->bufAddr,
+                    x,
+                    y,
+                    t->image[0][hwlevel].x + x,
+                    t->image[0][hwlevel].y + y, width, height);
+
+       r300EmitWait(rmesa, RADEON_WAIT_2D);
+}
+
+static void r300UploadRectSubImage(r300ContextPtr rmesa,
+                                  r300TexObjPtr t,
+                                  struct gl_texture_image *texImage,
+                                  GLint x, GLint y, GLint width, GLint height)
+{
+       const struct gl_texture_format *texFormat = texImage->TexFormat;
+       int blit_format, dstPitch, done;
+
+       switch (texFormat->TexelBytes) {
+       case 1:
+               blit_format = R200_CP_COLOR_FORMAT_CI8;
+               break;
+       case 2:
+               blit_format = R200_CP_COLOR_FORMAT_RGB565;
+               break;
+       case 4:
+               blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
+               break;
+       default:
+               return;
+       }
+
+       t->image[0][0].data = texImage->Data;
+
+       /* Currently don't need to cope with small pitches.
+        */
+       width = texImage->Width;
+       height = texImage->Height;
+       dstPitch = t->pitch + 32;
+
+       if (rmesa->prefer_gart_client_texturing && texImage->IsClientData) {
+               /* In this case, could also use GART texturing.  This is
+                * currently disabled, but has been tested & works.
+                */
+               t->offset =
+                   r300GartOffsetFromVirtual(rmesa, texImage->Data);
+               t->pitch =
+                   texImage->RowStride * texFormat->TexelBytes - 32;
+
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr,
+                               "Using GART texturing for rectangular client texture\n");
+
+               /* Release FB memory allocated for this image:
+                */
+               /* FIXME This may not be correct as driSwapOutTextureObject sets
+                * FIXME dirty_images.  It may be fine, though.
+                */
+               if (t->base.memBlock) {
+                       driSwapOutTextureObject((driTextureObject *) t);
+               }
+       } else if (texImage->IsClientData) {
+               /* Data already in GART memory, with usable pitch.
+                */
+               GLuint srcPitch;
+               srcPitch = texImage->RowStride * texFormat->TexelBytes;
+               r300EmitBlit(rmesa,
+                            blit_format,
+                            srcPitch,
+                            r300GartOffsetFromVirtual(rmesa, texImage->Data),
+                            dstPitch, t->bufAddr, 0, 0, 0, 0, width, height);
+       } else {
+               /* Data not in GART memory, or bad pitch.
+                */
+               for (done = 0; done < height;) {
+                       struct r300_dma_region region;
+                       int lines =
+                           MIN2(height - done, RADEON_BUFFER_SIZE / dstPitch);
+                       int src_pitch;
+                       char *tex;
+
+                       src_pitch = texImage->RowStride * texFormat->TexelBytes;
+
+                       tex = (char *)texImage->Data + done * src_pitch;
+
+                       memset(&region, 0, sizeof(region));
+                       r300AllocDmaRegion(rmesa, &region, lines * dstPitch,
+                                          1024);
+
+                       /* Copy texdata to dma:
+                        */
+                       if (0)
+                               fprintf(stderr,
+                                       "%s: src_pitch %d dst_pitch %d\n",
+                                       __FUNCTION__, src_pitch, dstPitch);
+
+                       if (src_pitch == dstPitch) {
+                               memcpy(region.address + region.start, tex,
+                                      lines * src_pitch);
+                       } else {
+                               char *buf = region.address + region.start;
+                               int i;
+                               for (i = 0; i < lines; i++) {
+                                       memcpy(buf, tex, src_pitch);
+                                       buf += dstPitch;
+                                       tex += src_pitch;
+                               }
+                       }
+
+                       r300EmitWait(rmesa, RADEON_WAIT_3D);
+
+                       /* Blit to framebuffer
+                        */
+                       r300EmitBlit(rmesa,
+                                    blit_format,
+                                    dstPitch, GET_START(&region),
+                                    dstPitch, t->bufAddr,
+                                    0, 0, 0, done, width, lines);
+
+                       r300EmitWait(rmesa, RADEON_WAIT_2D);
+
+                       r300ReleaseDmaRegion(rmesa, &region, __FUNCTION__);
+                       done += lines;
+               }
+       }
+}
+
+/**
+ * Upload the texture image associated with texture \a t at the specified
+ * level at the address relative to \a start.
+ */
+static void uploadSubImage(r300ContextPtr rmesa, r300TexObjPtr t,
+                          GLint hwlevel,
+                          GLint x, GLint y, GLint width, GLint height,
+                          GLuint face)
+{
+       struct gl_texture_image *texImage = NULL;
+       GLuint offset;
+       GLint imageWidth, imageHeight;
+       GLint ret;
+       drm_radeon_texture_t tex;
+       drm_radeon_tex_image_t tmp;
+       const int level = hwlevel + t->base.firstLevel;
+
+       if (RADEON_DEBUG & DEBUG_TEXTURE) {
+               fprintf(stderr,
+                       "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n",
+                       __FUNCTION__, (void *)t, (void *)t->base.tObj, level,
+                       width, height, face);
+       }
+
+       ASSERT(face < 6);
+
+       /* Ensure we have a valid texture to upload */
+       if ((hwlevel < 0) || (hwlevel >= RADEON_MAX_TEXTURE_LEVELS)) {
+               _mesa_problem(NULL, "bad texture level in %s", __FUNCTION__);
+               return;
+       }
+
+       texImage = t->base.tObj->Image[face][level];
+
+       if (!texImage) {
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr, "%s: texImage %d is NULL!\n",
+                               __FUNCTION__, level);
+               return;
+       }
+       if (!texImage->Data) {
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr, "%s: image data is NULL!\n",
+                               __FUNCTION__);
+               return;
+       }
+
+       if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
+               assert(level == 0);
+               assert(hwlevel == 0);
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr, "%s: image data is rectangular\n",
+                               __FUNCTION__);
+               r300UploadRectSubImage(rmesa, t, texImage, x, y, width, height);
+               return;
+       } else if (texImage->IsClientData) {
+               if (RADEON_DEBUG & DEBUG_TEXTURE)
+                       fprintf(stderr,
+                               "%s: image data is in GART client storage\n",
+                               __FUNCTION__);
+               r300UploadGARTClientSubImage(rmesa, t, texImage, hwlevel, x, y,
+                                            width, height);
+               return;
+       } else if (RADEON_DEBUG & DEBUG_TEXTURE)
+               fprintf(stderr, "%s: image data is in normal memory\n",
+                       __FUNCTION__);
+
+       imageWidth = texImage->Width;
+       imageHeight = texImage->Height;
+
+       offset = t->bufAddr;
+
+       if (RADEON_DEBUG & (DEBUG_TEXTURE | DEBUG_IOCTL)) {
+               GLint imageX = 0;
+               GLint imageY = 0;
+               GLint blitX = t->image[face][hwlevel].x;
+               GLint blitY = t->image[face][hwlevel].y;
+               GLint blitWidth = t->image[face][hwlevel].width;
+               GLint blitHeight = t->image[face][hwlevel].height;
+               fprintf(stderr, "   upload image: %d,%d at %d,%d\n",
+                       imageWidth, imageHeight, imageX, imageY);
+               fprintf(stderr, "   upload  blit: %d,%d at %d,%d\n",
+                       blitWidth, blitHeight, blitX, blitY);
+               fprintf(stderr, "       blit ofs: 0x%07x level: %d/%d\n",
+                       (GLuint) offset, hwlevel, level);
+       }
+
+       t->image[face][hwlevel].data = texImage->Data;
+
+       /* Init the DRM_RADEON_TEXTURE command / drm_radeon_texture_t struct.
+        * NOTE: we're always use a 1KB-wide blit and I8 texture format.
+        * We used to use 1, 2 and 4-byte texels and used to use the texture
+        * width to dictate the blit width - but that won't work for compressed
+        * textures. (Brian)
+        */
+       tex.offset = offset;
+       tex.pitch = BLIT_WIDTH_BYTES / 64;
+       tex.format = R200_TXFORMAT_I8;  /* any 1-byte texel format */
+       if (texImage->TexFormat->TexelBytes) {
+               tex.width = imageWidth * texImage->TexFormat->TexelBytes;       /* in bytes */
+               tex.height = imageHeight;
+       } else {
+               tex.width = imageWidth; /* compressed */
+               tex.height = imageHeight;
+               if (tex.height < 4)
+                       tex.height = 4;
+       }
+       tex.image = &tmp;
+
+       /* copy (x,y,width,height,data) */
+       memcpy(&tmp, &t->image[face][hwlevel], sizeof(tmp));
+
+       LOCK_HARDWARE(&rmesa->radeon);
+       do {
+               ret = drmCommandWriteRead(rmesa->radeon.dri.fd, DRM_RADEON_TEXTURE,
+                                         &tex, sizeof(drm_radeon_texture_t));
+               if (ret) {
+                       if (RADEON_DEBUG & DEBUG_IOCTL)
+                               fprintf(stderr,
+                                       "DRM_RADEON_TEXTURE:  again!\n");
+                       usleep(1);
+               }
+       } while (ret && errno == EAGAIN);
+
+       UNLOCK_HARDWARE(&rmesa->radeon);
+
+       if (ret) {
+               fprintf(stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret);
+               fprintf(stderr, "   offset=0x%08x\n", offset);
+               fprintf(stderr, "   image width=%d height=%d\n",
+                       imageWidth, imageHeight);
+               fprintf(stderr, "    blit width=%d height=%d data=%p\n",
+                       t->image[face][hwlevel].width,
+                       t->image[face][hwlevel].height,
+                       t->image[face][hwlevel].data);
+               exit(1);
+       }
+}
+
+/**
+ * Upload the texture images associated with texture \a t.  This might
+ * require the allocation of texture memory.
+ *
+ * \param rmesa Context pointer
+ * \param t Texture to be uploaded
+ * \param face Cube map face to be uploaded.  Zero for non-cube maps.
+ */
+
+int r300UploadTexImages(r300ContextPtr rmesa, r300TexObjPtr t, GLuint face)
+{
+       const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
+
+       if (RADEON_DEBUG & (DEBUG_TEXTURE | DEBUG_IOCTL)) {
+               fprintf(stderr, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__,
+                       (void *)rmesa->radeon.glCtx, (void *)t->base.tObj,
+                       t->base.totalSize, t->base.firstLevel,
+                       t->base.lastLevel);
+       }
+
+       if (!t || t->base.totalSize == 0)
+               return 0;
+
+       if (RADEON_DEBUG & DEBUG_SYNC) {
+               fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
+               radeonFinish(rmesa->radeon.glCtx);
+       }
+
+       LOCK_HARDWARE(&rmesa->radeon);
+
+       if (t->base.memBlock == NULL) {
+               int heap;
+
+               heap = driAllocateTexture(rmesa->texture_heaps, rmesa->nr_heaps,
+                                         (driTextureObject *) t);
+               if (heap == -1) {
+                       UNLOCK_HARDWARE(&rmesa->radeon);
+                       return -1;
+               }
+
+               /* Set the base offset of the texture image */
+               t->bufAddr = rmesa->radeon.radeonScreen->texOffset[heap]
+                   + t->base.memBlock->ofs;
+               t->offset = t->bufAddr;
+
+               /* Mark this texobj as dirty on all units:
+                */
+               t->dirty_state = TEX_ALL;
+       }
+
+       /* Let the world know we've used this memory recently.
+        */
+       driUpdateTextureLRU((driTextureObject *) t);
+       UNLOCK_HARDWARE(&rmesa->radeon);
+
+       /* Upload any images that are new */
+       if (t->base.dirty_images[face]) {
+               int i;
+               for (i = 0; i < numLevels; i++) {
+                       if ((t->base.
+                            dirty_images[face] & (1 <<
+                                                  (i + t->base.firstLevel))) !=
+                           0) {
+                               uploadSubImage(rmesa, t, i, 0, 0,
+                                              t->image[face][i].width,
+                                              t->image[face][i].height, face);
+                       }
+               }
+               t->base.dirty_images[face] = 0;
+       }
+
+       if (RADEON_DEBUG & DEBUG_SYNC) {
+               fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
+               radeonFinish(rmesa->radeon.glCtx);
+       }
+
+       return 0;
+}
diff --git a/src/mesa/drivers/dri/r300/r300_texstate.c b/src/mesa/drivers/dri/r300/r300_texstate.c
new file mode 100644 (file)
index 0000000..6962bb3
--- /dev/null
@@ -0,0 +1,1390 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r300/r300_texstate.c,v 1.3 2003/02/15 22:18:47 dawes Exp $ */
+/*
+Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
+
+The Weather Channel (TM) funded Tungsten Graphics to develop the
+initial release of the Radeon 8500 driver under the XFree86 license.
+This notice must be preserved.
+
+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 (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 NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "macros.h"
+#include "texformat.h"
+#include "enums.h"
+
+#include "r300_context.h"
+#include "r300_state.h"
+#include "radeon_ioctl.h"
+//#include "r300_swtcl.h"
+#include "r300_tex.h"
+//#include "r300_tcl.h"
+
+#define R200_TXFORMAT_A8        R200_TXFORMAT_I8
+#define R200_TXFORMAT_L8        R200_TXFORMAT_I8
+#define R200_TXFORMAT_AL88      R200_TXFORMAT_AI88
+#define R200_TXFORMAT_YCBCR     R200_TXFORMAT_YVYU422
+#define R200_TXFORMAT_YCBCR_REV R200_TXFORMAT_VYUY422
+
+#define _COLOR(f) \
+    [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, 0 }
+#define _COLOR_REV(f) \
+    [ MESA_FORMAT_ ## f ## _REV ] = { R200_TXFORMAT_ ## f, 0 }
+#define _ALPHA(f) \
+    [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f | R200_TXFORMAT_ALPHA_IN_MAP, 0 }
+#define _ALPHA_REV(f) \
+    [ MESA_FORMAT_ ## f ## _REV ] = { R200_TXFORMAT_ ## f | R200_TXFORMAT_ALPHA_IN_MAP, 0 }
+#define _YUV(f) \
+    [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, R200_YUV_TO_RGB }
+#define _INVALID(f) \
+    [ MESA_FORMAT_ ## f ] = { 0xffffffff, 0 }
+#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_YCBCR_REV) \
+                            && (tx_table[f].format != 0xffffffff) )
+
+static const struct {
+       GLuint format, filter;
+} tx_table[] = {
+_ALPHA(RGBA8888),
+           _ALPHA_REV(RGBA8888),
+           _ALPHA(ARGB8888),
+           _ALPHA_REV(ARGB8888),
+           _INVALID(RGB888),
+           _COLOR(RGB565),
+           _COLOR_REV(RGB565),
+           _ALPHA(ARGB4444),
+           _ALPHA_REV(ARGB4444),
+           _ALPHA(ARGB1555),
+           _ALPHA_REV(ARGB1555),
+           _ALPHA(AL88),
+           _ALPHA_REV(AL88),
+           _ALPHA(A8),
+           _COLOR(L8),
+           _ALPHA(I8), _INVALID(CI8), _YUV(YCBCR), _YUV(YCBCR_REV),};
+
+#undef _COLOR
+#undef _ALPHA
+#undef _INVALID
+
+/**
+ * This function computes the number of bytes of storage needed for
+ * the given texture object (all mipmap levels, all cube faces).
+ * The \c image[face][level].x/y/width/height parameters for upload/blitting
+ * are computed here.  \c filter, \c format, etc. will be set here
+ * too.
+ *
+ * \param rmesa Context pointer
+ * \param tObj GL texture object whose images are to be posted to
+ *                 hardware state.
+ */
+static void r300SetTexImages(r300ContextPtr rmesa,
+                            struct gl_texture_object *tObj)
+{
+       r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData;
+       const struct gl_texture_image *baseImage =
+           tObj->Image[0][tObj->BaseLevel];
+       GLint curOffset;
+       GLint i;
+       GLint numLevels;
+       GLint log2Width, log2Height, log2Depth;
+
+       /* Set the hardware texture format
+        */
+
+       t->format &= ~(R200_TXFORMAT_FORMAT_MASK |
+                           R200_TXFORMAT_ALPHA_IN_MAP);
+       t->filter &= ~R200_YUV_TO_RGB;
+
+       if (VALID_FORMAT(baseImage->TexFormat->MesaFormat)) {
+               t->format |=
+                   tx_table[baseImage->TexFormat->MesaFormat].format;
+               t->filter |=
+                   tx_table[baseImage->TexFormat->MesaFormat].filter;
+       } else {
+               _mesa_problem(NULL, "unexpected texture format in %s",
+                             __FUNCTION__);
+               return;
+       }
+
+       /* Compute which mipmap levels we really want to send to the hardware.
+        */
+
+       driCalculateTextureFirstLastLevel((driTextureObject *) t);
+       log2Width = tObj->Image[0][t->base.firstLevel]->WidthLog2;
+       log2Height = tObj->Image[0][t->base.firstLevel]->HeightLog2;
+       log2Depth = tObj->Image[0][t->base.firstLevel]->DepthLog2;
+
+       numLevels = t->base.lastLevel - t->base.firstLevel + 1;
+
+       assert(numLevels <= RADEON_MAX_TEXTURE_LEVELS);
+
+       /* Calculate mipmap offsets and dimensions for blitting (uploading)
+        * The idea is that we lay out the mipmap levels within a block of
+        * memory organized as a rectangle of width BLIT_WIDTH_BYTES.
+        */
+       curOffset = 0;
+
+       for (i = 0; i < numLevels; i++) {
+               const struct gl_texture_image *texImage;
+               GLuint size;
+
+               texImage = tObj->Image[0][i + t->base.firstLevel];
+               if (!texImage)
+                       break;
+
+               /* find image size in bytes */
+               if (texImage->IsCompressed) {
+                       size = texImage->CompressedSize;
+               } else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
+                       size =
+                           ((texImage->Width *
+                             texImage->TexFormat->TexelBytes + 63)
+                            & ~63) * texImage->Height;
+               } else {
+                       int w =
+                           texImage->Width * texImage->TexFormat->TexelBytes;
+                       if (w < 32)
+                               w = 32;
+                       size = w * texImage->Height * texImage->Depth;
+               }
+               assert(size > 0);
+
+               /* Align to 32-byte offset.  It is faster to do this unconditionally
+                * (no branch penalty).
+                */
+
+               curOffset = (curOffset + 0x1f) & ~0x1f;
+
+               t->image[0][i].x = curOffset % BLIT_WIDTH_BYTES;
+               t->image[0][i].y = curOffset / BLIT_WIDTH_BYTES;
+               t->image[0][i].width = MIN2(size, BLIT_WIDTH_BYTES);
+               t->image[0][i].height = size / t->image[0][i].width;
+
+#if 0
+               /* for debugging only and only  applicable to non-rectangle targets */
+               assert(size % t->image[0][i].width == 0);
+               assert(t->image[0][i].x == 0
+                      || (size < BLIT_WIDTH_BYTES
+                          && t->image[0][i].height == 1));
+#endif
+
+               if (0)
+                       fprintf(stderr,
+                               "level %d: %dx%d x=%d y=%d w=%d h=%d size=%d at %d\n",
+                               i, texImage->Width, texImage->Height,
+                               t->image[0][i].x, t->image[0][i].y,
+                               t->image[0][i].width, t->image[0][i].height,
+                               size, curOffset);
+
+               curOffset += size;
+
+       }
+
+       /* Align the total size of texture memory block.
+        */
+       t->base.totalSize =
+           (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
+
+       /* Setup remaining cube face blits, if needed */
+       if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
+               /* Round totalSize up to multiple of BLIT_WIDTH_BYTES */
+               const GLuint faceSize =
+                   (t->base.totalSize + BLIT_WIDTH_BYTES - 1)
+                   & ~(BLIT_WIDTH_BYTES - 1);
+               const GLuint lines = faceSize / BLIT_WIDTH_BYTES;
+               GLuint face;
+               /* reuse face 0 x/y/width/height - just adjust y */
+               for (face = 1; face < 6; face++) {
+                       for (i = 0; i < numLevels; i++) {
+                               t->image[face][i].x = t->image[0][i].x;
+                               t->image[face][i].y =
+                                   t->image[0][i].y + face * lines;
+                               t->image[face][i].width = t->image[0][i].width;
+                               t->image[face][i].height =
+                                   t->image[0][i].height;
+                       }
+               }
+               t->base.totalSize = 6 * faceSize;       /* total texmem needed */
+       }
+
+       /* Hardware state:
+        */
+       t->filter &= ~R200_MAX_MIP_LEVEL_MASK;
+       t->filter |= (numLevels - 1) << R200_MAX_MIP_LEVEL_SHIFT;
+
+       t->format &= ~(R200_TXFORMAT_WIDTH_MASK |
+                           R200_TXFORMAT_HEIGHT_MASK |
+                           R200_TXFORMAT_CUBIC_MAP_ENABLE |
+                           R200_TXFORMAT_F5_WIDTH_MASK |
+                           R200_TXFORMAT_F5_HEIGHT_MASK);
+       t->format |= ((log2Width << R200_TXFORMAT_WIDTH_SHIFT) |
+                          (log2Height << R200_TXFORMAT_HEIGHT_SHIFT));
+
+       #if 0
+       t->format_x &= ~(R200_DEPTH_LOG2_MASK | R200_TEXCOORD_MASK);
+       if (tObj->Target == GL_TEXTURE_3D) {
+               t->format_x |= (log2Depth << R200_DEPTH_LOG2_SHIFT);
+               t->format_x |= R200_TEXCOORD_VOLUME;
+       } else if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
+               ASSERT(log2Width == log2height);
+               t->format |= ((log2Width << R200_TXFORMAT_F5_WIDTH_SHIFT) |
+                                  (log2Height << R200_TXFORMAT_F5_HEIGHT_SHIFT)
+                                  | (R200_TXFORMAT_CUBIC_MAP_ENABLE));
+               t->format_x |= R200_TEXCOORD_CUBIC_ENV;
+               t->pp_cubic_faces = ((log2Width << R200_FACE_WIDTH_1_SHIFT) |
+                                    (log2Height << R200_FACE_HEIGHT_1_SHIFT) |
+                                    (log2Width << R200_FACE_WIDTH_2_SHIFT) |
+                                    (log2Height << R200_FACE_HEIGHT_2_SHIFT) |
+                                    (log2Width << R200_FACE_WIDTH_3_SHIFT) |
+                                    (log2Height << R200_FACE_HEIGHT_3_SHIFT) |
+                                    (log2Width << R200_FACE_WIDTH_4_SHIFT) |
+                                    (log2Height << R200_FACE_HEIGHT_4_SHIFT));
+       }
+       #endif
+       
+       t->size = (((tObj->Image[0][t->base.firstLevel]->Width - 1) << 0) |
+                       ((tObj->Image[0][t->base.firstLevel]->Height -
+                         1) << 16));
+
+       /* Only need to round to nearest 32 for textures, but the blitter
+        * requires 64-byte aligned pitches, and we may/may not need the
+        * blitter.   NPOT only!
+        */
+       if (baseImage->IsCompressed)
+               t->pitch =
+                   (tObj->Image[0][t->base.firstLevel]->Width + 63) & ~(63);
+       else
+               t->pitch =
+                   ((tObj->Image[0][t->base.firstLevel]->Width *
+                     baseImage->TexFormat->TexelBytes) + 63) & ~(63);
+       t->pitch -= 32;
+
+       t->dirty_state = TEX_ALL;
+
+       /* FYI: r300UploadTexImages( rmesa, t ) used to be called here */
+}
+
+/* ================================================================
+ * Texture combine functions
+ */
+
+/* GL_ARB_texture_env_combine support
+ */
+
+/* The color tables have combine functions for GL_SRC_COLOR,
+ * GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA.
+ */
+static GLuint r300_register_color[][R200_MAX_TEXTURE_UNITS] = {
+       {
+        R200_TXC_ARG_A_R0_COLOR,
+        R200_TXC_ARG_A_R1_COLOR,
+        R200_TXC_ARG_A_R2_COLOR,
+        R200_TXC_ARG_A_R3_COLOR,
+        R200_TXC_ARG_A_R4_COLOR,
+        R200_TXC_ARG_A_R5_COLOR},
+       {
+        R200_TXC_ARG_A_R0_COLOR | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R1_COLOR | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R2_COLOR | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R3_COLOR | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R4_COLOR | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R5_COLOR | R200_TXC_COMP_ARG_A},
+       {
+        R200_TXC_ARG_A_R0_ALPHA,
+        R200_TXC_ARG_A_R1_ALPHA,
+        R200_TXC_ARG_A_R2_ALPHA,
+        R200_TXC_ARG_A_R3_ALPHA,
+        R200_TXC_ARG_A_R4_ALPHA,
+        R200_TXC_ARG_A_R5_ALPHA},
+       {
+        R200_TXC_ARG_A_R0_ALPHA | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R1_ALPHA | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R2_ALPHA | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R3_ALPHA | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R4_ALPHA | R200_TXC_COMP_ARG_A,
+        R200_TXC_ARG_A_R5_ALPHA | R200_TXC_COMP_ARG_A},
+};
+
+static GLuint r300_tfactor_color[] = {
+       R200_TXC_ARG_A_TFACTOR_COLOR,
+       R200_TXC_ARG_A_TFACTOR_COLOR | R200_TXC_COMP_ARG_A,
+       R200_TXC_ARG_A_TFACTOR_ALPHA,
+       R200_TXC_ARG_A_TFACTOR_ALPHA | R200_TXC_COMP_ARG_A
+};
+
+static GLuint r300_primary_color[] = {
+       R200_TXC_ARG_A_DIFFUSE_COLOR,
+       R200_TXC_ARG_A_DIFFUSE_COLOR | R200_TXC_COMP_ARG_A,
+       R200_TXC_ARG_A_DIFFUSE_ALPHA,
+       R200_TXC_ARG_A_DIFFUSE_ALPHA | R200_TXC_COMP_ARG_A
+};
+
+/* GL_ZERO table - indices 0-3
+ * GL_ONE  table - indices 1-4
+ */
+static GLuint r300_zero_color[] = {
+       R200_TXC_ARG_A_ZERO,
+       R200_TXC_ARG_A_ZERO | R200_TXC_COMP_ARG_A,
+       R200_TXC_ARG_A_ZERO,
+       R200_TXC_ARG_A_ZERO | R200_TXC_COMP_ARG_A,
+       R200_TXC_ARG_A_ZERO
+};
+
+/* The alpha tables only have GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA.
+ */
+static GLuint r300_register_alpha[][R200_MAX_TEXTURE_UNITS] = {
+       {
+        R200_TXA_ARG_A_R0_ALPHA,
+        R200_TXA_ARG_A_R1_ALPHA,
+        R200_TXA_ARG_A_R2_ALPHA,
+        R200_TXA_ARG_A_R3_ALPHA,
+        R200_TXA_ARG_A_R4_ALPHA,
+        R200_TXA_ARG_A_R5_ALPHA},
+       {
+        R200_TXA_ARG_A_R0_ALPHA | R200_TXA_COMP_ARG_A,
+        R200_TXA_ARG_A_R1_ALPHA | R200_TXA_COMP_ARG_A,
+        R200_TXA_ARG_A_R2_ALPHA | R200_TXA_COMP_ARG_A,
+        R200_TXA_ARG_A_R3_ALPHA | R200_TXA_COMP_ARG_A,
+        R200_TXA_ARG_A_R4_ALPHA | R200_TXA_COMP_ARG_A,
+        R200_TXA_ARG_A_R5_ALPHA | R200_TXA_COMP_ARG_A},
+};
+
+static GLuint r300_tfactor_alpha[] = {
+       R200_TXA_ARG_A_TFACTOR_ALPHA,
+       R200_TXA_ARG_A_TFACTOR_ALPHA | R200_TXA_COMP_ARG_A
+};
+
+static GLuint r300_primary_alpha[] = {
+       R200_TXA_ARG_A_DIFFUSE_ALPHA,
+       R200_TXA_ARG_A_DIFFUSE_ALPHA | R200_TXA_COMP_ARG_A
+};
+
+/* GL_ZERO table - indices 0-1
+ * GL_ONE  table - indices 1-2
+ */
+static GLuint r300_zero_alpha[] = {
+       R200_TXA_ARG_A_ZERO,
+       R200_TXA_ARG_A_ZERO | R200_TXA_COMP_ARG_A,
+       R200_TXA_ARG_A_ZERO,
+};
+
+/* Extract the arg from slot A, shift it into the correct argument slot
+ * and set the corresponding complement bit.
+ */
+#define R200_COLOR_ARG( n, arg )                       \
+do {                                                   \
+   color_combine |=                                    \
+      ((color_arg[n] & R200_TXC_ARG_A_MASK)            \
+       << R200_TXC_ARG_##arg##_SHIFT);                 \
+   color_combine |=                                    \
+      ((color_arg[n] >> R200_TXC_COMP_ARG_A_SHIFT)     \
+       << R200_TXC_COMP_ARG_##arg##_SHIFT);            \
+} while (0)
+
+#define R200_ALPHA_ARG( n, arg )                       \
+do {                                                   \
+   alpha_combine |=                                    \
+      ((alpha_arg[n] & R200_TXA_ARG_A_MASK)            \
+       << R200_TXA_ARG_##arg##_SHIFT);                 \
+   alpha_combine |=                                    \
+      ((alpha_arg[n] >> R200_TXA_COMP_ARG_A_SHIFT)     \
+       << R200_TXA_COMP_ARG_##arg##_SHIFT);            \
+} while (0)
+
+/* ================================================================
+ * Texture unit state management
+ */
+
+static GLboolean r300UpdateTextureEnv(GLcontext * ctx, int unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+       GLuint color_combine, alpha_combine;
+       
+       #if 0 /* disable for now.. */
+       GLuint color_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2] &
+           ~(R200_TXC_SCALE_MASK);
+       GLuint alpha_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2] &
+           ~(R200_TXA_DOT_ALPHA | R200_TXA_SCALE_MASK);
+
+       /* texUnit->_Current can be NULL if and only if the texture unit is
+        * not actually enabled.
+        */
+       assert((texUnit->_ReallyEnabled == 0)
+              || (texUnit->_Current != NULL));
+
+       if (RADEON_DEBUG & DEBUG_TEXTURE) {
+               fprintf(stderr, "%s( %p, %d )\n", __FUNCTION__, (void *)ctx,
+                       unit);
+       }
+
+       /* Set the texture environment state.  Isn't this nice and clean?
+        * The chip will automagically set the texture alpha to 0xff when
+        * the texture format does not include an alpha component.  This
+        * reduces the amount of special-casing we have to do, alpha-only
+        * textures being a notable exception.
+        */
+       /* Don't cache these results.
+        */
+       rmesa->state.texture.unit[unit].format = 0;
+       rmesa->state.texture.unit[unit].envMode = 0;
+
+       if (!texUnit->_ReallyEnabled) {
+               if (unit == 0) {
+                       color_combine =
+                           R200_TXC_ARG_A_ZERO | R200_TXC_ARG_B_ZERO |
+                           R200_TXC_ARG_C_DIFFUSE_COLOR | R200_TXC_OP_MADD;
+                       alpha_combine =
+                           R200_TXA_ARG_A_ZERO | R200_TXA_ARG_B_ZERO |
+                           R200_TXA_ARG_C_DIFFUSE_ALPHA | R200_TXA_OP_MADD;
+               } else {
+                       color_combine =
+                           R200_TXC_ARG_A_ZERO | R200_TXC_ARG_B_ZERO |
+                           R200_TXC_ARG_C_R0_COLOR | R200_TXC_OP_MADD;
+                       alpha_combine =
+                           R200_TXA_ARG_A_ZERO | R200_TXA_ARG_B_ZERO |
+                           R200_TXA_ARG_C_R0_ALPHA | R200_TXA_OP_MADD;
+               }
+       } else {
+               GLuint color_arg[3], alpha_arg[3];
+               GLuint i;
+               const GLuint numColorArgs =
+                   texUnit->_CurrentCombine->_NumArgsRGB;
+               const GLuint numAlphaArgs = texUnit->_CurrentCombine->_NumArgsA;
+               GLuint RGBshift = texUnit->_CurrentCombine->ScaleShiftRGB;
+               GLuint Ashift = texUnit->_CurrentCombine->ScaleShiftA;
+
+               /* Step 1:
+                * Extract the color and alpha combine function arguments.
+                */
+               for (i = 0; i < numColorArgs; i++) {
+                       const GLint op =
+                           texUnit->_CurrentCombine->OperandRGB[i] -
+                           GL_SRC_COLOR;
+                       assert(op >= 0);
+                       assert(op <= 3);
+                       switch (texUnit->_CurrentCombine->SourceRGB[i]) {
+                       case GL_TEXTURE:
+                               color_arg[i] = r300_register_color[op][unit];
+                               break;
+                       case GL_CONSTANT:
+                               color_arg[i] = r300_tfactor_color[op];
+                               break;
+                       case GL_PRIMARY_COLOR:
+                               color_arg[i] = r300_primary_color[op];
+                               break;
+                       case GL_PREVIOUS:
+                               if (unit == 0)
+                                       color_arg[i] = r300_primary_color[op];
+                               else
+                                       color_arg[i] =
+                                           r300_register_color[op][0];
+                               break;
+                       case GL_ZERO:
+                               color_arg[i] = r300_zero_color[op];
+                               break;
+                       case GL_ONE:
+                               color_arg[i] = r300_zero_color[op + 1];
+                               break;
+                       default:
+                               return GL_FALSE;
+                       }
+               }
+
+               for (i = 0; i < numAlphaArgs; i++) {
+                       const GLint op =
+                           texUnit->_CurrentCombine->OperandA[i] -
+                           GL_SRC_ALPHA;
+                       assert(op >= 0);
+                       assert(op <= 1);
+                       switch (texUnit->_CurrentCombine->SourceA[i]) {
+                       case GL_TEXTURE:
+                               alpha_arg[i] = r300_register_alpha[op][unit];
+                               break;
+                       case GL_CONSTANT:
+                               alpha_arg[i] = r300_tfactor_alpha[op];
+                               break;
+                       case GL_PRIMARY_COLOR:
+                               alpha_arg[i] = r300_primary_alpha[op];
+                               break;
+                       case GL_PREVIOUS:
+                               if (unit == 0)
+                                       alpha_arg[i] = r300_primary_alpha[op];
+                               else
+                                       alpha_arg[i] =
+                                           r300_register_alpha[op][0];
+                               break;
+                       case GL_ZERO:
+                               alpha_arg[i] = r300_zero_alpha[op];
+                               break;
+                       case GL_ONE:
+                               alpha_arg[i] = r300_zero_alpha[op + 1];
+                               break;
+                       default:
+                               return GL_FALSE;
+                       }
+               }
+
+               /* Step 2:
+                * Build up the color and alpha combine functions.
+                */
+               switch (texUnit->_CurrentCombine->ModeRGB) {
+               case GL_REPLACE:
+                       color_combine = (R200_TXC_ARG_A_ZERO |
+                                        R200_TXC_ARG_B_ZERO |
+                                        R200_TXC_OP_MADD);
+                       R200_COLOR_ARG(0, C);
+                       break;
+               case GL_MODULATE:
+                       color_combine = (R200_TXC_ARG_C_ZERO |
+                                        R200_TXC_OP_MADD);
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, B);
+                       break;
+               case GL_ADD:
+                       color_combine = (R200_TXC_ARG_B_ZERO |
+                                        R200_TXC_COMP_ARG_B |
+                                        R200_TXC_OP_MADD);
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, C);
+                       break;
+               case GL_ADD_SIGNED:
+                       color_combine = (R200_TXC_ARG_B_ZERO | R200_TXC_COMP_ARG_B | R200_TXC_BIAS_ARG_C |      /* new */
+                                        R200_TXC_OP_MADD);     /* was ADDSIGNED */
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, C);
+                       break;
+               case GL_SUBTRACT:
+                       color_combine = (R200_TXC_ARG_B_ZERO |
+                                        R200_TXC_COMP_ARG_B |
+                                        R200_TXC_NEG_ARG_C | R200_TXC_OP_MADD);
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, C);
+                       break;
+               case GL_INTERPOLATE:
+                       color_combine = (R200_TXC_OP_LERP);
+                       R200_COLOR_ARG(0, B);
+                       R200_COLOR_ARG(1, A);
+                       R200_COLOR_ARG(2, C);
+                       break;
+
+               case GL_DOT3_RGB_EXT:
+               case GL_DOT3_RGBA_EXT:
+                       /* The EXT version of the DOT3 extension does not support the
+                        * scale factor, but the ARB version (and the version in OpenGL
+                        * 1.3) does.
+                        */
+                       RGBshift = 0;
+                       /* FALLTHROUGH */
+
+               case GL_DOT3_RGB:
+               case GL_DOT3_RGBA:
+                       /* DOT3 works differently on R200 than on R100.  On R100, just
+                        * setting the DOT3 mode did everything for you.  On R200, the
+                        * driver has to enable the biasing and scale in the inputs to
+                        * put them in the proper [-1,1] range.  This is what the 4x and
+                        * the -0.5 in the DOT3 spec do.  The post-scale is then set
+                        * normally.
+                        */
+
+                       color_combine = (R200_TXC_ARG_C_ZERO |
+                                        R200_TXC_OP_DOT3 |
+                                        R200_TXC_BIAS_ARG_A |
+                                        R200_TXC_BIAS_ARG_B |
+                                        R200_TXC_SCALE_ARG_A |
+                                        R200_TXC_SCALE_ARG_B);
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, B);
+                       break;
+
+               case GL_MODULATE_ADD_ATI:
+                       color_combine = (R200_TXC_OP_MADD);
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, C);
+                       R200_COLOR_ARG(2, B);
+                       break;
+               case GL_MODULATE_SIGNED_ADD_ATI:
+                       color_combine = (R200_TXC_BIAS_ARG_C |  /* new */
+                                        R200_TXC_OP_MADD);     /* was ADDSIGNED */
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, C);
+                       R200_COLOR_ARG(2, B);
+                       break;
+               case GL_MODULATE_SUBTRACT_ATI:
+                       color_combine = (R200_TXC_NEG_ARG_C | R200_TXC_OP_MADD);
+                       R200_COLOR_ARG(0, A);
+                       R200_COLOR_ARG(1, C);
+                       R200_COLOR_ARG(2, B);
+                       break;
+               default:
+                       return GL_FALSE;
+               }
+
+               switch (texUnit->_CurrentCombine->ModeA) {
+               case GL_REPLACE:
+                       alpha_combine = (R200_TXA_ARG_A_ZERO |
+                                        R200_TXA_ARG_B_ZERO |
+                                        R200_TXA_OP_MADD);
+                       R200_ALPHA_ARG(0, C);
+                       break;
+               case GL_MODULATE:
+                       alpha_combine = (R200_TXA_ARG_C_ZERO |
+                                        R200_TXA_OP_MADD);
+                       R200_ALPHA_ARG(0, A);
+                       R200_ALPHA_ARG(1, B);
+                       break;
+               case GL_ADD:
+                       alpha_combine = (R200_TXA_ARG_B_ZERO |
+                                        R200_TXA_COMP_ARG_B |
+                                        R200_TXA_OP_MADD);
+                       R200_ALPHA_ARG(0, A);
+                       R200_ALPHA_ARG(1, C);
+                       break;
+               case GL_ADD_SIGNED:
+                       alpha_combine = (R200_TXA_ARG_B_ZERO | R200_TXA_COMP_ARG_B | R200_TXA_BIAS_ARG_C |      /* new */
+                                        R200_TXA_OP_MADD);     /* was ADDSIGNED */
+                       R200_ALPHA_ARG(0, A);
+                       R200_ALPHA_ARG(1, C);
+                       break;
+               case GL_SUBTRACT:
+                       alpha_combine = (R200_TXA_ARG_B_ZERO |
+                                        R200_TXA_COMP_ARG_B |
+                                        R200_TXA_NEG_ARG_C | R200_TXA_OP_MADD);
+                       R200_ALPHA_ARG(0, A);
+                       R200_ALPHA_ARG(1, C);
+                       break;
+               case GL_INTERPOLATE:
+                       alpha_combine = (R200_TXA_OP_LERP);
+                       R200_ALPHA_ARG(0, B);
+                       R200_ALPHA_ARG(1, A);
+                       R200_ALPHA_ARG(2, C);
+                       break;
+
+               case GL_MODULATE_ADD_ATI:
+                       alpha_combine = (R200_TXA_OP_MADD);
+                       R200_ALPHA_ARG(0, A);
+                       R200_ALPHA_ARG(1, C);
+                       R200_ALPHA_ARG(2, B);
+                       break;
+               case GL_MODULATE_SIGNED_ADD_ATI:
+                       alpha_combine = (R200_TXA_BIAS_ARG_C |  /* new */
+                                        R200_TXA_OP_MADD);     /* was ADDSIGNED */
+                       R200_ALPHA_ARG(0, A);
+                       R200_ALPHA_ARG(1, C);
+                       R200_ALPHA_ARG(2, B);
+                       break;
+               case GL_MODULATE_SUBTRACT_ATI:
+                       alpha_combine = (R200_TXA_NEG_ARG_C | R200_TXA_OP_MADD);
+                       R200_ALPHA_ARG(0, A);
+                       R200_ALPHA_ARG(1, C);
+                       R200_ALPHA_ARG(2, B);
+                       break;
+               default:
+                       return GL_FALSE;
+               }
+
+               if ((texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA_EXT)
+                   || (texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA)) {
+                       alpha_scale |= R200_TXA_DOT_ALPHA;
+                       Ashift = RGBshift;
+               }
+
+               /* Step 3:
+                * Apply the scale factor.
+                */
+               color_scale |= (RGBshift << R200_TXC_SCALE_SHIFT);
+               alpha_scale |= (Ashift << R200_TXA_SCALE_SHIFT);
+
+               /* All done!
+                */
+       }
+
+       if (rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND] != color_combine ||
+           rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND] != alpha_combine ||
+           rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2] != color_scale ||
+           rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2] != alpha_scale) {
+               R300_STATECHANGE(rmesa, pix[unit]);
+               rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND] = color_combine;
+               rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND] = alpha_combine;
+               rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2] = color_scale;
+               rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2] = alpha_scale;
+       }
+
+       #endif
+       
+       return GL_TRUE;
+}
+
+#define TEXOBJ_TXFILTER_MASK (R200_MAX_MIP_LEVEL_MASK |                \
+                             R200_MIN_FILTER_MASK |            \
+                             R200_MAG_FILTER_MASK |            \
+                             R200_MAX_ANISO_MASK |             \
+                             R200_YUV_TO_RGB |                 \
+                             R200_YUV_TEMPERATURE_MASK |       \
+                             R200_CLAMP_S_MASK |               \
+                             R200_CLAMP_T_MASK |               \
+                             R200_BORDER_MODE_D3D )
+
+#define TEXOBJ_TXFORMAT_MASK (R200_TXFORMAT_WIDTH_MASK |       \
+                             R200_TXFORMAT_HEIGHT_MASK |       \
+                             R200_TXFORMAT_FORMAT_MASK |       \
+                              R200_TXFORMAT_F5_WIDTH_MASK |    \
+                              R200_TXFORMAT_F5_HEIGHT_MASK |   \
+                             R200_TXFORMAT_ALPHA_IN_MAP |      \
+                             R200_TXFORMAT_CUBIC_MAP_ENABLE |  \
+                              R200_TXFORMAT_NON_POWER2)
+
+#define TEXOBJ_TXFORMAT_X_MASK (R200_DEPTH_LOG2_MASK |         \
+                                R200_TEXCOORD_MASK |           \
+                                R200_CLAMP_Q_MASK |            \
+                                R200_VOLUME_FILTER_MASK)
+
+static void import_tex_obj_state(r300ContextPtr rmesa,
+                                int unit, r300TexObjPtr texobj)
+{
+       #if 0 /* needs fixing.. or should be done elsewhere */
+       GLuint *cmd = R300_DB_STATE(tex[unit]);
+
+       cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK;
+       cmd[TEX_PP_TXFILTER] |= texobj->filter & TEXOBJ_TXFILTER_MASK;
+       cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
+       cmd[TEX_PP_TXFORMAT] |= texobj->format & TEXOBJ_TXFORMAT_MASK;
+       cmd[TEX_PP_TXFORMAT_X] &= ~TEXOBJ_TXFORMAT_X_MASK;
+       cmd[TEX_PP_TXFORMAT_X] |=
+           texobj->format_x & TEXOBJ_TXFORMAT_X_MASK;
+       cmd[TEX_PP_TXSIZE] = texobj->size;      /* NPOT only! */
+       cmd[TEX_PP_TXPITCH] = texobj->pitch;    /* NPOT only! */
+       cmd[TEX_PP_TXOFFSET] = texobj->pp_txoffset;
+       cmd[TEX_PP_BORDER_COLOR] = texobj->pp_border_color;
+       R200_DB_STATECHANGE(rmesa, &rmesa->hw.tex[unit]);
+
+       if (texobj->base.tObj->Target == GL_TEXTURE_CUBE_MAP) {
+               GLuint *cube_cmd = R200_DB_STATE(cube[unit]);
+               GLuint bytesPerFace = texobj->base.totalSize / 6;
+               ASSERT(texobj->totalSize % 6 == 0);
+               cube_cmd[CUBE_PP_CUBIC_FACES] = texobj->pp_cubic_faces;
+               cube_cmd[CUBE_PP_CUBIC_OFFSET_F1] =
+                   texobj->pp_txoffset + 1 * bytesPerFace;
+               cube_cmd[CUBE_PP_CUBIC_OFFSET_F2] =
+                   texobj->pp_txoffset + 2 * bytesPerFace;
+               cube_cmd[CUBE_PP_CUBIC_OFFSET_F3] =
+                   texobj->pp_txoffset + 3 * bytesPerFace;
+               cube_cmd[CUBE_PP_CUBIC_OFFSET_F4] =
+                   texobj->pp_txoffset + 4 * bytesPerFace;
+               cube_cmd[CUBE_PP_CUBIC_OFFSET_F5] =
+                   texobj->pp_txoffset + 5 * bytesPerFace;
+               R200_DB_STATECHANGE(rmesa, &rmesa->hw.cube[unit]);
+       }
+
+       texobj->dirty_state &= ~(1 << unit);
+       #endif
+}
+
+static void set_texgen_matrix(r300ContextPtr rmesa,
+                             GLuint unit,
+                             const GLfloat * s_plane,
+                             const GLfloat * t_plane, const GLfloat * r_plane)
+{
+       static const GLfloat scale_identity[4] = { 1, 1, 1, 1 };
+
+       if (!TEST_EQ_4V(s_plane, scale_identity) ||
+           !TEST_EQ_4V(t_plane, scale_identity) ||
+           !TEST_EQ_4V(r_plane, scale_identity)) {
+               rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE << unit;
+               rmesa->TexGenMatrix[unit].m[0] = s_plane[0];
+               rmesa->TexGenMatrix[unit].m[4] = s_plane[1];
+               rmesa->TexGenMatrix[unit].m[8] = s_plane[2];
+               rmesa->TexGenMatrix[unit].m[12] = s_plane[3];
+
+               rmesa->TexGenMatrix[unit].m[1] = t_plane[0];
+               rmesa->TexGenMatrix[unit].m[5] = t_plane[1];
+               rmesa->TexGenMatrix[unit].m[9] = t_plane[2];
+               rmesa->TexGenMatrix[unit].m[13] = t_plane[3];
+
+               /* NOTE: r_plane goes in the 4th row, not 3rd! */
+               rmesa->TexGenMatrix[unit].m[3] = r_plane[0];
+               rmesa->TexGenMatrix[unit].m[7] = r_plane[1];
+               rmesa->TexGenMatrix[unit].m[11] = r_plane[2];
+               rmesa->TexGenMatrix[unit].m[15] = r_plane[3];
+
+               //rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+       }
+}
+
+/* Need this special matrix to get correct reflection map coords */
+static void set_texgen_reflection_matrix(r300ContextPtr rmesa, GLuint unit)
+{
+       static const GLfloat m[16] = {
+               -1, 0, 0, 0,
+               0, -1, 0, 0,
+               0, 0, 0, -1,
+               0, 0, -1, 0
+       };
+       _math_matrix_loadf(&(rmesa->TexGenMatrix[unit]), m);
+       _math_matrix_analyse(&(rmesa->TexGenMatrix[unit]));
+       rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE << unit;
+}
+
+/* Need this special matrix to get correct normal map coords */
+static void set_texgen_normal_map_matrix(r300ContextPtr rmesa, GLuint unit)
+{
+       static const GLfloat m[16] = {
+               1, 0, 0, 0,
+               0, 1, 0, 0,
+               0, 0, 0, 1,
+               0, 0, 1, 0
+       };
+       _math_matrix_loadf(&(rmesa->TexGenMatrix[unit]), m);
+       _math_matrix_analyse(&(rmesa->TexGenMatrix[unit]));
+       rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE << unit;
+}
+
+/* Ignoring the Q texcoord for now.
+ *
+ * Returns GL_FALSE if fallback required.
+ */
+static GLboolean r300_validate_texgen(GLcontext * ctx, GLuint unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+       GLuint inputshift = R200_TEXGEN_0_INPUT_SHIFT + unit * 4;
+       GLuint tmp = rmesa->TexGenEnabled;
+
+       rmesa->TexGenCompSel &= ~(R200_OUTPUT_TEX_0 << unit);
+       rmesa->TexGenEnabled &= ~(R200_TEXGEN_TEXMAT_0_ENABLE << unit);
+       rmesa->TexGenEnabled &= ~(R200_TEXMAT_0_ENABLE << unit);
+       rmesa->TexGenInputs &= ~(R200_TEXGEN_INPUT_MASK << inputshift);
+       rmesa->TexGenNeedNormals[unit] = 0;
+
+       if (0)
+               fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit);
+
+       if ((texUnit->TexGenEnabled & (S_BIT | T_BIT | R_BIT)) == 0) {
+               /* Disabled, no fallback:
+                */
+               rmesa->TexGenInputs |=
+                   (R200_TEXGEN_INPUT_TEXCOORD_0 + unit) << inputshift;
+               return GL_TRUE;
+       } else if (texUnit->TexGenEnabled & Q_BIT) {
+               /* Very easy to do this, in fact would remove a fallback case
+                * elsewhere, but I haven't done it yet...  Fallback:
+                */
+               /*fprintf(stderr, "fallback Q_BIT\n"); */
+               return GL_FALSE;
+       } else if (texUnit->TexGenEnabled == (S_BIT | T_BIT) &&
+                  texUnit->GenModeS == texUnit->GenModeT) {
+               /* OK */
+               rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit;
+               /* continue */
+       } else if (texUnit->TexGenEnabled == (S_BIT | T_BIT | R_BIT) &&
+                  texUnit->GenModeS == texUnit->GenModeT &&
+                  texUnit->GenModeT == texUnit->GenModeR) {
+               /* OK */
+               rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit;
+               /* continue */
+       } else {
+               /* Mixed modes, fallback:
+                */
+               /* fprintf(stderr, "fallback mixed texgen\n"); */
+               return GL_FALSE;
+       }
+
+       rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit;
+
+       switch (texUnit->GenModeS) {
+       case GL_OBJECT_LINEAR:
+               rmesa->TexGenInputs |= R200_TEXGEN_INPUT_OBJ << inputshift;
+               set_texgen_matrix(rmesa, unit,
+                                 texUnit->ObjectPlaneS,
+                                 texUnit->ObjectPlaneT, texUnit->ObjectPlaneR);
+               break;
+
+       case GL_EYE_LINEAR:
+               rmesa->TexGenInputs |= R200_TEXGEN_INPUT_EYE << inputshift;
+               set_texgen_matrix(rmesa, unit,
+                                 texUnit->EyePlaneS,
+                                 texUnit->EyePlaneT, texUnit->EyePlaneR);
+               break;
+
+       case GL_REFLECTION_MAP_NV:
+               rmesa->TexGenNeedNormals[unit] = GL_TRUE;
+               rmesa->TexGenInputs |=
+                   R200_TEXGEN_INPUT_EYE_REFLECT << inputshift;
+               set_texgen_reflection_matrix(rmesa, unit);
+               break;
+
+       case GL_NORMAL_MAP_NV:
+               rmesa->TexGenNeedNormals[unit] = GL_TRUE;
+               rmesa->TexGenInputs |=
+                   R200_TEXGEN_INPUT_EYE_NORMAL << inputshift;
+               set_texgen_normal_map_matrix(rmesa, unit);
+               break;
+
+       case GL_SPHERE_MAP:
+               rmesa->TexGenNeedNormals[unit] = GL_TRUE;
+               rmesa->TexGenInputs |= R200_TEXGEN_INPUT_SPHERE << inputshift;
+               break;
+
+       default:
+               /* Unsupported mode, fallback:
+                */
+               /*  fprintf(stderr, "fallback unsupported texgen\n"); */
+               return GL_FALSE;
+       }
+
+       rmesa->TexGenCompSel |= R200_OUTPUT_TEX_0 << unit;
+
+       if (tmp != rmesa->TexGenEnabled) {
+               //rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+       }
+
+       return GL_TRUE;
+}
+
+static void disable_tex(GLcontext * ctx, int unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+
+       #if 0 /* This needs to be redone.. or done elsewhere */
+       if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_0_ENABLE << unit)) {
+               /* Texture unit disabled */
+               if (rmesa->state.texture.unit[unit].texobj != NULL) {
+                       /* The old texture is no longer bound to this texture unit.
+                        * Mark it as such.
+                        */
+
+                       rmesa->state.texture.unit[unit].texobj->base.bound &=
+                           ~(1UL << unit);
+                       rmesa->state.texture.unit[unit].texobj = NULL;
+               }
+
+               R300_STATECHANGE(rmesa, ctx);
+               rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~((R200_TEX_0_ENABLE |
+                                                    R200_TEX_BLEND_0_ENABLE) <<
+                                                   unit);
+               rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_BLEND_0_ENABLE;
+
+               R300_STATECHANGE(rmesa, tcl);
+               rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_VTXFMT_1] &=
+                   ~(7 << (unit * 3));
+
+               if (rmesa->radeon.TclFallback & (RADEON_TCL_FALLBACK_TEXGEN_0 << unit)) {
+                       TCL_FALLBACK(ctx, (RADEON_TCL_FALLBACK_TEXGEN_0 << unit),
+                                    GL_FALSE);
+               }
+
+               /* Actually want to keep all units less than max active texture
+                * enabled, right?  Fix this for >2 texunits.
+                */
+               /* FIXME: What should happen here if r300UpdateTextureEnv fails? */
+               if (unit == 0)
+                       r300UpdateTextureEnv(ctx, unit);
+
+               {
+                       GLuint inputshift =
+                           R200_TEXGEN_0_INPUT_SHIFT + unit * 4;
+                       GLuint tmp = rmesa->TexGenEnabled;
+
+                       rmesa->TexGenEnabled &=
+                           ~(R200_TEXGEN_TEXMAT_0_ENABLE << unit);
+                       rmesa->TexGenEnabled &= ~(R200_TEXMAT_0_ENABLE << unit);
+                       rmesa->TexGenEnabled &=
+                           ~(R200_TEXGEN_INPUT_MASK << inputshift);
+                       rmesa->TexGenNeedNormals[unit] = 0;
+                       rmesa->TexGenCompSel &= ~(R200_OUTPUT_TEX_0 << unit);
+                       rmesa->TexGenInputs &=
+                           ~(R200_TEXGEN_INPUT_MASK << inputshift);
+
+                       if (tmp != rmesa->TexGenEnabled) {
+                               rmesa->recheck_texgen[unit] = GL_TRUE;
+                               rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+                       }
+               }
+       }
+       #endif
+}
+
+static GLboolean enable_tex_2d(GLcontext * ctx, int unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+       struct gl_texture_object *tObj = texUnit->_Current;
+       r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData;
+
+       /* Need to load the 2d images associated with this unit.
+        */
+       if (t->format & R200_TXFORMAT_NON_POWER2) {
+               t->format &= ~R200_TXFORMAT_NON_POWER2;
+               t->base.dirty_images[0] = ~0;
+       }
+
+       ASSERT(tObj->Target == GL_TEXTURE_2D || tObj->Target == GL_TEXTURE_1D);
+
+       if (t->base.dirty_images[0]) {
+               R300_FIREVERTICES(rmesa);
+               r300SetTexImages(rmesa, tObj);
+               r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0);
+               if (!t->base.memBlock)
+                       return GL_FALSE;
+       }
+
+       return GL_TRUE;
+}
+
+#if ENABLE_HW_3D_TEXTURE
+static GLboolean enable_tex_3d(GLcontext * ctx, int unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+       struct gl_texture_object *tObj = texUnit->_Current;
+       r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData;
+
+       /* Need to load the 3d images associated with this unit.
+        */
+       if (t->format & R200_TXFORMAT_NON_POWER2) {
+               t->format &= ~R200_TXFORMAT_NON_POWER2;
+               t->base.dirty_images[0] = ~0;
+       }
+
+       ASSERT(tObj->Target == GL_TEXTURE_3D);
+
+       /* R100 & R200 do not support mipmaps for 3D textures.
+        */
+       if ((tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR)) {
+               return GL_FALSE;
+       }
+
+       if (t->base.dirty_images[0]) {
+               R300_FIREVERTICES(rmesa);
+               r300SetTexImages(rmesa, tObj);
+               r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0);
+               if (!t->base.memBlock)
+                       return GL_FALSE;
+       }
+
+       return GL_TRUE;
+}
+#endif
+
+static GLboolean enable_tex_cube(GLcontext * ctx, int unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+       struct gl_texture_object *tObj = texUnit->_Current;
+       r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData;
+       GLuint face;
+
+       /* Need to load the 2d images associated with this unit.
+        */
+       if (t->format & R200_TXFORMAT_NON_POWER2) {
+               t->format &= ~R200_TXFORMAT_NON_POWER2;
+               for (face = 0; face < 6; face++)
+                       t->base.dirty_images[face] = ~0;
+       }
+
+       ASSERT(tObj->Target == GL_TEXTURE_CUBE_MAP);
+
+       if (t->base.dirty_images[0] || t->base.dirty_images[1] ||
+           t->base.dirty_images[2] || t->base.dirty_images[3] ||
+           t->base.dirty_images[4] || t->base.dirty_images[5]) {
+               /* flush */
+               R300_FIREVERTICES(rmesa);
+               /* layout memory space, once for all faces */
+               r300SetTexImages(rmesa, tObj);
+       }
+
+       /* upload (per face) */
+       for (face = 0; face < 6; face++) {
+               if (t->base.dirty_images[face]) {
+                       r300UploadTexImages(rmesa,
+                                           (r300TexObjPtr) tObj->DriverData,
+                                           face);
+               }
+       }
+
+       if (!t->base.memBlock) {
+               /* texmem alloc failed, use s/w fallback */
+               return GL_FALSE;
+       }
+
+       return GL_TRUE;
+}
+
+static GLboolean enable_tex_rect(GLcontext * ctx, int unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+       struct gl_texture_object *tObj = texUnit->_Current;
+       r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData;
+
+       if (!(t->format & R200_TXFORMAT_NON_POWER2)) {
+               t->format |= R200_TXFORMAT_NON_POWER2;
+               t->base.dirty_images[0] = ~0;
+       }
+
+       ASSERT(tObj->Target == GL_TEXTURE_RECTANGLE_NV);
+
+       if (t->base.dirty_images[0]) {
+               R300_FIREVERTICES(rmesa);
+               r300SetTexImages(rmesa, tObj);
+               r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0);
+               if (!t->base.memBlock && !rmesa->prefer_gart_client_texturing)
+                       return GL_FALSE;
+       }
+
+       return GL_TRUE;
+}
+
+static GLboolean update_tex_common(GLcontext * ctx, int unit)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+       struct gl_texture_object *tObj = texUnit->_Current;
+       r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData;
+       GLenum format;
+
+       /* 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 (rmesa->state.texture.unit[unit].texobj != t) {
+               if (rmesa->state.texture.unit[unit].texobj != NULL) {
+                       /* The old texture is no longer bound to this texture unit.
+                        * Mark it as such.
+                        */
+
+                       rmesa->state.texture.unit[unit].texobj->base.bound &=
+                           ~(1UL << unit);
+               }
+
+               rmesa->state.texture.unit[unit].texobj = t;
+               t->base.bound |= (1UL << unit);
+               t->dirty_state |= 1 << unit;
+               driUpdateTextureLRU((driTextureObject *) t);    /* XXX: should be locked! */
+       }
+
+       #if 0 /* do elsewhere ? */
+       /* Newly enabled?
+        */
+       if (1
+           || !(rmesa->hw.ctx.
+                cmd[CTX_PP_CNTL] & (R200_TEX_0_ENABLE << unit))) {
+               R300_STATECHANGE(rmesa, ctx);
+               rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (R200_TEX_0_ENABLE |
+                                                  R200_TEX_BLEND_0_ENABLE) <<
+                   unit;
+
+               R300_STATECHANGE(rmesa, vtx);
+               rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_VTXFMT_1] |= 4 << (unit * 3);
+
+               rmesa->recheck_texgen[unit] = GL_TRUE;
+       }
+
+       if (t->dirty_state & (1 << unit)) {
+               import_tex_obj_state(rmesa, unit, t);
+       }
+
+       if (rmesa->recheck_texgen[unit]) {
+               GLboolean fallback = !r300_validate_texgen(ctx, unit);
+               TCL_FALLBACK(ctx, (RADEON_TCL_FALLBACK_TEXGEN_0 << unit),
+                            fallback);
+               rmesa->recheck_texgen[unit] = 0;
+               rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+       }
+
+       format = tObj->Image[0][tObj->BaseLevel]->Format;
+       if (rmesa->state.texture.unit[unit].format != format ||
+           rmesa->state.texture.unit[unit].envMode != texUnit->EnvMode) {
+               rmesa->state.texture.unit[unit].format = format;
+               rmesa->state.texture.unit[unit].envMode = texUnit->EnvMode;
+               if (!r300UpdateTextureEnv(ctx, unit)) {
+                       return GL_FALSE;
+               }
+       }
+       #endif
+       
+       FALLBACK(&rmesa->radeon, RADEON_FALLBACK_BORDER_MODE, t->border_fallback);
+       return !t->border_fallback;
+}
+
+static GLboolean r300UpdateTextureUnit(GLcontext * ctx, int unit)
+{
+       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+       if (texUnit->_ReallyEnabled & (TEXTURE_RECT_BIT)) {
+               return (enable_tex_rect(ctx, unit) &&
+                       update_tex_common(ctx, unit));
+       } else if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) {
+               return (enable_tex_2d(ctx, unit) &&
+                       update_tex_common(ctx, unit));
+       }
+#if ENABLE_HW_3D_TEXTURE
+       else if (texUnit->_ReallyEnabled & (TEXTURE_3D_BIT)) {
+               return (enable_tex_3d(ctx, unit) &&
+                       update_tex_common(ctx, unit));
+       }
+#endif
+       else if (texUnit->_ReallyEnabled & (TEXTURE_CUBE_BIT)) {
+               return (enable_tex_cube(ctx, unit) &&
+                       update_tex_common(ctx, unit));
+       } else if (texUnit->_ReallyEnabled) {
+               return GL_FALSE;
+       } else {
+               disable_tex(ctx, unit);
+               return GL_TRUE;
+       }
+}
+
+void r300UpdateTextureState(GLcontext * ctx)
+{
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       GLboolean ok;
+       GLuint dbg;
+       int i;
+
+       ok = (r300UpdateTextureUnit(ctx, 0) &&
+             r300UpdateTextureUnit(ctx, 1) &&
+             r300UpdateTextureUnit(ctx, 2) &&
+             r300UpdateTextureUnit(ctx, 3) &&
+             r300UpdateTextureUnit(ctx, 4) && 
+             r300UpdateTextureUnit(ctx, 5) &&
+             r300UpdateTextureUnit(ctx, 6) && 
+             r300UpdateTextureUnit(ctx, 7)
+             );
+
+       FALLBACK(&rmesa->radeon, RADEON_FALLBACK_TEXTURE, !ok);
+
+       /* This needs correction, or just be done elsewhere 
+       if (rmesa->radeon.TclFallback)
+               r300ChooseVertexState(ctx);
+       */
+               
+       #if 0 /* Workaround - disable.. */
+       if (GET_CHIP(rmesa->radeon.radeonScreen) == RADEON_CHIP_REAL_R200) {
+               /*
+                * T0 hang workaround -------------
+                * not needed for r300 derivatives?
+                */
+               if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_ENABLE_MASK) ==
+                   R200_TEX_0_ENABLE
+                   && (rmesa->hw.tex[0].
+                       cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK) >
+                   R200_MIN_FILTER_LINEAR) {
+
+                       R300_STATECHANGE(rmesa, ctx);
+                       R300_STATECHANGE(rmesa, tex[1]);
+                       rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_1_ENABLE;
+                       rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &=
+                           ~TEXOBJ_TXFORMAT_MASK;
+                       rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] |= 0x08000000;
+               } else {
+                       if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_1_ENABLE)
+                           && (rmesa->hw.tex[1].
+                               cmd[TEX_PP_TXFORMAT] & 0x08000000)) {
+                               R300_STATECHANGE(rmesa, tex[1]);
+                               rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &=
+                                   ~0x08000000;
+                       }
+               }
+
+               /* maybe needs to be done pairwise due to 2 parallel (physical) tex units ?
+                  looks like that's not the case, if 8500/9100 owners don't complain remove this...
+                  for ( i = 0; i < ctx->Const.MaxTextureUnits; i += 2) {
+                  if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & ((R200_TEX_0_ENABLE |
+                  R200_TEX_1_ENABLE ) << i)) == (R200_TEX_0_ENABLE << i)) &&
+                  ((rmesa->hw.tex[i].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK) >
+                  R200_MIN_FILTER_LINEAR)) {
+                  R300_STATECHANGE(rmesa, ctx);
+                  R300_STATECHANGE(rmesa, tex[i+1]);
+                  rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (R200_TEX_1_ENABLE << i);
+                  rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
+                  rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] |= 0x08000000;
+                  }
+                  else {
+                  if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_1_ENABLE << i)) &&
+                  (rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] & 0x08000000)) {
+                  R300_STATECHANGE(rmesa, tex[i+1]);
+                  rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] &= ~0x08000000;
+                  }
+                  }
+                  } */
+
+               /*
+                * Texture cache LRU hang workaround -------------
+                * not needed for r300 derivatives?
+                */
+               dbg = 0x0;
+
+               if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_0_ENABLE)) &&
+                    ((((rmesa->hw.tex[0].
+                        cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04)
+                     == 0))
+                   || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_2_ENABLE)
+                       &&
+                       ((((rmesa->hw.tex[2].
+                           cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+                         0x04) == 0))
+                   || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_4_ENABLE)
+                       &&
+                       ((((rmesa->hw.tex[4].
+                           cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+                         0x04) == 0))) {
+                       dbg |= 0x02;
+               }
+
+               if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_1_ENABLE)) &&
+                    ((((rmesa->hw.tex[1].
+                        cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04)
+                     == 0))
+                   || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_3_ENABLE)
+                       &&
+                       ((((rmesa->hw.tex[3].
+                           cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+                         0x04) == 0))
+                   || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_5_ENABLE)
+                       &&
+                       ((((rmesa->hw.tex[5].
+                           cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+                         0x04) == 0))) {
+                       dbg |= 0x04;
+               }
+
+               if (dbg != rmesa->hw.tam.cmd[TAM_DEBUG3]) {
+                       R300_STATECHANGE(rmesa, tam);
+                       rmesa->hw.tam.cmd[TAM_DEBUG3] = dbg;
+                       if (0)
+                               printf("TEXCACHE LRU HANG WORKAROUND %x\n",
+                                      dbg);
+               }
+       }
+       #endif
+}