enable cube maps on radeon (#2241 on bugzilla). No vtxfmt code yet (just generates...
authorRoland Scheidegger <rscheidegger@gmx.ch>
Sat, 15 Oct 2005 23:45:53 +0000 (23:45 +0000)
committerRoland Scheidegger <rscheidegger@gmx.ch>
Sat, 15 Oct 2005 23:45:53 +0000 (23:45 +0000)
14 files changed:
docs/VERSIONS
src/mesa/drivers/dri/radeon/radeon_context.c
src/mesa/drivers/dri/radeon/radeon_context.h
src/mesa/drivers/dri/radeon/radeon_ioctl.c
src/mesa/drivers/dri/radeon/radeon_maos_arrays.c
src/mesa/drivers/dri/radeon/radeon_maos_verts.c
src/mesa/drivers/dri/radeon/radeon_screen.c
src/mesa/drivers/dri/radeon/radeon_screen.h
src/mesa/drivers/dri/radeon/radeon_state.c
src/mesa/drivers/dri/radeon/radeon_state_init.c
src/mesa/drivers/dri/radeon/radeon_swtcl.c
src/mesa/drivers/dri/radeon/radeon_tex.c
src/mesa/drivers/dri/radeon/radeon_texmem.c
src/mesa/drivers/dri/radeon/radeon_texstate.c

index 315fd3ddbc64119542bec2ab319be216628c95a7..58ec9edff25549b56189e89e4479aa6cc82c4b61 100644 (file)
@@ -1383,6 +1383,7 @@ Mesa Version History
        - GL_EXT_timer_query extension
        - r200: add support for GL_ATI_fragment_shader
        - added fast XOR-mode line drawing optimization
+       - radeon: add support for all 3 tmus and cube maps
     Changes:
        - removed GL_HP_occlusion_test (use GL_ARB_occlusion_query instead)
     Bug fixes:
index 9ab6e676780ade9d3648b551bedfd36348768aec..a1e3582415c338816e2e715239f2265f8dddde0d 100644 (file)
@@ -69,7 +69,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define need_GL_EXT_secondary_color
 #include "extension_helper.h"
 
-#define DRIVER_DATE    "20051008"
+#define DRIVER_DATE    "20051013"
 
 #include "vblank.h"
 #include "utils.h"
@@ -338,7 +338,7 @@ radeonCreateContext( const __GLcontextModes *glVisual,
                                 4,
                                 11, /* max 2D texture size is 2048x2048 */
                                 0,  /* 3D textures unsupported. */
-                                0,  /* cube textures unsupported. */
+                                9,  /* \todo: max cube texture size seems to be 512x512(x6) */
                                 11, /* max rect texture size is 2048x2048. */
                                 12,
                                 GL_FALSE );
@@ -412,6 +412,8 @@ radeonCreateContext( const __GLcontextModes *glVisual,
    }
 
    driInitExtensions( ctx, card_extensions, GL_TRUE );
+   if (rmesa->radeonScreen->drmSupportsCubeMaps)
+      _mesa_enable_extension( ctx, "GL_ARB_texture_cube_map" );
    if (rmesa->glCtx->Mesa_DXTn) {
       _mesa_enable_extension( ctx, "GL_EXT_texture_compression_s3tc" );
       _mesa_enable_extension( ctx, "GL_S3_s3tc" );
index 09bb96861ee61ab7c3ef739223e8be9e82cb1282..d6dc9c46ed49363a66f4fe6e21e5baf34a5a5b38 100644 (file)
@@ -264,6 +264,16 @@ struct radeon_state_atom {
 #define TXR_PP_TEX_PITCH            2 /* 0x1d08, 0x1d10 for NPOT! */
 #define TXR_STATE_SIZE              3
 
+#define CUBE_CMD_0                  0
+#define CUBE_PP_CUBIC_FACES         1
+#define CUBE_CMD_1                  2
+#define CUBE_PP_CUBIC_OFFSET_0      3
+#define CUBE_PP_CUBIC_OFFSET_1      4
+#define CUBE_PP_CUBIC_OFFSET_2      5
+#define CUBE_PP_CUBIC_OFFSET_3      6
+#define CUBE_PP_CUBIC_OFFSET_4      7
+#define CUBE_STATE_SIZE             8
+
 #define ZBS_CMD_0              0
 #define ZBS_SE_ZBIAS_FACTOR             1
 #define ZBS_SE_ZBIAS_CONSTANT           2
@@ -415,6 +425,7 @@ struct radeon_hw_state {
    struct radeon_state_atom tcl;
    struct radeon_state_atom msc;
    struct radeon_state_atom tex[3];
+   struct radeon_state_atom cube[3];
    struct radeon_state_atom zbs;
    struct radeon_state_atom mtl; 
    struct radeon_state_atom mat[6];
index 1cf5340b9cb66cb1ea79e10f197b06f6a3327344..37a619c24506415bff73330957cbbe4de002a002 100644 (file)
@@ -152,6 +152,7 @@ void radeonSetUpAtomList( radeonContextPtr rmesa )
    for (i = 0; i < mtu; ++i) {
        insert_at_tail(&rmesa->hw.atomlist, &rmesa->hw.tex[i]);
        insert_at_tail(&rmesa->hw.atomlist, &rmesa->hw.txr[i]);
+       insert_at_tail(&rmesa->hw.atomlist, &rmesa->hw.cube[i]);
    }
    insert_at_tail(&rmesa->hw.atomlist, &rmesa->hw.zbs);
    insert_at_tail(&rmesa->hw.atomlist, &rmesa->hw.mtl);
index 1602464011ac50ddbb80d0013ab7a4e1f9af1ece..76ad1f3cd4bd45a96a962ad6359c451d1279b7cc 100644 (file)
@@ -542,13 +542,13 @@ void radeonEmitArrays( GLcontext *ctx, GLuint inputs )
          /* assume we need the 3rd coord if texgen is active for r/q OR at least
            3 coords are submitted. This may not be 100% correct */
          if (VB->TexCoordPtr[unit]->size >= 3) {
-        /* tcl_vtx and vc_frmt values are identical */
            vtx |= RADEON_Q_BIT(unit);
            vfmt |= RADEON_Q_BIT(unit);
         }
         if ( (ctx->Texture.Unit[unit].TexGenEnabled & (R_BIT | Q_BIT)) )
            vtx |= RADEON_Q_BIT(unit);
-        else if (VB->TexCoordPtr[unit]->size >= 3) {
+        else if ((VB->TexCoordPtr[unit]->size >= 3) &&
+                 ((ctx->Texture.Unit[unit]._ReallyEnabled & (TEXTURE_CUBE_BIT)) == 0)) {
            GLuint swaptexmatcol = (VB->TexCoordPtr[unit]->size - 3);
            if (((rmesa->NeedTexMatrix >> unit) & 1) &&
                 (swaptexmatcol != ((rmesa->TexMatColSwap >> unit) & 1)))
index 57aa90321cf59eb65669e38683caa6a964f0880a..24e681c8c09c5fb1702ba1c0448405db2befdb17 100644 (file)
@@ -352,7 +352,8 @@ void radeonEmitArrays( GLcontext *ctx, GLuint inputs )
         }
         if ( (ctx->Texture.Unit[unit].TexGenEnabled & (R_BIT | Q_BIT)) )
            vtx |= RADEON_Q_BIT(unit);
-        else if (VB->TexCoordPtr[unit]->size >= 3) {
+        else if ((VB->TexCoordPtr[unit]->size >= 3) &&
+                 ((ctx->Texture.Unit[unit]._ReallyEnabled & (TEXTURE_CUBE_BIT)) == 0)) {
            GLuint swaptexmatcol = (VB->TexCoordPtr[unit]->size - 3);
            if (((rmesa->NeedTexMatrix >> unit) & 1) &&
                 (swaptexmatcol != ((rmesa->TexMatColSwap >> unit) & 1)))
index c79f406f68acaadfed414a93164b713c0a130e47..9a552c2c1205f3fc9d0b98c32027d8cea9aa435f 100644 (file)
@@ -262,6 +262,7 @@ radeonCreateScreen( __DRIscreenPrivate *sPriv )
            fprintf(stderr, "drm_radeon_getparam_t (RADEON_PARAM_IRQ_NR): %d\n", ret);
            return NULL;
         }
+        screen->drmSupportsCubeMaps = (sPriv->drmMinor >= 15);
       }
    }
 
index b9cbeaac3354f889b5233140511e75a90d468792..0bf88d98416187afb8eeda484317dcf75cdbd2eb 100644 (file)
@@ -98,6 +98,7 @@ typedef struct {
 
    /* Configuration cache with default values for all contexts */
    driOptionCache optionCache;
+   GLboolean drmSupportsCubeMaps;
 } radeonScreenRec, *radeonScreenPtr;
 
 #endif /* __RADEON_SCREEN_H__ */
index a79fefee502d926d17228f6a09c59675a3d9a178..28033881c5ee3d98347601c677e285ed9642509d 100644 (file)
@@ -2098,7 +2098,6 @@ void radeonUploadTexMatrix( radeonContextPtr rmesa,
       }
    }
    else {
-      /* never used currently - no swapping needed at all presumably */
       for (i = 0 ; i < 4 ; i++) {
         *dest++ = src[i];
         *dest++ = src[i+4];
index 7e7dc0f7823fa03b2634bf0cd00c22ce22a2c88a..6e538a29732fc7ef7009a353e7db96ef4ec6333a 100644 (file)
@@ -113,9 +113,14 @@ static GLboolean check_##NM( GLcontext *ctx )              \
 
 
 CHECK( always, GL_TRUE )
+CHECK( never, GL_FALSE )
 CHECK( tex0, ctx->Texture.Unit[0]._ReallyEnabled )
 CHECK( tex1, ctx->Texture.Unit[1]._ReallyEnabled )
-CHECK( tex2, ctx->Texture.Unit[2]._ReallyEnabled )
+/* need this for the cubic_map on disabled unit 2 bug, maybe r100 only? */
+CHECK( tex2, ctx->Texture._EnabledUnits )
+CHECK( cube0, (ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_CUBE_BIT))
+CHECK( cube1, (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_CUBE_BIT))
+CHECK( cube2, (ctx->Texture.Unit[2]._ReallyEnabled & TEXTURE_CUBE_BIT))
 CHECK( fog, ctx->Fog.Enabled )
 TCL_CHECK( tcl, GL_TRUE )
 TCL_CHECK( tcl_tex0, ctx->Texture.Unit[0]._ReallyEnabled )
@@ -233,6 +238,18 @@ void radeonInitState( radeonContextPtr rmesa )
    ALLOC_STATE( tex[0], tex0, TEX_STATE_SIZE, "TEX/tex-0", 0 );
    ALLOC_STATE( tex[1], tex1, TEX_STATE_SIZE, "TEX/tex-1", 0 );
    ALLOC_STATE( tex[2], tex2, TEX_STATE_SIZE, "TEX/tex-2", 0 );
+   if (rmesa->radeonScreen->drmSupportsCubeMaps)
+   {
+      ALLOC_STATE( cube[0], cube0, CUBE_STATE_SIZE, "CUBE/cube-0", 0 );
+      ALLOC_STATE( cube[1], cube1, CUBE_STATE_SIZE, "CUBE/cube-1", 0 );
+      ALLOC_STATE( cube[2], cube2, CUBE_STATE_SIZE, "CUBE/cube-2", 0 );
+   }
+   else
+   {
+      ALLOC_STATE( cube[0], never, CUBE_STATE_SIZE, "CUBE/cube-0", 0 );
+      ALLOC_STATE( cube[1], never, CUBE_STATE_SIZE, "CUBE/cube-1", 0 );
+      ALLOC_STATE( cube[2], never, CUBE_STATE_SIZE, "CUBE/cube-2", 0 );
+   }
    ALLOC_STATE( mat[0], tcl, MAT_STATE_SIZE, "MAT/modelproject", 1 );
    ALLOC_STATE( mat[1], tcl_eyespace_or_fog, MAT_STATE_SIZE, "MAT/modelview", 1 );
    ALLOC_STATE( mat[2], tcl_eyespace_or_lighting, MAT_STATE_SIZE, "MAT/it-modelview", 1 );
@@ -277,6 +294,12 @@ void radeonInitState( radeonContextPtr rmesa )
    rmesa->hw.tex[1].cmd[TEX_CMD_1] = cmdpkt(RADEON_EMIT_PP_BORDER_COLOR_1);
    rmesa->hw.tex[2].cmd[TEX_CMD_0] = cmdpkt(RADEON_EMIT_PP_TXFILTER_2);
    rmesa->hw.tex[2].cmd[TEX_CMD_1] = cmdpkt(RADEON_EMIT_PP_BORDER_COLOR_2);
+   rmesa->hw.cube[0].cmd[CUBE_CMD_0] = cmdpkt(RADEON_EMIT_PP_CUBIC_FACES_0);
+   rmesa->hw.cube[0].cmd[CUBE_CMD_1] = cmdpkt(RADEON_EMIT_PP_CUBIC_OFFSETS_T0);
+   rmesa->hw.cube[1].cmd[CUBE_CMD_0] = cmdpkt(RADEON_EMIT_PP_CUBIC_FACES_1);
+   rmesa->hw.cube[1].cmd[CUBE_CMD_1] = cmdpkt(RADEON_EMIT_PP_CUBIC_OFFSETS_T1);
+   rmesa->hw.cube[2].cmd[CUBE_CMD_0] = cmdpkt(RADEON_EMIT_PP_CUBIC_FACES_2);
+   rmesa->hw.cube[2].cmd[CUBE_CMD_1] = cmdpkt(RADEON_EMIT_PP_CUBIC_OFFSETS_T2);
    rmesa->hw.zbs.cmd[ZBS_CMD_0] = cmdpkt(RADEON_EMIT_SE_ZBIAS_FACTOR);
    rmesa->hw.tcl.cmd[TCL_CMD_0] = cmdpkt(RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT);
    rmesa->hw.mtl.cmd[MTL_CMD_0] = 
@@ -488,6 +511,18 @@ void radeonInitState( radeonContextPtr rmesa )
           RADEON_SCALE_1X |
           RADEON_CLAMP_TX);
       rmesa->hw.tex[i].cmd[TEX_PP_TFACTOR] = 0;
+
+      rmesa->hw.cube[i].cmd[CUBE_PP_CUBIC_FACES] = 0;
+      rmesa->hw.cube[i].cmd[CUBE_PP_CUBIC_OFFSET_0] =
+         rmesa->radeonScreen->texOffset[RADEON_LOCAL_TEX_HEAP];
+      rmesa->hw.cube[i].cmd[CUBE_PP_CUBIC_OFFSET_1] =
+         rmesa->radeonScreen->texOffset[RADEON_LOCAL_TEX_HEAP];
+      rmesa->hw.cube[i].cmd[CUBE_PP_CUBIC_OFFSET_2] =
+         rmesa->radeonScreen->texOffset[RADEON_LOCAL_TEX_HEAP];
+      rmesa->hw.cube[i].cmd[CUBE_PP_CUBIC_OFFSET_3] =
+         rmesa->radeonScreen->texOffset[RADEON_LOCAL_TEX_HEAP];
+      rmesa->hw.cube[i].cmd[CUBE_PP_CUBIC_OFFSET_4] =
+         rmesa->radeonScreen->texOffset[RADEON_LOCAL_TEX_HEAP];
    }
 
    /* Can only add ST1 at the time of doing some multitex but can keep
index 7200f71ef6b04f24e04b2cc2d878870f44525472..7a97cf0ce60cabf75492347420d82d92a7051f8e 100644 (file)
@@ -184,13 +184,18 @@ static void radeonSetVertexFormat( GLcontext *ctx )
            switch (sz) {
            case 1:
            case 2:
-           case 3:
               EMIT_ATTR( _TNL_ATTRIB_TEX0+i, EMIT_2F,
                          radeon_cp_vc_frmts[i][0] );
               break;
+           case 3:
            case 4:
-              EMIT_ATTR( _TNL_ATTRIB_TEX0+i, EMIT_3F_XYW,
-                         radeon_cp_vc_frmts[i][1] );
+              if (ctx->Texture.Unit[i]._ReallyEnabled & (TEXTURE_CUBE_BIT) ) {
+                 EMIT_ATTR( _TNL_ATTRIB_TEX0+i, EMIT_3F,
+                            radeon_cp_vc_frmts[i][1] );
+              } else {
+                 EMIT_ATTR( _TNL_ATTRIB_TEX0+i, EMIT_3F_XYW,
+                            radeon_cp_vc_frmts[i][1] );
+              }
               break;
            default:
               continue;
index c466af868c4981ba79553763914a8b31e57121d0..46ca86bde266662b0381c5b15ed64d8c5b19d985 100644 (file)
@@ -174,7 +174,24 @@ static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
 
    t->pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK);
 
-   if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) {
+   /* r100 chips can't handle mipmaps/aniso for cubemap/volume textures */
+   if ( t->base.tObj->Target == GL_TEXTURE_CUBE_MAP ) {
+      switch ( minf ) {
+      case GL_NEAREST:
+      case GL_NEAREST_MIPMAP_NEAREST:
+      case GL_NEAREST_MIPMAP_LINEAR:
+        t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
+        break;
+      case GL_LINEAR:
+      case GL_LINEAR_MIPMAP_NEAREST:
+      case GL_LINEAR_MIPMAP_LINEAR:
+        t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
+        break;
+      default:
+        break;
+      }
+   }
+   else if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) {
       switch ( minf ) {
       case GL_NEAREST:
         t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
@@ -774,7 +791,7 @@ static void radeonBindTexture( GLcontext *ctx, GLenum target,
    }
 
    assert( (target != GL_TEXTURE_1D && target != GL_TEXTURE_2D &&
-            target != GL_TEXTURE_RECTANGLE_NV) ||
+            target != GL_TEXTURE_RECTANGLE_NV && target != GL_TEXTURE_CUBE_MAP) ||
            (texObj->DriverData != NULL) );
 }
 
index 3943afcde0bdf694864316a54cfb725879bd3c3c..e2766713b2f7a6f2ebc6ae356971aa28e2b361c4 100644 (file)
@@ -67,7 +67,6 @@ radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
       for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ ) {
         if ( t == rmesa->state.texture.unit[i].texobj ) {
            rmesa->state.texture.unit[i].texobj = NULL;
-           rmesa->hw.tex[i].dirty = GL_FALSE;
         }
       }
    }
