st/nine: Rework texture data allocation
authorAxel Davy <axel.davy@ens.fr>
Thu, 19 Feb 2015 10:21:12 +0000 (11:21 +0100)
committerAxel Davy <axel.davy@ens.fr>
Wed, 29 Apr 2015 06:28:11 +0000 (08:28 +0200)
Some applications assume the memory for multilevel
textures is allocated per continuous blocks.

This patch implements that behaviour.

v2: cache offsets

Reviewed-by: Ilia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: Axel Davy <axel.davy@ens.fr>
src/gallium/state_trackers/nine/cubetexture9.c
src/gallium/state_trackers/nine/cubetexture9.h
src/gallium/state_trackers/nine/nine_pipe.h
src/gallium/state_trackers/nine/surface9.c
src/gallium/state_trackers/nine/surface9.h
src/gallium/state_trackers/nine/texture9.c
src/gallium/state_trackers/nine/texture9.h

index d81cc70f659cce0c23ba6063c477dfb583870ee6..f64764c6733f872afd2032aa37818373bfd629a1 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;
     D3DSURFACE_DESC sfdesc;
+    void *p;
     HRESULT hr;
 
     DBG("This=%p pParams=%p EdgeLength=%u Levels=%u Usage=%d "
@@ -97,6 +101,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 = MALLOC(6 * face_size);
+        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,16 +131,25 @@ 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 */
         This->dirty_rect[i].depth = 1;
 
@@ -146,6 +169,9 @@ NineCubeTexture9_dtor( struct NineCubeTexture9 *This )
         FREE(This->surfaces);
     }
 
+    if (This->managed_buffer)
+        FREE(This->managed_buffer);
+
     NineBaseTexture9_dtor(&This->base);
 }
 
index e8594d35bb454019eef03e5512a8a9e9f402f6f6..ee7e275e4d8a6adfbcca019eed2211f79070a61f 100644 (file)
@@ -31,6 +31,7 @@ struct NineCubeTexture9
     struct NineBaseTexture9 base;
     struct NineSurface9 **surfaces;
     struct pipe_box dirty_rect[6]; /* covers all mip levels */
+    uint8_t *managed_buffer;
 };
 static INLINE struct NineCubeTexture9 *
 NineCubeTexture9( void *data )
index b8e728eace9d0116ef971edc6debbb85b550aaef..1b88612f2ccc64372b440f90f9397d27770888b7 100644 (file)
@@ -673,4 +673,45 @@ d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE filter)
     }
 }
 
+static INLINE unsigned nine_format_get_stride(enum pipe_format format,
+                                              unsigned width)
+{
+    unsigned stride = util_format_get_stride(format, width);
+
+    return align(stride, 4);
+}
+
+static INLINE unsigned nine_format_get_level_alloc_size(enum pipe_format format,
+                                                        unsigned width,
+                                                        unsigned height,
+                                                        unsigned level)
+{
+    unsigned w, h, size;
+
+    w = u_minify(width, level);
+    h = u_minify(height, level);
+    size = nine_format_get_stride(format, w) *
+        util_format_get_nblocksy(format, h);
+    return size;
+}
+
+static INLINE unsigned nine_format_get_size_and_offsets(enum pipe_format format,
+                                                        unsigned *offsets,
+                                                        unsigned width,
+                                                        unsigned height,
+                                                        unsigned last_level)
+{
+    unsigned l, w, h, size = 0;
+
+    for (l = 0; l <= last_level; ++l) {
+        w = u_minify(width, l);
+        h = u_minify(height, l);
+        offsets[l] = size;
+        size += nine_format_get_stride(format, w) *
+            util_format_get_nblocksy(format, h);
+    }
+
+    return size;
+}
+
 #endif /* _NINE_PIPE_H_ */
