st/nine: Support ATI1/ATI2 for CubeTexture
[mesa.git] / src / gallium / state_trackers / nine / cubetexture9.c
index d81cc70f659cce0c23ba6063c477dfb583870ee6..03b5fcad60ec064e4cb40db2aeb0e0d0b274f1ab 100644 (file)
@@ -20,6 +20,8 @@
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
 
+#include "c99_alloca.h"
+
 #include "device9.h"
 #include "cubetexture9.h"
 #include "nine_helpers.h"
@@ -40,8 +42,10 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
     struct pipe_resource *info = &This->base.base.info;
     struct pipe_screen *screen = pParams->device->screen;
     enum pipe_format pf;
-    unsigned i;
+    unsigned i, l, f, offset, face_size = 0;
+    unsigned *level_offsets = NULL;
     D3DSURFACE_DESC sfdesc;
+    void *p;
     HRESULT hr;
 
     DBG("This=%p pParams=%p EdgeLength=%u Levels=%u Usage=%d "
@@ -49,11 +53,14 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
         This, pParams, EdgeLength, Levels, Usage,
         Format, Pool, pSharedHandle);
 
-    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
-                (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL);
+    user_assert(EdgeLength, D3DERR_INVALIDCALL);
 
+    /* user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); */
     user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */
 
+    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
+                (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL);
+
     if (Usage & D3DUSAGE_AUTOGENMIPMAP)
         Levels = 0;
 
@@ -62,9 +69,12 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
     if (pf == PIPE_FORMAT_NONE)
         return D3DERR_INVALIDCALL;
 
-    /* We support ATI1 and ATI2 hacks only for 2D textures */
-    if (Format == D3DFMT_ATI1 || Format == D3DFMT_ATI2)
-        return D3DERR_INVALIDCALL;
+    if (compressed_format(Format)) {
+        const unsigned w = util_format_get_blockwidth(pf);
+        const unsigned h = util_format_get_blockheight(pf);
+
+        user_assert(!(EdgeLength % w) && !(EdgeLength % h), D3DERR_INVALIDCALL);
+    }
 
     info->screen = pParams->device->screen;
     info->target = PIPE_TEXTURE_CUBE;
@@ -97,6 +107,16 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
         DBG("Application asked for Software Vertex Processing, "
             "but this is unimplemented\n");
 
+    if (Pool != D3DPOOL_DEFAULT) {
+        level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
+        face_size = nine_format_get_size_and_offsets(pf, level_offsets,
+                                                     EdgeLength, EdgeLength,
+                                                     info->last_level);
+        This->managed_buffer = align_malloc(6 * face_size, 32);
+        if (!This->managed_buffer)
+            return E_OUTOFMEMORY;
+    }
+
     This->surfaces = CALLOC(6 * (info->last_level + 1), sizeof(*This->surfaces));
     if (!This->surfaces)
         return E_OUTOFMEMORY;
@@ -117,18 +137,31 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
     sfdesc.Pool = Pool;
     sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
     sfdesc.MultiSampleQuality = 0;
-    for (i = 0; i < (info->last_level + 1) * 6; ++i) {
-        sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, i / 6);
-
-        hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
-                              This->base.base.resource, NULL, D3DRTYPE_CUBETEXTURE,
-                              i / 6, i % 6,
-                              &sfdesc, &This->surfaces[i]);
-        if (FAILED(hr))
-            return hr;
+    /* We allocate the memory for the surfaces as continous blocks.
+     * This is the expected behaviour, however we haven't tested for
+     * cube textures in which order the faces/levels should be in memory
+     */
+    for (f = 0; f < 6; f++) {
+        offset = f * face_size;
+        for (l = 0; l <= info->last_level; l++) {
+            sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, l);
+            p = This->managed_buffer ? This->managed_buffer + offset +
+                    level_offsets[l] : NULL;
+
+            hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
+                                  This->base.base.resource, p, D3DRTYPE_CUBETEXTURE,
+                                  l, f, &sfdesc, &This->surfaces[f + 6 * l]);
+            if (FAILED(hr))
+                return hr;
+        }
     }
-    for (i = 0; i < 6; ++i) /* width = 0 means empty, depth stays 1 */
+
+    for (i = 0; i < 6; ++i) {
+        /* Textures start initially dirty */
+        This->dirty_rect[i].width = EdgeLength;
+        This->dirty_rect[i].height = EdgeLength;
         This->dirty_rect[i].depth = 1;
+    }
 
     return D3D_OK;
 }
@@ -146,6 +179,9 @@ NineCubeTexture9_dtor( struct NineCubeTexture9 *This )
         FREE(This->surfaces);
     }
 
+    if (This->managed_buffer)
+        align_free(This->managed_buffer);
+
     NineBaseTexture9_dtor(&This->base);
 }
 
@@ -233,13 +269,17 @@ NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This,
     user_assert(FaceType < 6, D3DERR_INVALIDCALL);
 
     if (This->base.base.pool != D3DPOOL_MANAGED) {
-        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP)
+        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) {
             This->base.dirty_mip = TRUE;
+            BASETEX_REGISTER_UPDATE(&This->base);
+        }
         return D3D_OK;
     }
-    This->base.dirty = TRUE;
 
-    BASETEX_REGISTER_UPDATE(&This->base);
+    if (This->base.base.pool == D3DPOOL_MANAGED) {
+        This->base.managed.dirty = TRUE;
+        BASETEX_REGISTER_UPDATE(&This->base);
+    }
 
     if (!pDirtyRect) {
         u_box_origin_2d(This->base.base.info.width0,
@@ -250,6 +290,10 @@ NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This,
         rect_to_pipe_box_clamp(&box, pDirtyRect);
         u_box_union_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType],
                        &box);
+        (void) u_box_clip_2d(&This->dirty_rect[FaceType],
+                             &This->dirty_rect[FaceType],
+                             This->base.base.info.width0,
+                             This->base.base.info.height0);
     }
     return D3D_OK;
 }