@@ -226,7 +225,7 @@ static void uploadSubImage( radeonContextPtr rmesa, radeonTexObjPtr t,
    imageWidth = texImage->Width;
    imageHeight = texImage->Height;
 
-   offset = t->bufAddr;
+   offset = t->bufAddr + t->base.totalSize * face / 6;
 
    if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
       GLint imageX = 0;
index fe5445bf62635185062b18d4c4f9a4c524bb9870..ccf08850c2adf240629fabd1648c0b825ed990d8 100644 (file)
@@ -153,7 +153,13 @@ static void radeonSetTexImages( radeonContextPtr rmesa,
    /* Compute which mipmap levels we really want to send to the hardware.
     */
 
-   driCalculateTextureFirstLastLevel( (driTextureObject *) t );
+   if (tObj->Target != GL_TEXTURE_CUBE_MAP)
+      driCalculateTextureFirstLastLevel( (driTextureObject *) t );
+   else {
+      /* r100 can't handle mipmaps for cube/3d textures, so don't waste
+         memory for them */
+      t->base.firstLevel = t->base.lastLevel = tObj->BaseLevel;
+   }
    log2Width  = tObj->Image[0][t->base.firstLevel]->WidthLog2;
    log2Height = tObj->Image[0][t->base.firstLevel]->HeightLog2;
    log2Depth  = tObj->Image[0][t->base.firstLevel]->DepthLog2;
@@ -284,6 +290,22 @@ static void radeonSetTexImages( radeonContextPtr rmesa,
     */
    t->base.totalSize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
 
+   /* Setup remaining cube face blits, if needed */
+   if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
+      const GLuint faceSize = t->base.totalSize;
+      GLuint face;
+      /* reuse face 0 x/y/width/height - just update the offset when uploading */
+      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;
+            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->pp_txfilter &= ~RADEON_MAX_MIP_LEVEL_MASK;
@@ -291,10 +313,27 @@ static void radeonSetTexImages( radeonContextPtr rmesa,
 
    t->pp_txformat &= ~(RADEON_TXFORMAT_WIDTH_MASK |
                       RADEON_TXFORMAT_HEIGHT_MASK |
-                       RADEON_TXFORMAT_CUBIC_MAP_ENABLE);
+                       RADEON_TXFORMAT_CUBIC_MAP_ENABLE |
+                       RADEON_TXFORMAT_F5_WIDTH_MASK |
+                       RADEON_TXFORMAT_F5_HEIGHT_MASK);
    t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_WIDTH_SHIFT) |
                      (log2Height << RADEON_TXFORMAT_HEIGHT_SHIFT));
 
+   if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
+      assert(log2Width == log2Height);
+      t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_F5_WIDTH_SHIFT) |
+                         (log2Height << RADEON_TXFORMAT_F5_HEIGHT_SHIFT) |
+                         (RADEON_TXFORMAT_CUBIC_MAP_ENABLE));
+      t->pp_cubic_faces = ((log2Width << RADEON_FACE_WIDTH_1_SHIFT) |
+                           (log2Height << RADEON_FACE_HEIGHT_1_SHIFT) |
+                           (log2Width << RADEON_FACE_WIDTH_2_SHIFT) |
+                           (log2Height << RADEON_FACE_HEIGHT_2_SHIFT) |
+                           (log2Width << RADEON_FACE_WIDTH_3_SHIFT) |
+                           (log2Height << RADEON_FACE_HEIGHT_3_SHIFT) |
+                           (log2Width << RADEON_FACE_WIDTH_4_SHIFT) |
+                           (log2Height << RADEON_FACE_HEIGHT_4_SHIFT));
+   }
+
    t->pp_txsize = (((tObj->Image[0][t->base.firstLevel]->Width - 1) << 0) |
                    ((tObj->Image[0][t->base.firstLevel]->Height - 1) << 16));
 
