HRESULT NineVolume9_CopyVolume( struct NineVolume9 *This, struct NineVolume9 *From, unsigned dstx, unsigned dsty, unsigned dstz, struct pipe_box *pSrcBox ) { struct pipe_context *pipe = This->pipe; struct pipe_resource *r_dst = This->resource; struct pipe_resource *r_src = From->resource; struct pipe_transfer *transfer; struct pipe_box src_box; struct pipe_box dst_box; uint8_t *p_dst; const uint8_t *p_src; DBG("This=%p From=%p dstx=%u dsty=%u dstz=%u pSrcBox=%p\n", This, From, dstx, dsty, dstz, pSrcBox); assert(This->desc.Pool != D3DPOOL_MANAGED && From->desc.Pool != D3DPOOL_MANAGED); user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL); dst_box.x = dstx; dst_box.y = dsty; dst_box.z = dstz; if (pSrcBox) { /* make sure it doesn't range outside the source volume */ user_assert(pSrcBox->x >= 0 && (pSrcBox->width - pSrcBox->x) <= From->desc.Width && pSrcBox->y >= 0 && (pSrcBox->height - pSrcBox->y) <= From->desc.Height && pSrcBox->z >= 0 && (pSrcBox->depth - pSrcBox->z) <= From->desc.Depth, D3DERR_INVALIDCALL); src_box = *pSrcBox; } else { src_box.x = 0; src_box.y = 0; src_box.z = 0; src_box.width = From->desc.Width; src_box.height = From->desc.Height; src_box.depth = From->desc.Depth; } /* limits */ dst_box.width = This->desc.Width - dst_box.x; dst_box.height = This->desc.Height - dst_box.y; dst_box.depth = This->desc.Depth - dst_box.z; user_assert(src_box.width <= dst_box.width && src_box.height <= dst_box.height && src_box.depth <= dst_box.depth, D3DERR_INVALIDCALL); dst_box.width = src_box.width; dst_box.height = src_box.height; dst_box.depth = src_box.depth; if (r_dst && r_src) { pipe->resource_copy_region(pipe, r_dst, This->level, dst_box.x, dst_box.y, dst_box.z, r_src, From->level, &src_box); } else if (r_dst) { p_src = NineVolume9_GetSystemMemPointer(From, src_box.x, src_box.y, src_box.z); pipe->transfer_inline_write(pipe, r_dst, This->level, 0, /* WRITE|DISCARD are implicit */ &dst_box, p_src, From->stride, From->layer_stride); } else if (r_src) { p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0); p_src = pipe->transfer_map(pipe, r_src, From->level, PIPE_TRANSFER_READ, &src_box, &transfer); if (!p_src) return D3DERR_DRIVERINTERNALERROR; util_copy_box(p_dst, This->info.format, This->stride, This->layer_stride, dst_box.x, dst_box.y, dst_box.z, dst_box.width, dst_box.height, dst_box.depth, p_src, transfer->stride, transfer->layer_stride, src_box.x, src_box.y, src_box.z); pipe->transfer_unmap(pipe, transfer); } else { p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0); p_src = NineVolume9_GetSystemMemPointer(From, 0, 0, 0); util_copy_box(p_dst, This->info.format, This->stride, This->layer_stride, dst_box.x, dst_box.y, dst_box.z, dst_box.width, dst_box.height, dst_box.depth, p_src, From->stride, From->layer_stride, src_box.x, src_box.y, src_box.z); } if (This->desc.Pool == D3DPOOL_DEFAULT) NineVolume9_MarkContainerDirty(This); if (!r_dst && This->resource) NineVolume9_AddDirtyRegion(This, &dst_box); return D3D_OK; }
HRESULT NINE_WINAPI NineVolume9_LockBox( struct NineVolume9 *This, D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags ) { struct pipe_resource *resource = This->resource; struct pipe_box box; unsigned usage; DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n", This, This->base.container, pLockedVolume, pBox, pBox ? pBox->Left : 0, pBox ? pBox->Right : 0, pBox ? pBox->Top : 0, pBox ? pBox->Bottom : 0, pBox ? pBox->Front : 0, pBox ? pBox->Back : 0, nine_D3DLOCK_to_str(Flags)); /* check if it's already locked */ user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); /* set pBits to NULL after lock_count check */ user_assert(pLockedVolume, E_POINTER); pLockedVolume->pBits = NULL; user_assert(This->desc.Pool != D3DPOOL_DEFAULT || (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL); user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), D3DERR_INVALIDCALL); if (pBox && compressed_format (This->desc.Format)) { /* For volume all pools are checked */ const unsigned w = util_format_get_blockwidth(This->info.format); const unsigned h = util_format_get_blockheight(This->info.format); user_assert((pBox->Left == 0 && pBox->Right == This->desc.Width && pBox->Top == 0 && pBox->Bottom == This->desc.Height) || (!(pBox->Left % w) && !(pBox->Right % w) && !(pBox->Top % h) && !(pBox->Bottom % h)), D3DERR_INVALIDCALL); } if (Flags & D3DLOCK_DISCARD) { usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; } else { usage = (Flags & D3DLOCK_READONLY) ? PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE; } if (Flags & D3DLOCK_DONOTWAIT) usage |= PIPE_TRANSFER_DONTBLOCK; if (pBox) { user_assert(pBox->Right > pBox->Left, D3DERR_INVALIDCALL); user_assert(pBox->Bottom > pBox->Top, D3DERR_INVALIDCALL); user_assert(pBox->Back > pBox->Front, D3DERR_INVALIDCALL); user_assert(pBox->Right <= This->desc.Width, D3DERR_INVALIDCALL); user_assert(pBox->Bottom <= This->desc.Height, D3DERR_INVALIDCALL); user_assert(pBox->Back <= This->desc.Depth, D3DERR_INVALIDCALL); d3dbox_to_pipe_box(&box, pBox); if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) { DBG("Locked volume intersection empty.\n"); return D3DERR_INVALIDCALL; } } else { u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth, &box); } if (This->data_conversion) { /* For now we only have uncompressed formats here */ pLockedVolume->RowPitch = This->stride_conversion; pLockedVolume->SlicePitch = This->layer_stride_conversion; pLockedVolume->pBits = This->data_conversion + box.z * This->layer_stride_conversion + box.y * This->stride_conversion + util_format_get_stride(This->format_conversion, box.x); } else if (This->data) { pLockedVolume->RowPitch = This->stride; pLockedVolume->SlicePitch = This->layer_stride; pLockedVolume->pBits = NineVolume9_GetSystemMemPointer(This, box.x, box.y, box.z); } else { pLockedVolume->pBits = This->pipe->transfer_map(This->pipe, resource, This->level, usage, &box, &This->transfer); if (!This->transfer) { if (Flags & D3DLOCK_DONOTWAIT) return D3DERR_WASSTILLDRAWING; return D3DERR_DRIVERINTERNALERROR; } pLockedVolume->RowPitch = This->transfer->stride; pLockedVolume->SlicePitch = This->transfer->layer_stride; } if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { NineVolume9_MarkContainerDirty(This); NineVolume9_AddDirtyRegion(This, &box); } ++This->lock_count; return D3D_OK; }
HRESULT WINAPI NineVolume9_LockBox( struct NineVolume9 *This, D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags ) { struct pipe_resource *resource = This->resource; struct pipe_box box; unsigned usage; DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n", This, This->base.container, pLockedVolume, pBox, pBox ? pBox->Left : 0, pBox ? pBox->Right : 0, pBox ? pBox->Top : 0, pBox ? pBox->Bottom : 0, pBox ? pBox->Front : 0, pBox ? pBox->Back : 0, nine_D3DLOCK_to_str(Flags)); user_assert(This->desc.Pool != D3DPOOL_DEFAULT || (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL); user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), D3DERR_INVALIDCALL); user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); user_assert(pLockedVolume, E_POINTER); if (pBox && This->desc.Pool == D3DPOOL_DEFAULT && util_format_is_compressed(This->info.format)) { const unsigned w = util_format_get_blockwidth(This->info.format); const unsigned h = util_format_get_blockheight(This->info.format); user_assert(!(pBox->Left % w) && !(pBox->Right % w) && !(pBox->Top % h) && !(pBox->Bottom % h), D3DERR_INVALIDCALL); } if (Flags & D3DLOCK_DISCARD) { usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; } else { usage = (Flags & D3DLOCK_READONLY) ? PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE; } if (Flags & D3DLOCK_DONOTWAIT) usage |= PIPE_TRANSFER_DONTBLOCK; if (pBox) { d3dbox_to_pipe_box(&box, pBox); if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) { DBG("Locked volume intersection empty.\n"); return D3DERR_INVALIDCALL; } } else { u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth, &box); } if (This->data) { pLockedVolume->RowPitch = This->stride; pLockedVolume->SlicePitch = This->layer_stride; pLockedVolume->pBits = NineVolume9_GetSystemMemPointer(This, box.x, box.y, box.z); } else { pLockedVolume->pBits = This->pipe->transfer_map(This->pipe, resource, This->level, usage, &box, &This->transfer); if (!This->transfer) { if (Flags & D3DLOCK_DONOTWAIT) return D3DERR_WASSTILLDRAWING; return D3DERR_DRIVERINTERNALERROR; } pLockedVolume->RowPitch = This->transfer->stride; pLockedVolume->SlicePitch = This->transfer->layer_stride; } if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { NineVolume9_MarkContainerDirty(This); if (This->desc.Pool == D3DPOOL_MANAGED) NineVolume9_AddDirtyRegion(This, &box); } ++This->lock_count; 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; }