From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d/command.c | 136 ++++++++++++++++++++++++++++++++++++++++++- libs/vkd3d/device.c | 7 --- tests/d3d12.c | 46 +++++++++++---- 3 files changed, 169 insertions(+), 20 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index d61ee7177..f149c64d1 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -4059,15 +4059,145 @@ static inline void vk_extent_convert_tiles_to_texels(VkExtent3D *extent, const V extent->depth *= tile_extent->depth; }
+static void d3d12_command_list_copy_texture_tiles(struct d3d12_command_list *list, + struct d3d12_resource *resource, const struct d3d12_resource *buffer, uint64_t buffer_offset, + const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate, + const D3D12_TILE_REGION_SIZE *tile_region_size, bool to_image) +{ + D3D12_TILED_RESOURCE_COORDINATE coordinate = *tile_region_start_coordinate; + VkBufferImageCopy *vk_copies = resource->tiles.bind_buffer; + struct vkd3d_subresource_tile_mapping *mapping = NULL; + struct vkd3d_resource_tile_coordinate base_coordinate; + const struct vkd3d_tiled_region_extent *extent; + const struct vkd3d_vk_device_procs *vk_procs; + VkImageSubresourceLayers vk_subresource; + D3D12_TILE_REGION_SIZE region_size; + unsigned int i, j, subresource; + VkImageLayout layout; + + vk_procs = &list->device->vk_procs; + layout = to_image ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + subresource = 0; + + vkd3d_mutex_lock(&resource->tiles.mutex); + + /* In RADV at least, only one tile can be copied per VkBufferImageCopy, maybe because of + * a bug in address calculations for multiple buffer tiles. */ + for (i = 0, j = 0; i < tile_region_size->NumTiles; ++i, ++mapping) + { + if (subresource != coordinate.Subresource || !i) + { + if ((subresource = coordinate.Subresource) >= resource->tiles.subresource_count) + break; + if (subresource % resource->desc.MipLevels >= resource->tiles.standard_mip_count) + { + /* The spec doesn't state we should skip over packed mips and copy the next layer, so just break. */ + WARN("CopyTiles() does not support packed mips.\n"); + break; + } + + if (!vkd3d_initialise_tile_region(&base_coordinate, ®ion_size, &coordinate, tile_region_size, resource)) + { + WARN("Invalid tile region.\n"); + break; + } + + vk_image_subresource_layers_from_d3d12(&vk_subresource, resource->format, + subresource, resource->desc.MipLevels); + extent = &resource->tiles.subresources[subresource].extent; + mapping = &resource->tiles.subresources[subresource].mappings[coordinate.X + + coordinate.Y * extent->width + coordinate.Z * extent->width * extent->height]; + } + + if (mapping->vk_memory) + { + vk_copies[j].bufferOffset = buffer_offset; + vk_copies[j].bufferRowLength = resource->tiles.tile_extent.width; + vk_copies[j].bufferImageHeight = resource->tiles.tile_extent.height; + + vk_copies[j].imageSubresource = vk_subresource; + vk_copies[j].imageOffset.x = coordinate.X; + vk_copies[j].imageOffset.y = coordinate.Y; + vk_copies[j].imageOffset.z = coordinate.Z; + vk_offset_convert_tiles_to_texels(&vk_copies[j].imageOffset, &resource->tiles.tile_extent); + vk_copies[j++].imageExtent = resource->tiles.tile_extent; + } + + buffer_offset += D3D12_TILE_SIZE; + ++coordinate.X; + d3d12_tiled_resource_coordinate_normalise(&base_coordinate, ®ion_size, &coordinate); + } + + if (to_image) + VK_CALL(vkCmdCopyBufferToImage(list->vk_command_buffer, buffer->u.vk_buffer, resource->u.vk_image, layout, j, vk_copies)); + else + VK_CALL(vkCmdCopyImageToBuffer(list->vk_command_buffer, resource->u.vk_image, layout, buffer->u.vk_buffer, j, vk_copies)); + + vkd3d_mutex_unlock(&resource->tiles.mutex); +} + static void STDMETHODCALLTYPE d3d12_command_list_CopyTiles(ID3D12GraphicsCommandList2 *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, + const D3D12_TILE_REGION_SIZE *tile_region_size, ID3D12Resource *buffer_iface, UINT64 buffer_offset, D3D12_TILE_COPY_FLAGS flags) { - FIXME("iface %p, tiled_resource %p, tile_region_start_coordinate %p, tile_region_size %p, " - "buffer %p, buffer_offset %#"PRIx64", flags %#x stub!\n", + struct d3d12_resource *resource = unsafe_impl_from_ID3D12Resource(tiled_resource); + struct d3d12_resource *buffer = unsafe_impl_from_ID3D12Resource(buffer_iface); + struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); + const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; + D3D12_TILE_COPY_FLAGS ignored_flags; + bool to_resource; + + TRACE("iface %p, tiled_resource %p, tile_region_start_coordinate %p, tile_region_size %p, " + "buffer %p, buffer_offset %#"PRIx64", flags %#x.\n", iface, tiled_resource, tile_region_start_coordinate, tile_region_size, buffer, buffer_offset, flags); + + if (!resource || !buffer) + return; + + d3d12_command_list_track_resource_usage(list, resource); + + d3d12_command_list_end_current_render_pass(list); + + if (tile_region_start_coordinate->Subresource >= resource->tiles.subresource_count) + { + WARN("Invalid sub resource %u.\n", tile_region_start_coordinate->Subresource); + return; + } + + ignored_flags = flags; + flags &= D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE | + D3D12_TILE_COPY_FLAG_SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER; + if (vkd3d_popcount(flags) > 1) + { + WARN("Invalid flags %#x. Skipping.\n", flags); + return; + } + if ((ignored_flags ^= flags)) + WARN("Ignoring flags %#x.\n", ignored_flags); + /* No flags defaults to resource-to-buffer. */ + to_resource = flags == D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE; + + if (d3d12_resource_is_texture(resource)) + { + d3d12_command_list_copy_texture_tiles(list, resource, buffer, buffer_offset, + tile_region_start_coordinate, tile_region_size, to_resource); + } + else + { + VkDeviceSize tiled_offset = tile_region_start_coordinate->X * D3D12_TILE_SIZE; + VkBufferCopy buffer_copy; + + buffer_copy.srcOffset = to_resource ? buffer_offset : tiled_offset; + buffer_copy.dstOffset = to_resource ? tiled_offset : buffer_offset; + buffer_copy.size = tile_region_size->NumTiles * D3D12_TILE_SIZE; + + VK_CALL(vkCmdCopyBuffer(list->vk_command_buffer, + to_resource ? buffer->u.vk_buffer : resource->u.vk_buffer, + to_resource ? resource->u.vk_buffer : buffer->u.vk_buffer, 1, &buffer_copy)); + } }
static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresource(ID3D12GraphicsCommandList2 *iface, diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index fce248919..c8da7cb22 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -1489,13 +1489,6 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, if (device->vkd3d_instance->config_flags & VKD3D_CONFIG_FLAG_TILED_TIER_0) device->feature_options.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
- /* FIXME: Implement tiled resources. */ - if (device->feature_options.TiledResourcesTier) - { - WARN("Tiled resources are not implemented yet.\n"); - device->feature_options.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED; - } - if (device->vk_info.device_limits.maxPerStageDescriptorSamplers <= 16) device->feature_options.ResourceBindingTier = D3D12_RESOURCE_BINDING_TIER_1; else if (device->vk_info.device_limits.maxPerStageDescriptorUniformBuffers <= 14) diff --git a/tests/d3d12.c b/tests/d3d12.c index 17089673f..2bc7d91e8 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -36446,6 +36446,7 @@ static uint32_t compute_tile_count(uint32_t resource_size, uint32_t mip, uint32_ static void test_get_resource_tiling(void) { D3D12_SUBRESOURCE_TILING tilings_alt[17]; + D3D12_TILED_RESOURCES_TIER tiled_tier; D3D12_PACKED_MIP_INFO packed_mip_info; D3D12_SUBRESOURCE_TILING tilings[17]; UINT num_resource_tiles, num_tilings; @@ -36455,7 +36456,6 @@ static void test_get_resource_tiling(void) D3D12_TILE_SHAPE tile_shape; ID3D12Resource *resource; unsigned int i, j; - bool no_tier_3; HRESULT hr;
static const struct @@ -36555,6 +36555,13 @@ static void test_get_resource_tiling(void) if (!init_test_context(&context, &desc)) return;
+ if ((tiled_tier = get_tiled_resources_tier(context.device)) < D3D12_TILED_RESOURCES_TIER_1) + { + skip("Tiled resources not supported by device.\n"); + destroy_test_context(&context); + return; + } + /* Test behaviour with various parameter combinations */ resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; resource_desc.Alignment = 0; @@ -36603,16 +36610,13 @@ static void test_get_resource_tiling(void)
ID3D12Resource_Release(resource);
- /* Tiled tier is not included in feature support yet so as not to break future bisections. */ - no_tier_3 = is_amd_windows_device(context.device) || is_radv_device(context.device); - /* Test actual tiling properties */ for (i = 0; i < ARRAY_SIZE(tests); i++, vkd3d_test_pop_context()) { unsigned int tile_index = 0; vkd3d_test_push_context("test %u", i);
- if (no_tier_3 && tests[i].min_tier > D3D12_TILED_RESOURCES_TIER_2) + if (tests[i].min_tier > tiled_tier) { skip("Tiled resources tier %u not supported.\n", tests[i].min_tier); continue; @@ -36748,6 +36752,7 @@ static void test_update_tile_mappings(void) D3D12_TILE_REGION_SIZE region_sizes[8]; D3D12_GPU_VIRTUAL_ADDRESS readback_va; D3D12_HEAP_PROPERTIES heap_properties; + D3D12_TILED_RESOURCES_TIER tiled_tier; D3D12_PACKED_MIP_INFO packed_mip_info; D3D12_SUBRESOURCE_TILING tilings[10]; D3D12_TILE_RANGE_FLAGS tile_flags[8]; @@ -36956,6 +36961,13 @@ static void test_update_tile_mappings(void) if (!init_test_context(&context, &desc)) return;
+ if ((tiled_tier = get_tiled_resources_tier(context.device)) < D3D12_TILED_RESOURCES_TIER_1) + { + skip("Tiled resources not supported by device.\n"); + destroy_test_context(&context); + return; + } + descriptor_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; descriptor_range.NumDescriptors = 1; descriptor_range.BaseShaderRegister = 0; @@ -37375,7 +37387,7 @@ static void test_update_tile_mappings(void) ID3D12Resource_Release(resource_2); ID3D12Resource_Release(array_resource);
- if (!is_amd_windows_device(context.device) && !is_radv_device(context.device)) + if (tiled_tier >= D3D12_TILED_RESOURCES_TIER_3) { /* Test 3D image tile mappings */ resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; @@ -37567,6 +37579,13 @@ static void test_sparse_buffer_memory_lifetime(void) if (!init_compute_test_context(&context)) return;
+ if (get_tiled_resources_tier(context.device) < D3D12_TILED_RESOURCES_TIER_2) + { + skip("Tiled resources tier 2 not supported by device.\n"); + destroy_test_context(&context); + return; + } + memset(&rs_desc, 0, sizeof(rs_desc)); memset(root_parameters, 0, sizeof(root_parameters)); memset(&desc_range, 0, sizeof(desc_range)); @@ -37738,6 +37757,13 @@ static void test_copy_tiles(void) if (!init_test_context(&context, &desc)) return;
+ if (get_tiled_resources_tier(context.device) < D3D12_TILED_RESOURCES_TIER_1) + { + skip("Tiled resources not supported by device.\n"); + destroy_test_context(&context); + return; + } + memset(&heap_desc, 0, sizeof(heap_desc)); heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; heap_desc.SizeInBytes = TILE_SIZE * 16; @@ -37800,7 +37826,7 @@ static void test_copy_tiles(void) { uint32_t offset = i + 4 * TILE_SIZE / sizeof(*buffer_data); set_box(&box, offset, 0, 0, offset + 1, 1, 1); - todo check_readback_data_uint(&rb.rb, &box, buffer_data[i + buffer_offset / sizeof(*buffer_data)], 0); + check_readback_data_uint(&rb.rb, &box, buffer_data[i + buffer_offset / sizeof(*buffer_data)], 0); }
release_resource_readback(&rb); @@ -37829,7 +37855,7 @@ static void test_copy_tiles(void) { uint32_t offset = i + (TILE_SIZE + buffer_offset) / sizeof(*buffer_data); set_box(&box, i, 0, 0, i + 1, 1, 1); - todo check_readback_data_uint(&rb.rb, &box, buffer_data[offset], 0); + check_readback_data_uint(&rb.rb, &box, buffer_data[offset], 0); }
release_resource_readback(&rb); @@ -37892,7 +37918,7 @@ static void test_copy_tiles(void) uint32_t offset = image_tiles[i].tile_idx * TILE_SIZE / sizeof(*buffer_data) + 128 * y + x; set_box(&box, 128 * image_tiles[i].x + x, 128 * image_tiles[i].y + y, 0, 128 * image_tiles[i].x + x + 1, 128 * image_tiles[i].y + y + 1, 1); - todo_if(buffer_data[offset]) check_readback_data_uint(&rb.rb, &box, buffer_data[offset], 0); + check_readback_data_uint(&rb.rb, &box, buffer_data[offset], 0); } } } @@ -37929,7 +37955,7 @@ static void test_copy_tiles(void) { uint32_t offset = image_tiles[i].tile_idx * TILE_SIZE / sizeof(uint32_t) + x; set_box(&box, offset, 0, 0, offset + 1, 1, 1); - todo_if(buffer_data[offset]) check_readback_data_uint(&rb.rb, &box, buffer_data[offset], 0); + check_readback_data_uint(&rb.rb, &box, buffer_data[offset], 0); } }