st/nine: Rewrite Managed texture uploads

That part of the code was quite obscure.
This new implementation tries to make it clearer
by separating the differents parts, and commenting more.

Signed-off-by: Axel Davy <axel.davy@ens.fr>
This commit is contained in:
Axel Davy 2015-02-19 19:34:02 +01:00
parent 090ebc7638
commit b45fa97a22
1 changed files with 135 additions and 106 deletions

View File

@ -163,7 +163,8 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
{ {
HRESULT hr; HRESULT hr;
unsigned last_level = This->base.info.last_level; unsigned last_level = This->base.info.last_level;
unsigned l; unsigned l, min_level_dirty = This->managed.lod;
BOOL update_lod;
DBG("This=%p dirty=%i type=%s\n", This, This->managed.dirty, DBG("This=%p dirty=%i type=%s\n", This, This->managed.dirty,
nine_D3DRTYPE_to_str(This->base.type)); nine_D3DRTYPE_to_str(This->base.type));
@ -173,7 +174,14 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
last_level = 0; /* TODO: What if level 0 is not resident ? */ last_level = 0; /* TODO: What if level 0 is not resident ? */
if (This->managed.lod_resident != This->managed.lod) { update_lod = This->managed.lod_resident != This->managed.lod;
if (!update_lod && !This->managed.dirty)
return D3D_OK;
/* Allocate a new resource with the correct number of levels,
* Mark states for update, and tell the nine surfaces/volumes
* their new resource. */
if (update_lod) {
struct pipe_resource *res; struct pipe_resource *res;
DBG("updating LOD from %u to %u ...\n", This->managed.lod_resident, This->managed.lod); DBG("updating LOD from %u to %u ...\n", This->managed.lod_resident, This->managed.lod);
@ -192,51 +200,35 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
state->changed.group |= NINE_STATE_TEXTURE; state->changed.group |= NINE_STATE_TEXTURE;
} }
/* Allocate a new resource */
hr = NineBaseTexture9_CreatePipeResource(This, This->managed.lod_resident != -1); hr = NineBaseTexture9_CreatePipeResource(This, This->managed.lod_resident != -1);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
res = This->base.resource; res = This->base.resource;
if (This->managed.lod_resident == -1) /* no levels were resident */ if (This->managed.lod_resident == -1) {/* no levels were resident */
This->managed.dirty = FALSE; /* We are going to upload everything. */
This->managed.lod_resident = This->base.info.last_level + 1; This->managed.lod_resident = This->base.info.last_level + 1;
}
if (This->base.type == D3DRTYPE_TEXTURE) { if (This->base.type == D3DRTYPE_TEXTURE) {
struct NineTexture9 *tex = NineTexture9(This); struct NineTexture9 *tex = NineTexture9(This);
struct pipe_box box;
/* Mark uninitialized levels as dirty. */ /* last content (if apply) has been copied to the new resource.
box.x = box.y = box.z = 0; * Note: We cannot render to surfaces of managed textures.
box.depth = 1; * Note2: the level argument passed is to get the level offset
for (l = This->managed.lod; l < This->managed.lod_resident; ++l) { * right when the texture is uploaded (the texture first level
box.width = u_minify(This->base.info.width0, l); * corresponds to This->managed.lod).
box.height = u_minify(This->base.info.height0, l); * Note3: We don't care about the value passed for the surfaces
NineSurface9_AddDirtyRect(tex->surfaces[l], &box); * before This->managed.lod, negative with this implementation. */
} for (l = 0; l <= This->base.info.last_level; ++l)
for (l = 0; l < This->managed.lod; ++l)
NineSurface9_SetResource(tex->surfaces[l], NULL, -1);
for (; l <= This->base.info.last_level; ++l)
NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod); NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod);
} else } else
if (This->base.type == D3DRTYPE_CUBETEXTURE) { if (This->base.type == D3DRTYPE_CUBETEXTURE) {
struct NineCubeTexture9 *tex = NineCubeTexture9(This); struct NineCubeTexture9 *tex = NineCubeTexture9(This);
struct pipe_box box;
unsigned z; unsigned z;
/* Mark uninitialized levels as dirty. */ for (l = 0; l <= This->base.info.last_level; ++l) {
box.x = box.y = box.z = 0;
box.depth = 1;
for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
box.width = u_minify(This->base.info.width0, l);
box.height = u_minify(This->base.info.height0, l);
for (z = 0; z < 6; ++z)
NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box);
}
for (l = 0; l < This->managed.lod; ++l) {
for (z = 0; z < 6; ++z)
NineSurface9_SetResource(tex->surfaces[l * 6 + z],
NULL, -1);
}
for (; l <= This->base.info.last_level; ++l) {
for (z = 0; z < 6; ++z) for (z = 0; z < 6; ++z)
NineSurface9_SetResource(tex->surfaces[l * 6 + z], NineSurface9_SetResource(tex->surfaces[l * 6 + z],
res, l - This->managed.lod); res, l - This->managed.lod);
@ -244,31 +236,20 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
} else } else
if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
struct pipe_box box;
/* Mark uninitialized levels as dirty. */ for (l = 0; l <= This->base.info.last_level; ++l)
box.x = box.y = box.z = 0;
for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
box.width = u_minify(This->base.info.width0, l);
box.height = u_minify(This->base.info.height0, l);
box.depth = u_minify(This->base.info.depth0, l);
NineVolume9_AddDirtyRegion(tex->volumes[l], &box);
}
for (l = 0; l < This->managed.lod; ++l)
NineVolume9_SetResource(tex->volumes[l], NULL, -1);
for (; l <= This->base.info.last_level; ++l)
NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod); NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod);
} else { } else {
assert(!"invalid texture type"); assert(!"invalid texture type");
} }
if (This->managed.lod < This->managed.lod_resident) /* We are going to fully upload the new levels,
This->managed.dirty = TRUE; * no need to update dirty parts of the texture for these */
This->managed.lod_resident = This->managed.lod; min_level_dirty = MAX2(This->managed.lod, This->managed.lod_resident);
} }
if (!This->managed.dirty)
return D3D_OK;
/* Update dirty parts of the texture */
if (This->managed.dirty) {
if (This->base.type == D3DRTYPE_TEXTURE) { if (This->base.type == D3DRTYPE_TEXTURE) {
struct NineTexture9 *tex = NineTexture9(This); struct NineTexture9 *tex = NineTexture9(This);
struct pipe_box box; struct pipe_box box;
@ -279,11 +260,11 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
tex->dirty_rect.x, tex->dirty_rect.y, tex->dirty_rect.x, tex->dirty_rect.y,
tex->dirty_rect.width, tex->dirty_rect.height); tex->dirty_rect.width, tex->dirty_rect.height);
/* Note: for l < This->managed.lod, the resource is /* Note: for l < min_level_dirty, the resource is
* non-existing, and thus will be entirely re-uploaded * either non-existing (and thus will be entirely re-uploaded
* if This->managed.lod changes */ * if the lod changes) or going to have a full upload */
if (tex->dirty_rect.width) { if (tex->dirty_rect.width) {
for (l = This->managed.lod; l <= last_level; ++l) { for (l = min_level_dirty; l <= last_level; ++l) {
u_box_minify_2d(&box, &tex->dirty_rect, l); u_box_minify_2d(&box, &tex->dirty_rect, l);
NineSurface9_UploadSelf(tex->surfaces[l], &box); NineSurface9_UploadSelf(tex->surfaces[l], &box);
} }
@ -304,7 +285,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
tex->dirty_rect[z].width, tex->dirty_rect[z].height); tex->dirty_rect[z].width, tex->dirty_rect[z].height);
if (tex->dirty_rect[z].width) { if (tex->dirty_rect[z].width) {
for (l = This->managed.lod; l <= last_level; ++l) { for (l = min_level_dirty; l <= last_level; ++l) {
u_box_minify_2d(&box, &tex->dirty_rect[z], l); u_box_minify_2d(&box, &tex->dirty_rect[z], l);
NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box); NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);
} }
@ -328,12 +309,60 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
} }
memset(&tex->dirty_box, 0, sizeof(tex->dirty_box)); memset(&tex->dirty_box, 0, sizeof(tex->dirty_box));
} }
for (l = This->managed.lod; l <= last_level; ++l) for (l = min_level_dirty; l <= last_level; ++l)
NineVolume9_UploadSelf(tex->volumes[l]); NineVolume9_UploadSelf(tex->volumes[l]);
} else { } else {
assert(!"invalid texture type"); assert(!"invalid texture type");
} }
This->managed.dirty = FALSE; This->managed.dirty = FALSE;
}
/* Upload the new levels */
if (update_lod) {
if (This->base.type == D3DRTYPE_TEXTURE) {
struct NineTexture9 *tex = NineTexture9(This);
struct pipe_box box;
box.x = box.y = box.z = 0;
box.depth = 1;
for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
box.width = u_minify(This->base.info.width0, l);
box.height = u_minify(This->base.info.height0, l);
NineSurface9_UploadSelf(tex->surfaces[l], &box);
}
} else
if (This->base.type == D3DRTYPE_CUBETEXTURE) {
struct NineCubeTexture9 *tex = NineCubeTexture9(This);
struct pipe_box box;
unsigned z;
box.x = box.y = box.z = 0;
box.depth = 1;
for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
box.width = u_minify(This->base.info.width0, l);
box.height = u_minify(This->base.info.height0, l);
for (z = 0; z < 6; ++z)
NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);
}
} else
if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
struct pipe_box box;
box.x = box.y = box.z = 0;
for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
box.width = u_minify(This->base.info.width0, l);
box.height = u_minify(This->base.info.height0, l);
box.depth = u_minify(This->base.info.depth0, l);
NineVolume9_AddDirtyRegion(tex->volumes[l], &box);
NineVolume9_UploadSelf(tex->volumes[l]);
}
} else {
assert(!"invalid texture type");
}
This->managed.lod_resident = This->managed.lod;
}
if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
This->dirty_mip = TRUE; This->dirty_mip = TRUE;