From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d/command.c | 186 ++++++++++++++++++++++++++++++++++++++++--- tests/d3d12.c | 4 +- 2 files changed, 177 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 1e3c58d7c..faa0c891b 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -4065,6 +4065,47 @@ static bool vkd3d_initialise_tile_region(struct vkd3d_resource_tile_coordinate * return true; }
+static bool d3d12_tiled_resource_coordinate_normalise(const struct vkd3d_resource_tile_coordinate *base_coordinate, + const D3D12_TILE_REGION_SIZE *region_extent, D3D12_TILED_RESOURCE_COORDINATE *coordinate) +{ + unsigned int carry; + + /* This should compile branchless on most hardware. */ + carry = coordinate->X >= base_coordinate->x + region_extent->Width; + coordinate->Y += carry; + coordinate->X -= region_extent->Width & -carry; + + carry = coordinate->Y >= base_coordinate->y + region_extent->Height; + coordinate->Z += carry; + coordinate->Y -= region_extent->Height & -carry; + + carry = coordinate->Z >= base_coordinate->z + region_extent->Depth; + coordinate->Subresource += carry; + coordinate->Z -= region_extent->Depth & -carry; + + return carry; +} + +static void vk_offset_convert_tiles_to_texels(VkOffset3D *offset, const VkExtent3D *tile_extent) +{ + offset->x *= tile_extent->width; + offset->y *= tile_extent->height; + offset->z *= tile_extent->depth; +} + +static void d3d12_resource_get_vk_subresource(const struct d3d12_resource *resource, unsigned int subresource, + VkImageSubresource *vk_subresource) +{ + const struct vkd3d_format *format = resource->format; + const D3D12_RESOURCE_DESC1 *desc = &resource->desc; + + assert(format->plane_count == 1); + + vk_subresource->mipLevel = subresource % desc->MipLevels; + vk_subresource->arrayLayer = subresource / desc->MipLevels; + vk_subresource->aspectMask = format->vk_aspect_mask; +} + static void STDMETHODCALLTYPE d3d12_command_list_CopyTiles(ID3D12GraphicsCommandList5 *iface, ID3D12Resource *tiled_resource, const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate, const D3D12_TILE_REGION_SIZE *tile_region_size, ID3D12Resource *buffer, UINT64 buffer_offset, @@ -6614,6 +6655,61 @@ free_clones: update_mappings_cleanup(&update_mappings); }
+static unsigned int vkd3d_set_sparse_image_bind_region(VkSparseImageMemoryBind *memory_bind, + const struct vkd3d_resource_tile_coordinate *base_coordinate, + D3D12_TILED_RESOURCE_COORDINATE *coordinate, + const D3D12_TILE_REGION_SIZE *region_extent, const struct d3d12_resource *resource, + unsigned int memory_tile_count) +{ + unsigned int height, depth, remaining, max_tile_count, tile_count, layer_stride; + VkOffset3D *offset = &memory_bind->offset; + VkExtent3D *extent = &memory_bind->extent; + bool partial_x, partial_y; + + max_tile_count = min(region_extent->NumTiles, memory_tile_count); + tile_count = max_tile_count; + partial_x = coordinate->X > base_coordinate->x; + partial_y = coordinate->Y > base_coordinate->y; + + offset->x = coordinate->X; + offset->y = coordinate->Y; + offset->z = coordinate->Z; + + /* Grab the largest possible width */ + remaining = region_extent->Width - (coordinate->X - base_coordinate->x); + extent->width = min(remaining, tile_count); + coordinate->X += extent->width; + tile_count -= extent->width; + extent->height = 1; + extent->depth = 1; + if (d3d12_tiled_resource_coordinate_normalise(base_coordinate, region_extent, coordinate) + || partial_x || !tile_count || !(height = tile_count / region_extent->Width)) + goto done; + + /* Expand the height */ + remaining = region_extent->Height - (coordinate->Y - base_coordinate->y); + remaining = min(remaining, height); + extent->height += remaining; + coordinate->Y += remaining; + tile_count -= region_extent->Width * remaining; + if (d3d12_tiled_resource_coordinate_normalise(base_coordinate, region_extent, coordinate) + || partial_y || !tile_count + || !(depth = tile_count / (layer_stride = region_extent->Width * region_extent->Height))) + goto done; + + /* Expand the depth */ + remaining = region_extent->Depth - (coordinate->Z - base_coordinate->z); + remaining = min(remaining, depth); + extent->depth += remaining; + coordinate->Z += remaining; + tile_count -= layer_stride * remaining; + + d3d12_tiled_resource_coordinate_normalise(base_coordinate, region_extent, coordinate); + +done: + return max_tile_count - tile_count; +} + static void deaggregate_sparse_memory_bind(VkSparseBufferMemoryBindInfo *buffer_bind_info, const VkSparseMemoryBind *src, unsigned int tile_count, struct d3d12_resource *resource) { @@ -6632,12 +6728,47 @@ static void deaggregate_sparse_memory_bind(VkSparseBufferMemoryBindInfo *buffer_ buffer_bind_info->bindCount += tile_count; }
+static void deaggregate_sparse_image_memory_bind(VkSparseImageMemoryBindInfo *image_bind_info, + const VkSparseImageMemoryBind *src, struct d3d12_resource *resource) +{ + const VkExtent3D *tile_extent = &resource->tiles.tile_extent; + VkSparseImageMemoryBind *image_memory_binds; + unsigned int i, x, y, z, tile_count; + + image_memory_binds = (VkSparseImageMemoryBind *)image_bind_info->pBinds + image_bind_info->bindCount; + tile_count = src->extent.width * src->extent.height * src->extent.depth; + + for (z = 0, i = 0; z < src->extent.depth; ++z) + { + for (y = 0; y < src->extent.height; ++y) + { + for (x = 0; x < src->extent.width; ++x, ++i) + { + image_memory_binds[i].subresource = src->subresource; + image_memory_binds[i].offset.x = src->offset.x + x; + image_memory_binds[i].offset.y = src->offset.y + y; + image_memory_binds[i].offset.z = src->offset.z + z; + vk_offset_convert_tiles_to_texels(&image_memory_binds[i].offset, tile_extent); + image_memory_binds[i].extent.width = tile_extent->width; + image_memory_binds[i].extent.height = tile_extent->height; + image_memory_binds[i].extent.depth = tile_extent->depth; + image_memory_binds[i].memory = src->memory; + image_memory_binds[i].memoryOffset = src->memoryOffset + i * D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; + image_memory_binds[i].flags = src->flags; + } + } + } + + image_bind_info->bindCount += tile_count; +} + static unsigned int vkd3d_queue_bind_sparse_block(VkBindSparseInfo *sparse_info, struct d3d12_resource *resource, const struct vkd3d_resource_tile_coordinate *base_coordinate, D3D12_TILED_RESOURCE_COORDINATE *coordinate, const D3D12_TILE_REGION_SIZE *region_size, VkDeviceMemory vk_memory, unsigned int memory_offset, unsigned int memory_tile_count, bool skip_binding) { unsigned int subresource = coordinate->Subresource; + VkSparseImageMemoryBind image_memory_bind; VkSparseMemoryBind memory_bind; unsigned int tiles_used;
@@ -6675,7 +6806,21 @@ static unsigned int vkd3d_queue_bind_sparse_block(VkBindSparseInfo *sparse_info, } else { - vkd3d_unreachable(); + d3d12_resource_get_vk_subresource(resource, subresource, &image_memory_bind.subresource); + + tiles_used = vkd3d_set_sparse_image_bind_region(&image_memory_bind, + base_coordinate, coordinate, region_size, resource, memory_tile_count); + + if (skip_binding || !tiles_used) + return tiles_used; + + image_memory_bind.memory = vk_memory; + image_memory_bind.memoryOffset = memory_offset * D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; + image_memory_bind.flags = 0; + + /* NVIDIA bug (see above).*/ + deaggregate_sparse_image_memory_bind((VkSparseImageMemoryBindInfo *)sparse_info->pImageBinds, + &image_memory_bind, resource); }
return tiles_used; @@ -6694,12 +6839,13 @@ static void d3d12_command_queue_update_tile_mappings(struct d3d12_command_queue { const struct vkd3d_vk_device_procs *vk_procs = &command_queue->device->vk_procs; bool null_binding, aliased_binding, skip_binding, have_unsupported_aliasing; + unsigned int memory_offset, memory_tile_count, tiles_used, subresource; VkDeviceMemory vk_memory = heap ? heap->vk_memory : VK_NULL_HANDLE; - unsigned int memory_offset, memory_tile_count, tiles_used; struct vkd3d_resource_tile_coordinate base_coordinate; struct d3d12_device *device = command_queue->device; D3D12_TILED_RESOURCE_COORDINATE coordinate_zero; VkSparseBufferMemoryBindInfo buffer_bind_info; + VkSparseImageMemoryBindInfo image_bind_info; D3D12_TILE_REGION_SIZE region_size_default; D3D12_TILED_RESOURCE_COORDINATE coordinate; D3D12_TILE_REGION_SIZE region_size; @@ -6710,12 +6856,6 @@ static void d3d12_command_queue_update_tile_mappings(struct d3d12_command_queue unsigned int tile_count_all; VkResult vr;
- if (d3d12_resource_is_texture(resource)) - { - FIXME("Tiled textures are not implemented yet.\n"); - return; - } - if (region_count == 1) { if (!region_sizes) @@ -6747,6 +6887,7 @@ static void d3d12_command_queue_update_tile_mappings(struct d3d12_command_queue if (!vkd3d_initialise_tile_region(&base_coordinate, ®ion_size, &coordinate, ®ion_sizes[0], resource)) return;
+ subresource = coordinate.Subresource; region_idx = 0; range_idx = 0; null_binding = false; @@ -6765,16 +6906,25 @@ static void d3d12_command_queue_update_tile_mappings(struct d3d12_command_queue if (heap) vkd3d_mutex_lock(&heap->mutex);
- buffer_bind_info.buffer = resource->u.vk_buffer; buffer_bind_info.bindCount = 0; buffer_bind_info.pBinds = resource->tiles.bind_buffer; + image_bind_info.bindCount = 0; + image_bind_info.pBinds = resource->tiles.bind_buffer; + memset(&sparse_info, 0, sizeof(sparse_info)); sparse_info.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; - sparse_info.bufferBindCount = 1; sparse_info.pBufferBinds = &buffer_bind_info; + sparse_info.pImageBinds = &image_bind_info;
do { + if (coordinate.Subresource != subresource) + { + if ((subresource = coordinate.Subresource) >= resource->tiles.subresource_count) + break; + d3d12_tile_region_size_set_entire_subresource(®ion_size, resource, subresource); + } + if (range_flags) { cur_flags = range_flags[range_idx]; @@ -6824,8 +6974,22 @@ static void d3d12_command_queue_update_tile_mappings(struct d3d12_command_queue if (heap) vkd3d_mutex_unlock(&heap->mutex);
- if (!buffer_bind_info.bindCount) + if (buffer_bind_info.bindCount) + { + buffer_bind_info.buffer = resource->u.vk_buffer; + sparse_info.bufferBindCount = 1; + sparse_info.pImageBinds = NULL; + } + else if (image_bind_info.bindCount) + { + image_bind_info.image = resource->u.vk_image; + sparse_info.imageBindCount = 1; + sparse_info.pBufferBinds = NULL; + } + else + { return; + }
if (have_unsupported_aliasing) FIXME("Aliased bindings are not implemented.\n"); diff --git a/tests/d3d12.c b/tests/d3d12.c index ee0bc1006..42dbb18b1 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -39114,7 +39114,7 @@ static void test_update_tile_mappings(void) for (i = 0; i < j; i++) { set_box(&box, i, 0, 0, i + 1, 1, 1); - todo_if(i < packed_mip_info.StartTileIndexInOverallResource) check_readback_data_uint(&rb.rb, &box, i + 1, 0); + check_readback_data_uint(&rb.rb, &box, i + 1, 0); }
release_resource_readback(&rb); @@ -39210,7 +39210,7 @@ static void test_update_tile_mappings(void) for (i = 0; i < j; i++) { set_box(&box, i, 0, 0, i + 1, 1, 1); - todo_if(i < packed_mip_info.StartTileIndexInOverallResource && texture_region_tiles[i]) + todo_if(i == 6 || i == 7 || i == 9 || i == 11 || i == 16) check_readback_data_uint(&rb.rb, &box, texture_region_tiles[i], 0); }