index f1b4aa947ec00490f12a11a103c63bb3e9f532bf..e202f8707209affad0fa44ac63cb3a149b06a363 100644 (file)
@@ -62,10 +62,17 @@ NineSurface9_ctor( struct NineSurface9 *This,
     user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) ||
                 (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL);
 
-    assert(pResource ||
-           pDesc->Pool != D3DPOOL_DEFAULT || pDesc->Format == D3DFMT_NULL);
+    assert(pResource || (user_buffer && pDesc->Pool != D3DPOOL_DEFAULT) ||
+           (!pContainer && pDesc->Pool != D3DPOOL_DEFAULT) ||
+           pDesc->Format == D3DFMT_NULL);
 
     assert(!pResource || !user_buffer);
+    assert(!user_buffer || pDesc->Pool != D3DPOOL_DEFAULT);
+    /* The only way we can have !pContainer is being created
+     * from create_zs_or_rt_surface with params 0 0 0 */
+    assert(pContainer || (Level == 0 && Layer == 0 && TextureType == 0));
+
+    This->data = (uint8_t *)user_buffer;
 
     This->base.info.screen = pParams->device->screen;
     This->base.info.target = PIPE_TEXTURE_2D;
@@ -90,9 +97,20 @@ NineSurface9_ctor( struct NineSurface9 *This,
     if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL)
         This->base.info.bind |= PIPE_BIND_DEPTH_STENCIL;
 
+    /* Ram buffer with no parent. Has to allocate the resource itself */
+    if (!pResource && !pContainer) {
+        assert(!user_buffer);
+        This->data = MALLOC(
+            nine_format_get_level_alloc_size(This->base.info.format,
+                                             pDesc->Width,
+                                             pDesc->Height,
+                                             0));
+        if (!This->data)
+            return E_OUTOFMEMORY;
+    }
+
     if (pDesc->Pool == D3DPOOL_SYSTEMMEM) {
         This->base.info.usage = PIPE_USAGE_STAGING;
-        This->data = (uint8_t *)user_buffer; /* this is *pSharedHandle */
         assert(!pResource);
     } else {
         if (pResource && (pDesc->Usage & D3DUSAGE_DYNAMIC))
@@ -113,24 +131,10 @@ NineSurface9_ctor( struct NineSurface9 *This,
     This->layer = Layer;
     This->desc = *pDesc;
 
-    This->stride = util_format_get_stride(This->base.info.format, pDesc->Width);
-    This->stride = align(This->stride, 4);
-
-    if (!pResource && !This->data) {
-        const unsigned size = This->stride *
-            util_format_get_nblocksy(This->base.info.format, This->desc.Height);
+    This->stride = nine_format_get_stride(This->base.info.format, pDesc->Width);
 
-        DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n",
-            This->base.base.container, This, This->level, size);
-
-        This->data = (uint8_t *)MALLOC(size);
-        if (!This->data)
-            return E_OUTOFMEMORY;
-        This->manage_data = TRUE;
-    } else {
-        if (pResource && NineSurface9_IsOffscreenPlain(This))
-            pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; /* why setting this flag there ? too late ? should be before NineResource9_ctor call perhaps ? */
-    }
+    if (pResource && NineSurface9_IsOffscreenPlain(This))
+        pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
 
     NineSurface9_Dump(This);
 
@@ -147,8 +151,8 @@ NineSurface9_dtor( struct NineSurface9 *This )
     pipe_surface_reference(&This->surface[0], NULL);
     pipe_surface_reference(&This->surface[1], NULL);
 
-    /* release allocated system memory for non-D3DPOOL_DEFAULT resources */
-    if (This->manage_data && This->data)
+    /* Release system memory when we have to manage it (no parent) */
+    if (!This->base.base.container && This->data)
         FREE(This->data);
     NineResource9_dtor(&This->base);
 }
