From 35fe920e1ec877d487e5dd33c9aea7e1ec1dbe11 Mon Sep 17 00:00:00 2001 From: Axel Davy Date: Thu, 19 Feb 2015 11:21:12 +0100 Subject: [PATCH] st/nine: Rework texture data allocation 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 Signed-off-by: Axel Davy --- src/gallium/state_trackers/nine/cubetexture9.c | 46 ++++++++++++++++++----- src/gallium/state_trackers/nine/cubetexture9.h | 1 + src/gallium/state_trackers/nine/nine_pipe.h | 41 +++++++++++++++++++++ src/gallium/state_trackers/nine/surface9.c | 51 ++++++++++++++------------ src/gallium/state_trackers/nine/surface9.h | 1 - src/gallium/state_trackers/nine/texture9.c | 27 +++++++++++++- src/gallium/state_trackers/nine/texture9.h | 1 + 7 files changed, 131 insertions(+), 37 deletions(-) diff --git a/src/gallium/state_trackers/nine/cubetexture9.c b/src/gallium/state_trackers/nine/cubetexture9.c index d81cc70..f64764c 100644 --- a/src/gallium/state_trackers/nine/cubetexture9.c +++ b/src/gallium/state_trackers/nine/cubetexture9.c @@ -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); } diff --git a/src/gallium/state_trackers/nine/cubetexture9.h b/src/gallium/state_trackers/nine/cubetexture9.h index e8594d3..ee7e275 100644 --- a/src/gallium/state_trackers/nine/cubetexture9.h +++ b/src/gallium/state_trackers/nine/cubetexture9.h @@ -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 ) diff --git a/src/gallium/state_trackers/nine/nine_pipe.h b/src/gallium/state_trackers/nine/nine_pipe.h index b8e728e..1b88612 100644 --- a/src/gallium/state_trackers/nine/nine_pipe.h +++ b/src/gallium/state_trackers/nine/nine_pipe.h @@ -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_ */ diff --git a/src/gallium/state_trackers/nine/surface9.c b/src/gallium/state_trackers/nine/surface9.c index f1b4aa9..e202f87 100644 --- a/src/gallium/state_trackers/nine/surface9.c +++ b/src/gallium/state_trackers/nine/surface9.c @@ -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); diff --git a/src/gallium/state_trackers/nine/surface9.h b/src/gallium/state_trackers/nine/surface9.h index 32e1722..7d6932a 100644 --- a/src/gallium/state_trackers/nine/surface9.h +++ b/src/gallium/state_trackers/nine/surface9.h @@ -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 */ diff --git a/src/gallium/state_trackers/nine/texture9.c b/src/gallium/state_trackers/nine/texture9.c index 78a632f..536d631 100644 --- a/src/gallium/state_trackers/nine/texture9.c +++ b/src/gallium/state_trackers/nine/texture9.c @@ -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); } diff --git a/src/gallium/state_trackers/nine/texture9.h b/src/gallium/state_trackers/nine/texture9.h index 5e37a12..65db874 100644 --- a/src/gallium/state_trackers/nine/texture9.h +++ b/src/gallium/state_trackers/nine/texture9.h @@ -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 ) -- 2.7.4