@@ -816,15 +855,33 @@ static void import_tex_obj_state( radeonContextPtr rmesa,
    cmd[TEX_PP_TXFORMAT] |= texobj->pp_txformat & TEXOBJ_TXFORMAT_MASK;
    cmd[TEX_PP_TXOFFSET] = texobj->pp_txoffset;
    cmd[TEX_PP_BORDER_COLOR] = texobj->pp_border_color;
-   RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[unit] );
 
-   if (texobj->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
+   if (texobj->base.tObj->Target == GL_TEXTURE_CUBE_MAP) {
+      GLuint *cube_cmd = RADEON_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;
+      /* dont know if this setup conforms to OpenGL.. 
+       * at least it matches the behavior of mesa software renderer
+       */
+      cube_cmd[CUBE_PP_CUBIC_OFFSET_0] = texobj->pp_txoffset; /* right */
+      cube_cmd[CUBE_PP_CUBIC_OFFSET_1] = texobj->pp_txoffset + 1 * bytesPerFace; /* left */
+      cube_cmd[CUBE_PP_CUBIC_OFFSET_2] = texobj->pp_txoffset + 2 * bytesPerFace; /* top */
+      cube_cmd[CUBE_PP_CUBIC_OFFSET_3] = texobj->pp_txoffset + 3 * bytesPerFace; /* bottom */
+      cube_cmd[CUBE_PP_CUBIC_OFFSET_4] = texobj->pp_txoffset + 4 * bytesPerFace; /* front */
+      RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.cube[unit] );
+      cmd[TEX_PP_TXOFFSET] = texobj->pp_txoffset + 5 * bytesPerFace; /* back */
+   }
+   else if (texobj->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
       GLuint *txr_cmd = RADEON_DB_STATE( txr[unit] );
       txr_cmd[TXR_PP_TEX_SIZE] = texobj->pp_txsize; /* NPOT only! */
       txr_cmd[TXR_PP_TEX_PITCH] = texobj->pp_txpitch; /* NPOT only! */
       RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.txr[unit] );
    }
 
