HRESULT NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) { HRESULT hr; unsigned last_level = This->base.info.last_level; unsigned l, min_level_dirty = This->managed.lod; BOOL update_lod; DBG("This=%p dirty=%i type=%s\n", This, This->managed.dirty, nine_D3DRTYPE_to_str(This->base.type)); assert(This->base.pool == D3DPOOL_MANAGED); if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) last_level = 0; 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; DBG("updating LOD from %u to %u ...\n", This->managed.lod_resident, This->managed.lod); pipe_sampler_view_reference(&This->view[0], NULL); pipe_sampler_view_reference(&This->view[1], NULL); /* Allocate a new resource */ hr = NineBaseTexture9_CreatePipeResource(This, This->managed.lod_resident != -1); if (FAILED(hr)) return hr; res = This->base.resource; 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; } if (This->base.type == D3DRTYPE_TEXTURE) { struct NineTexture9 *tex = NineTexture9(This); /* last content (if apply) has been copied to the new resource. * Note: We cannot render to surfaces of managed textures. * Note2: the level argument passed is to get the level offset * right when the texture is uploaded (the texture first level * corresponds to This->managed.lod). * Note3: We don't care about the value passed for the surfaces * before This->managed.lod, negative with this implementation. */ for (l = 0; l <= This->base.info.last_level; ++l) NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod); } else if (This->base.type == D3DRTYPE_CUBETEXTURE) { struct NineCubeTexture9 *tex = NineCubeTexture9(This); unsigned z; for (l = 0; l <= This->base.info.last_level; ++l) { for (z = 0; z < 6; ++z) NineSurface9_SetResource(tex->surfaces[l * 6 + z], res, l - This->managed.lod); } } else if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); for (l = 0; l <= This->base.info.last_level; ++l) NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod); } else { assert(!"invalid texture type"); } /* We are going to fully upload the new levels, * no need to update dirty parts of the texture for these */ min_level_dirty = MAX2(This->managed.lod, This->managed.lod_resident); } /* Update dirty parts of the texture */ if (This->managed.dirty) { if (This->base.type == D3DRTYPE_TEXTURE) { struct NineTexture9 *tex = NineTexture9(This); struct pipe_box box; box.z = 0; box.depth = 1; DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n", tex->dirty_rect.x, tex->dirty_rect.y, tex->dirty_rect.width, tex->dirty_rect.height); /* Note: for l < min_level_dirty, the resource is * either non-existing (and thus will be entirely re-uploaded * if the lod changes) or going to have a full upload */ if (tex->dirty_rect.width) { for (l = min_level_dirty; l <= last_level; ++l) { u_box_minify_2d(&box, &tex->dirty_rect, l); NineSurface9_UploadSelf(tex->surfaces[l], &box); } memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect)); tex->dirty_rect.depth = 1; } } else if (This->base.type == D3DRTYPE_CUBETEXTURE) { struct NineCubeTexture9 *tex = NineCubeTexture9(This); unsigned z; struct pipe_box box; box.z = 0; box.depth = 1; for (z = 0; z < 6; ++z) { DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z, tex->dirty_rect[z].x, tex->dirty_rect[z].y, tex->dirty_rect[z].width, tex->dirty_rect[z].height); if (tex->dirty_rect[z].width) { for (l = min_level_dirty; l <= last_level; ++l) { u_box_minify_2d(&box, &tex->dirty_rect[z], l); NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box); } memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z])); tex->dirty_rect[z].depth = 1; } } } else if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); struct pipe_box box; DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n", tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y, tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth); if (tex->dirty_box.width) { for (l = min_level_dirty; l <= last_level; ++l) { u_box_minify_3d(&box, &tex->dirty_box, l); NineVolume9_UploadSelf(tex->volumes[l], &box); } memset(&tex->dirty_box, 0, sizeof(tex->dirty_box)); } } else { assert(!"invalid texture type"); } 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_UploadSelf(tex->volumes[l], &box); } } else { assert(!"invalid texture type"); } This->managed.lod_resident = This->managed.lod; } if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) This->dirty_mip = TRUE; /* Set again the textures currently bound to update the texture data */ if (This->bind_count) { struct nine_state *state = &This->base.base.device->state; unsigned s; for (s = 0; s < NINE_MAX_SAMPLERS; ++s) /* Dirty tracking is done in device9 state, not nine_context. */ if (state->texture[s] == This) nine_context_set_texture(This->base.base.device, s, This); } DBG("DONE, generate mip maps = %i\n", This->dirty_mip); return D3D_OK; }
HRESULT NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) { HRESULT hr; unsigned last_level = This->base.info.last_level; unsigned l; DBG("This=%p dirty=%i type=%s\n", This, This->dirty, nine_D3DRTYPE_to_str(This->base.type)); assert(This->base.pool == D3DPOOL_MANAGED); if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) last_level = 0; /* TODO: What if level 0 is not resident ? */ if (This->lod_resident != This->lod) { struct pipe_resource *res; DBG("updating LOD from %u to %u ...\n", This->lod_resident, This->lod); pipe_sampler_view_reference(&This->view[0], NULL); pipe_sampler_view_reference(&This->view[1], NULL); if (This->bind_count) { /* mark state dirty */ struct nine_state *state = &This->base.base.device->state; unsigned s; for (s = 0; s < NINE_MAX_SAMPLERS; ++s) if (state->texture[s] == This) state->changed.texture |= 1 << s; if (state->changed.texture) state->changed.group |= NINE_STATE_TEXTURE; } hr = NineBaseTexture9_CreatePipeResource(This, This->lod_resident != -1); if (FAILED(hr)) return hr; res = This->base.resource; if (This->lod_resident == -1) /* no levels were resident */ This->lod_resident = This->base.info.last_level + 1; if (This->base.type == D3DRTYPE_TEXTURE) { struct NineTexture9 *tex = NineTexture9(This); struct pipe_box box; /* Mark uninitialized levels as dirty. */ box.x = box.y = box.z = 0; box.depth = 1; for (l = This->lod; l < This->lod_resident; ++l) { box.width = u_minify(This->base.info.width0, l); box.height = u_minify(This->base.info.height0, l); NineSurface9_AddDirtyRect(tex->surfaces[l], &box); } for (l = 0; l < This->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->lod); } else if (This->base.type == D3DRTYPE_CUBETEXTURE) { struct NineCubeTexture9 *tex = NineCubeTexture9(This); struct pipe_box box; unsigned z; /* Mark uninitialized levels as dirty. */ box.x = box.y = box.z = 0; box.depth = 1; for (l = This->lod; l < This->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->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) NineSurface9_SetResource(tex->surfaces[l * 6 + z], res, l - This->lod); } } else if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); struct pipe_box box; /* Mark uninitialized levels as dirty. */ box.x = box.y = box.z = 0; for (l = This->lod; l < This->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->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->lod); } else { assert(!"invalid texture type"); } if (This->lod < This->lod_resident) This->dirty = TRUE; This->lod_resident = This->lod; } if (!This->dirty) return D3D_OK; if (This->base.type == D3DRTYPE_TEXTURE) { struct NineTexture9 *tex = NineTexture9(This); struct pipe_box box; box.z = 0; box.depth = 1; DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n", tex->dirty_rect.x, tex->dirty_rect.y, tex->dirty_rect.width, tex->dirty_rect.height); if (tex->dirty_rect.width) { for (l = 0; l <= last_level; ++l) { u_box_minify_2d(&box, &tex->dirty_rect, l); NineSurface9_AddDirtyRect(tex->surfaces[l], &box); } memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect)); tex->dirty_rect.depth = 1; } for (l = This->lod; l <= last_level; ++l) NineSurface9_UploadSelf(tex->surfaces[l]); } else if (This->base.type == D3DRTYPE_CUBETEXTURE) { struct NineCubeTexture9 *tex = NineCubeTexture9(This); unsigned z; struct pipe_box box; box.z = 0; box.depth = 1; for (z = 0; z < 6; ++z) { DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z, tex->dirty_rect[z].x, tex->dirty_rect[z].y, tex->dirty_rect[z].width, tex->dirty_rect[z].height); if (tex->dirty_rect[z].width) { for (l = 0; l <= last_level; ++l) { u_box_minify_2d(&box, &tex->dirty_rect[z], l); NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box); } memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z])); tex->dirty_rect[z].depth = 1; } for (l = This->lod; l <= last_level; ++l) NineSurface9_UploadSelf(tex->surfaces[l * 6 + z]); } } else if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); struct pipe_box box; DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n", tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y, tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth); if (tex->dirty_box.width) { for (l = 0; l <= last_level; ++l) { u_box_minify_2d(&box, &tex->dirty_box, l); NineVolume9_AddDirtyRegion(tex->volumes[l], &tex->dirty_box); } memset(&tex->dirty_box, 0, sizeof(tex->dirty_box)); } for (l = This->lod; l <= last_level; ++l) NineVolume9_UploadSelf(tex->volumes[l]); } else { assert(!"invalid texture type"); } This->dirty = FALSE; if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) This->dirty_mip = TRUE; /* TODO: if dirty only because of lod change, only generate added levels */ DBG("DONE, generate mip maps = %i\n", This->dirty_mip); return D3D_OK; }