@@ -678,9 +682,8 @@ NineSurface9_SetResourceResize( struct NineSurface9 *This,
     This->desc.Height = This->base.info.height0 = resource->height0;
     This->desc.MultiSampleType = This->base.info.nr_samples = resource->nr_samples;
 
-    This->stride = util_format_get_stride(This->base.info.format,
+    This->stride = nine_format_get_stride(This->base.info.format,
                                           This->desc.Width);
-    This->stride = align(This->stride, 4);
 
     pipe_surface_reference(&This->surface[0], NULL);
     pipe_surface_reference(&This->surface[1], NULL);
index 32e17222f1094f8630bb6c0b635d5b62d8d5953e..7d6932a0f170f8f65ebabe9eab62616df4f4cc94 100644 (file)
@@ -48,7 +48,6 @@ struct NineSurface9
     D3DSURFACE_DESC desc;
 
     uint8_t *data; /* system memory backing */
-    boolean manage_data;
     unsigned stride; /* for system memory backing */
 
     /* wine doesn't even use these, 2 will be enough */
index 78a632f54ba347f437c8fedb260ef63449e845d2..536d631af4c0da45421b8873c936c2b887818906 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 "surface9.h"
 #include "texture9.h"
@@ -48,10 +50,11 @@ NineTexture9_ctor( struct NineTexture9 *This,
     struct pipe_resource *info = &This->base.base.info;
     struct pipe_resource *resource;
     enum pipe_format pf;
+    unsigned *level_offsets;
     unsigned l;
     D3DSURFACE_DESC sfdesc;
     HRESULT hr;
-    void *user_buffer = NULL;
+    void *user_buffer = NULL, *user_buffer_for_level;
 
     DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
         "pSharedHandle=%p\n", This, Width, Height, Levels,
@@ -138,6 +141,19 @@ NineTexture9_ctor( struct NineTexture9 *This,
 
     if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */
         user_buffer = (void *)*pSharedHandle;
+        level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
+        (void) nine_format_get_size_and_offsets(pf, level_offsets,
+                                                Width, Height,
+                                                info->last_level);
+    } else if (Pool != D3DPOOL_DEFAULT) {
+        level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
+        user_buffer = MALLOC(
+            nine_format_get_size_and_offsets(pf, level_offsets,
+                                             Width, Height,
+                                             info->last_level));
+        This->managed_buffer = user_buffer;
+        if (!This->managed_buffer)
+            return E_OUTOFMEMORY;
     }
 
     This->surfaces = CALLOC(info->last_level + 1, sizeof(*This->surfaces));
@@ -168,9 +184,13 @@ NineTexture9_ctor( struct NineTexture9 *This,
     for (l = 0; l <= info->last_level; ++l) {
         sfdesc.Width = u_minify(Width, l);
         sfdesc.Height = u_minify(Height, l);
+        /* Some apps expect the memory to be allocated in
+         * continous blocks */
+        user_buffer_for_level = user_buffer ? user_buffer +
+            level_offsets[l] : NULL;
 
         hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
-                              resource, user_buffer,
+                              resource, user_buffer_for_level,
                               D3DRTYPE_TEXTURE, l, 0,
                               &sfdesc, &This->surfaces[l]);
         if (FAILED(hr))
@@ -198,6 +218,9 @@ NineTexture9_dtor( struct NineTexture9 *This )
         FREE(This->surfaces);
     }
 
+    if (This->managed_buffer)
+        FREE(This->managed_buffer);
+
     NineBaseTexture9_dtor(&This->base);
 }
 
index 5e37a12cf4e462c2d7ea2e71e8c7ecc8965481fc..65db874b2a3fe5d3b8d02d466b204ddd74b3b559 100644 (file)
@@ -31,6 +31,7 @@ struct NineTexture9
     struct NineBaseTexture9 base;
     struct NineSurface9 **surfaces;
     struct pipe_box dirty_rect; /* covers all mip levels */
+    uint8_t *managed_buffer;
 };
 static INLINE struct NineTexture9 *
 NineTexture9( void *data )