+   RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[unit] );
+
    texobj->dirty_state &= ~(1<<unit);
 }
 
@@ -1002,7 +1059,14 @@ static void disable_tex( GLcontext *ctx, int unit )
         rmesa->recheck_texgen[unit] = GL_TRUE;
       }
 
-
+      if (rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT] & RADEON_TXFORMAT_CUBIC_MAP_ENABLE) {
+      /* this seems to be a genuine (r100 only?) hw bug. Need to remove the
+         cubic_map bit on unit 2 when the unit is disabled, otherwise every
+        2nd (2d) mipmap on unit 0 will be broken (may not be needed for other
+        units, better be safe than sorry though).*/
+        RADEON_STATECHANGE( rmesa, tex[unit] );
+        rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT] &= ~RADEON_TXFORMAT_CUBIC_MAP_ENABLE;
+      }
 
       {
         GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4;
@@ -1050,6 +1114,48 @@ static GLboolean enable_tex_2d( GLcontext *ctx, int unit )
    return GL_TRUE;
 }
 
+static GLboolean enable_tex_cube( GLcontext *ctx, int unit )
+{
+   radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+   struct gl_texture_object *tObj = texUnit->_Current;
+   radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData;
+   GLuint face;
+
+   /* Need to load the 2d images associated with this unit.
+    */
+   if (t->pp_txformat & RADEON_TXFORMAT_NON_POWER2) {
+      t->pp_txformat &= ~RADEON_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 */
+      RADEON_FIREVERTICES( rmesa );
+      /* layout memory space, once for all faces */
+      radeonSetTexImages( rmesa, tObj );
+   }
+
+   /* upload (per face) */
+   for (face = 0; face < 6; face++) {
+      if (t->base.dirty_images[face]) {
+         radeonUploadTexImages( rmesa, (radeonTexObjPtr) 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 )
 {
    radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
@@ -1167,6 +1273,10 @@ static GLboolean radeonUpdateTextureUnit( GLcontext *ctx, int unit )
       return (enable_tex_2d( ctx, unit ) &&
              update_tex_common( ctx, unit ));
    }
+   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;
    }