-- v3: vkd3d: Implement ID3D12Device::GetResourceTiling() for textures.
From: Conor McCarthy cmccarthy@codeweavers.com
Based on vkd3d-proton patches by Philip Rebohle and Hans-Kristian Arntzen. --- tests/d3d12.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+)
diff --git a/tests/d3d12.c b/tests/d3d12.c index 2f1c905f2..e2dcbde69 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -36438,6 +36438,284 @@ static void test_vs_ps_relative_addressing(void) destroy_test_context(&context); }
+static uint32_t compute_tile_count(uint32_t resource_size, uint32_t mip, uint32_t tile_size) +{ + uint32_t mip_size = max(resource_size >> mip, 1u); + return (mip_size + tile_size - 1) / tile_size; +} + +static void test_get_resource_tiling(void) +{ + UINT resource_tile_count, tilings_count; + D3D12_TILED_RESOURCES_TIER tiled_tier; + D3D12_PACKED_MIP_INFO packed_mip_info; + D3D12_SUBRESOURCE_TILING tilings[64]; + D3D12_RESOURCE_DESC resource_desc; + struct test_context_desc desc; + struct test_context context; + D3D12_TILE_SHAPE tile_shape; + ID3D12Resource *resource; + unsigned int i, j; + HRESULT hr; + + static const struct + { + D3D12_RESOURCE_DIMENSION dim; + DXGI_FORMAT format; + UINT width; + UINT height; + UINT depth_or_array_layers; + UINT mip_levels; + UINT expected_tile_count; + UINT expected_tiling_count; + UINT expected_standard_mips; + UINT tile_shape_w; + UINT tile_shape_h; + UINT tile_shape_d; + D3D12_TILED_RESOURCES_TIER min_tier; + bool todo_radv; + } + tests[] = + { + /* Test buffers */ + { D3D12_RESOURCE_DIMENSION_BUFFER, DXGI_FORMAT_UNKNOWN, 1024, 1, 1, 1, 1, 1, 0, 65536, 1, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_BUFFER, DXGI_FORMAT_UNKNOWN, 16*65536, 1, 1, 1, 16, 1, 0, 65536, 1, 1, D3D12_TILED_RESOURCES_TIER_1 }, + /* Test small resource behavior */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 1, 1, 1, 1, 1, 1, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 2, 2, 1, 2, 1, 2, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 4, 4, 1, 3, 1, 3, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 8, 8, 1, 4, 1, 4, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 16, 16, 1, 5, 1, 5, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 32, 32, 1, 6, 1, 6, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 64, 64, 1, 7, 1, 7, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 128, 128, 1, 8, 1, 8, 0, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 256, 256, 1, 9, 2, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + /* Test various image formats */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM, 512, 512, 1, 1, 4, 1, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8_UNORM, 512, 512, 1, 1, 8, 1, 1, 256, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 512, 512, 1, 1, 16, 1, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R16G16B16A16_UNORM, 512, 512, 1, 1, 32, 1, 1, 128, 64, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R32G32B32A32_FLOAT, 512, 512, 1, 1, 64, 1, 1, 64, 64, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_D16_UNORM, 512, 512, 1, 1, 8, 1, 1, 256, 128, 1, D3D12_TILED_RESOURCES_TIER_1, true }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_D32_FLOAT, 512, 512, 1, 1, 16, 1, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1, true }, + /* Test rectangular textures */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 1024, 256, 1, 1, 16, 1, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 256, 1024, 1, 1, 16, 1, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 192, 128, 1, 1, 2, 1, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_2 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 128, 192, 1, 1, 2, 1, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_2 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 320, 192, 1, 1, 6, 1, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_2 }, + /* Test array layers and packed mip levels */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 128, 128, 16, 1, 16, 16, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 128, 128, 1, 8, 1, 8, 1, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 512, 512, 1, 10, 21, 10, 3, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 512, 512, 4, 3, 84, 12, 3, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 64, 64, 1, 1, 0, 1, 0, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_1 }, + /* Test 3D textures */ + { D3D12_RESOURCE_DIMENSION_TEXTURE3D, DXGI_FORMAT_R8_UNORM, 64, 64, 64, 1, 4, 1, 1, 64, 32, 32, D3D12_TILED_RESOURCES_TIER_3 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE3D, DXGI_FORMAT_R8G8_UNORM, 64, 64, 64, 1, 8, 1, 1, 32, 32, 32, D3D12_TILED_RESOURCES_TIER_3 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE3D, DXGI_FORMAT_R8G8B8A8_UNORM, 64, 64, 64, 1, 16, 1, 1, 32, 32, 16, D3D12_TILED_RESOURCES_TIER_3 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE3D, DXGI_FORMAT_R32G32B32A32_FLOAT, 64, 64, 64, 3, 73, 3, 3, 16, 16, 16, D3D12_TILED_RESOURCES_TIER_3 }, + /* Basic BC configurations. */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 512, 512, 1, 1, 2, 1, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC2_UNORM, 512, 512, 1, 1, 4, 1, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC3_UNORM, 512, 512, 1, 1, 4, 1, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC4_UNORM, 512, 512, 1, 1, 2, 1, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC5_UNORM, 512, 512, 1, 1, 4, 1, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC6H_UF16, 512, 512, 1, 1, 4, 1, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC6H_SF16, 512, 512, 1, 1, 4, 1, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 512, 512, 1, 1, 4, 1, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + /* Basic mipmapping with obvious tiling layouts. */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 512, 256, 1, 10, 2, 10, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 1024, 512, 1, 10, 6, 10, 2, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 2048, 1024, 1, 10, 22, 10, 3, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 256, 256, 1, 9, 2, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 512, 512, 1, 9, 6, 9, 2, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 1024, 1024, 1, 9, 22, 9, 3, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + /* Wide shapes. On AMD, we keep observing standard mips even when the smallest dimension dips below the tile size. + * This is not the case on NV however. */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 1024, 256, 1, 10, 3, 10, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 2048, 256, 1, 10, 6, 10, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 4096, 256, 1, 10, 11, 10, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 512, 256, 1, 9, 3, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 1024, 256, 1, 9, 6, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 2048, 256, 1, 9, 11, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + /* Tall shapes. Similar to wide tests. */ + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 512, 512, 1, 10, 3, 10, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 512, 1024, 1, 10, 6, 10, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC1_UNORM, 512, 2048, 1, 10, 11, 10, 1, 512, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 256, 512, 1, 9, 3, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 256, 1024, 1, 9, 6, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_BC7_UNORM, 256, 2048, 1, 9, 11, 9, 1, 256, 256, 1, D3D12_TILED_RESOURCES_TIER_1 }, + }; + static const D3D12_SUBRESOURCE_TILING uninit_tiling = {0xdeadbeef, 0xdead, 0xbeef, 0xdeadbeef}; + + memset(&desc, 0, sizeof(desc)); + desc.rt_width = 640; + desc.rt_height = 480; + desc.rt_format = DXGI_FORMAT_R8G8B8A8_UNORM; + 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; + resource_desc.Width = 512; + resource_desc.Height = 512; + resource_desc.DepthOrArraySize = 1; + resource_desc.MipLevels = 10; + resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + resource_desc.SampleDesc.Count = 1; + resource_desc.SampleDesc.Quality = 0; + resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; + resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&resource); + ok(hr == S_OK, "Failed to create reserved resource, hr %#x.\n", hr); + + /* This is nonsense, but it doesn't crash or generate errors. */ + ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, NULL, 0, NULL); + + /* If tilings_count is NULL, tilings is ignored. */ + tilings[0] = uninit_tiling; + ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, NULL, 0, tilings); + ok(!memcmp(&tilings[0], &uninit_tiling, sizeof(uninit_tiling)), "Mismatch.\n"); + + tilings_count = 0; + ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &tilings_count, 0, NULL); + ok(tilings_count == 0, "Unexpected tiling count %u.\n", tilings_count); + + tilings_count = ARRAY_SIZE(tilings); + ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &tilings_count, 10, tilings); + ok(tilings_count == 0, "Unexpected tiling count %u.\n", tilings_count); + + tilings_count = ARRAY_SIZE(tilings); + ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &tilings_count, 2, tilings); + ok(tilings_count == 8, "Unexpected tiling count %u.\n", tilings_count); + ok(tilings[0].StartTileIndexInOverallResource == 20, "Unexpected start tile index %u.\n", tilings[0].StartTileIndexInOverallResource); + + tilings_count = 1; + memset(&tilings, 0xaa, sizeof(tilings)); + ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &tilings_count, 2, tilings); + ok(tilings_count == 1, "Unexpected tiling count %u.\n", tilings_count); + ok(tilings[0].StartTileIndexInOverallResource == 20, "Unexpected start tile index %u.\n", tilings[0].StartTileIndexInOverallResource); + ok(tilings[1].StartTileIndexInOverallResource == 0xaaaaaaaa, "Tiling array got modified.\n"); + + ID3D12Resource_Release(resource); + + /* 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 (tests[i].min_tier > tiled_tier) + { + skip("Tiled resources tier %u not supported.\n", tests[i].min_tier); + continue; + } + + memset(&packed_mip_info, 0xaa, sizeof(packed_mip_info)); + memset(&tile_shape, 0xaa, sizeof(tile_shape)); + memset(&tilings, 0xaa, sizeof(tilings)); + + resource_tile_count = 0xdeadbeef; + tilings_count = ARRAY_SIZE(tilings); + + resource_desc.Dimension = tests[i].dim; + resource_desc.Alignment = 0; + resource_desc.Width = tests[i].width; + resource_desc.Height = tests[i].height; + resource_desc.DepthOrArraySize = tests[i].depth_or_array_layers; + resource_desc.MipLevels = tests[i].mip_levels; + resource_desc.Format = tests[i].format; + resource_desc.SampleDesc.Count = 1; + resource_desc.SampleDesc.Quality = 0; + resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; + resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + if (tests[i].dim == D3D12_RESOURCE_DIMENSION_BUFFER) + resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&resource); + todo_if(is_radv_device(context.device) && tests[i].todo_radv) + ok(hr == S_OK, "Failed to create reserved resource, hr %#x.\n", hr); + + if (hr != S_OK) + continue; + + ID3D12Device_GetResourceTiling(context.device, resource, &resource_tile_count, &packed_mip_info, &tile_shape, &tilings_count, 0, tilings); + assert(tilings_count <= ARRAY_SIZE(tilings)); + + ok(resource_tile_count != 0xdeadbeef && resource_tile_count >= tests[i].expected_tile_count, + "Unexpected resource tile count %u.\n", resource_tile_count); + ok(tilings_count == tests[i].expected_tiling_count, "Unexpected subresource tiling count %u.\n", tilings_count); + + ok(packed_mip_info.NumStandardMips != 0xaa && packed_mip_info.NumStandardMips >= tests[i].expected_standard_mips, + "Unexpected standard mip count %u.\n", packed_mip_info.NumStandardMips); + ok(packed_mip_info.NumPackedMips == (tests[i].dim == D3D12_RESOURCE_DIMENSION_BUFFER + ? 0 : tests[i].mip_levels - packed_mip_info.NumStandardMips), + "Unexpected packed mip count %u.\n", packed_mip_info.NumPackedMips); + ok(packed_mip_info.NumPackedMips != 0xaa + && (packed_mip_info.NumTilesForPackedMips == 0) == (packed_mip_info.NumPackedMips == 0), + "Unexpected packed tile count %u.\n", packed_mip_info.NumTilesForPackedMips); + + /* Docs say that tile shape should be cleared to zero if there is no standard mip, but drivers don't seem to care about this. */ + ok(tile_shape.WidthInTexels == tests[i].tile_shape_w, "Unexpected tile width %u.\n", tile_shape.WidthInTexels); + ok(tile_shape.HeightInTexels == tests[i].tile_shape_h, "Unexpected tile height %u.\n", tile_shape.HeightInTexels); + ok(tile_shape.DepthInTexels == tests[i].tile_shape_d, "Unexpected tile depth %u.\n", tile_shape.DepthInTexels); + + for (j = 0; j < tests[i].expected_tiling_count; j++) + { + uint32_t mip = j % tests[i].mip_levels; + + if (mip < packed_mip_info.NumStandardMips || !packed_mip_info.NumPackedMips) + { + uint32_t expected_w = compute_tile_count(tests[i].width, mip, tests[i].tile_shape_w); + uint32_t expected_h = compute_tile_count(tests[i].height, mip, tests[i].tile_shape_h); + uint32_t expected_d = 1; + + if (tests[i].dim == D3D12_RESOURCE_DIMENSION_TEXTURE3D) + expected_d = compute_tile_count(tests[i].depth_or_array_layers, mip, tests[i].tile_shape_d); + + ok(tilings[j].WidthInTiles == expected_w, "Unexpected width %u for subresource %u.\n", tilings[j].WidthInTiles, j); + ok(tilings[j].HeightInTiles == expected_h, "Unexpected width %u for subresource %u.\n", tilings[j].HeightInTiles, j); + ok(tilings[j].DepthInTiles == expected_d, "Unexpected width %u for subresource %u.\n", tilings[j].DepthInTiles, j); + + ok(tilings[j].StartTileIndexInOverallResource == tile_index, "Unexpected start tile index %u for subresource %u.\n", + tilings[j].StartTileIndexInOverallResource, j); + + tile_index += tilings[j].WidthInTiles * tilings[j].HeightInTiles * tilings[j].DepthInTiles; + } + else + { + ok(!tilings[j].WidthInTiles && !tilings[j].HeightInTiles && !tilings[j].DepthInTiles, + "Unexpected tile count (%u,%u,%u) for packed subresource %u.\n", + tilings[j].WidthInTiles, tilings[j].HeightInTiles, tilings[j].DepthInTiles, j); + ok(tilings[j].StartTileIndexInOverallResource == 0xffffffff, "Unexpected start tile index %u for packed subresource %u.\n", + tilings[j].StartTileIndexInOverallResource, j); + } + } + + ok(resource_tile_count == tile_index + packed_mip_info.NumTilesForPackedMips, + "Unexpected resource tile count %u.\n", resource_tile_count); + ok(packed_mip_info.StartTileIndexInOverallResource == (packed_mip_info.NumPackedMips ? tile_index : 0), + "Unexpected mip tail start tile index %u.\n", packed_mip_info.StartTileIndexInOverallResource); + + ID3D12Resource_Release(resource); + } + + destroy_test_context(&context); +} + START_TEST(d3d12) { parse_args(argc, argv); @@ -36617,4 +36895,5 @@ START_TEST(d3d12) run_test(test_clock_calibration); run_test(test_readback_map_stability); run_test(test_vs_ps_relative_addressing); + run_test(test_get_resource_tiling); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- include/vkd3d_d3d12.idl | 1 + libs/vkd3d/device.c | 10 +++- libs/vkd3d/resource.c | 102 +++++++++++++++++++++++++++++++++++-- libs/vkd3d/vkd3d_private.h | 22 ++++++++ 4 files changed, 130 insertions(+), 5 deletions(-)
diff --git a/include/vkd3d_d3d12.idl b/include/vkd3d_d3d12.idl index 06287f5a8..9af75f402 100644 --- a/include/vkd3d_d3d12.idl +++ b/include/vkd3d_d3d12.idl @@ -72,6 +72,7 @@ const UINT D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT = 4096; const UINT D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE = 4; const UINT D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256; const UINT D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT = 512; +const UINT D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES = 65536; const UINT D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT = 4096; const UINT D3D12_VS_INPUT_REGISTER_COUNT = 32; const UINT D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE = 16; diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index b9a8943cc..d461256be 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -3891,12 +3891,18 @@ static void STDMETHODCALLTYPE d3d12_device_GetResourceTiling(ID3D12Device *iface UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling, D3D12_SUBRESOURCE_TILING *sub_resource_tilings) { - FIXME("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, " + const struct d3d12_resource *resource_impl = impl_from_ID3D12Resource(resource); + struct d3d12_device *device = impl_from_ID3D12Device(iface); + + TRACE("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, " "standard_title_shape %p, sub_resource_tiling_count %p, " - "first_sub_resource_tiling %u, sub_resource_tilings %p stub!\n", + "first_sub_resource_tiling %u, sub_resource_tilings %p.\n", iface, resource, total_tile_count, packed_mip_info, standard_tile_shape, sub_resource_tiling_count, first_sub_resource_tiling, sub_resource_tilings); + + d3d12_resource_get_tiling(device, resource_impl, total_tile_count, packed_mip_info, standard_tile_shape, + sub_resource_tiling_count, first_sub_resource_tiling, sub_resource_tilings); }
static LUID * STDMETHODCALLTYPE d3d12_device_GetAdapterLuid(ID3D12Device *iface, LUID *luid) diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 4c07d3265..86466b8c3 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -971,6 +971,11 @@ HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device, return hr; }
+static void d3d12_resource_tile_info_cleanup(struct d3d12_resource *resource) +{ + vkd3d_free(resource->tiles.subresources); +} + static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12_device *device) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; @@ -986,6 +991,8 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12 else VK_CALL(vkDestroyImage(device->vk_device, resource->u.vk_image, NULL));
+ d3d12_resource_tile_info_cleanup(resource); + if (resource->heap) d3d12_heap_resource_destroyed(resource->heap); } @@ -1057,9 +1064,94 @@ static void d3d12_resource_get_level_box(const struct d3d12_resource *resource, box->back = d3d12_resource_desc_get_depth(&resource->desc, level); }
-static void d3d12_resource_init_tiles(struct d3d12_resource *resource) +void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource, + UINT *total_tile_count, D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape, + UINT *subresource_tiling_count, UINT first_subresource_tiling, + D3D12_SUBRESOURCE_TILING *subresource_tilings) +{ + unsigned int i, subresource, subresource_count, count; + const struct vkd3d_subresource_tile_info *tile_info; + const VkExtent3D *tile_extent; + + if (d3d12_resource_is_texture(resource)) + { + FIXME("Not implemented for textures.\n"); + return; + } + + tile_extent = &resource->tiles.tile_extent; + + if (packed_mip_info) + { + packed_mip_info->NumStandardMips = resource->tiles.standard_mip_count; + packed_mip_info->NumPackedMips = 0; + packed_mip_info->NumTilesForPackedMips = 0; + packed_mip_info->StartTileIndexInOverallResource = 0; + } + + if (standard_tile_shape) + { + /* D3D12 docs say tile shape is cleared to zero if there is no standard mip, but drivers don't to do this. */ + standard_tile_shape->WidthInTexels = tile_extent->width; + standard_tile_shape->HeightInTexels = tile_extent->height; + standard_tile_shape->DepthInTexels = tile_extent->depth; + } + + if (total_tile_count) + *total_tile_count = resource->tiles.total_count; + + if (!subresource_tiling_count) + return; + + subresource_count = resource->tiles.subresource_count; + + count = subresource_count - min(first_subresource_tiling, subresource_count); + count = min(count, *subresource_tiling_count); + + for (i = 0; i < count; ++i) + { + subresource = i + first_subresource_tiling; + tile_info = &resource->tiles.subresources[subresource]; + subresource_tilings[i].StartTileIndexInOverallResource = tile_info->offset; + subresource_tilings[i].WidthInTiles = tile_info->extent.width; + subresource_tilings[i].HeightInTiles = tile_info->extent.height; + subresource_tilings[i].DepthInTiles = tile_info->extent.depth; + } + *subresource_tiling_count = i; +} + +static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3d12_device *device) { - resource->tiles.subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc); + struct vkd3d_subresource_tile_info *tile_info; + unsigned int subresource_count; + + subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc); + + if (d3d12_resource_is_buffer(resource)) + { + if (!(resource->tiles.subresources = vkd3d_calloc(subresource_count, sizeof(*resource->tiles.subresources)))) + { + ERR("Failed to allocate subresource info array.\n"); + return false; + } + + tile_info = &resource->tiles.subresources[0]; + tile_info->offset = 0; + tile_info->extent.width = align(resource->desc.Width, D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES) + / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; + tile_info->extent.height = 1; + tile_info->extent.depth = 1; + tile_info->count = tile_info->extent.width; + + resource->tiles.tile_extent.width = D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; + resource->tiles.tile_extent.height = 1; + resource->tiles.tile_extent.depth = 1; + resource->tiles.total_count = tile_info->extent.width; + resource->tiles.subresource_count = 1; + resource->tiles.standard_mip_count = 1; + } + + return true; }
/* ID3D12Resource */ @@ -2013,7 +2105,11 @@ HRESULT d3d12_reserved_resource_create(struct d3d12_device *device, desc, initial_state, optimized_clear_value, &object))) return hr;
- d3d12_resource_init_tiles(object); + if (!d3d12_resource_init_tiles(object, device)) + { + d3d12_resource_Release(&object->ID3D12Resource_iface); + return E_OUTOFMEMORY; + }
TRACE("Created reserved resource %p.\n", object);
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index c5259420a..459354b07 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -673,9 +673,27 @@ struct d3d12_heap *unsafe_impl_from_ID3D12Heap(ID3D12Heap *iface); #define VKD3D_RESOURCE_DEDICATED_HEAP 0x00000008 #define VKD3D_RESOURCE_LINEAR_TILING 0x00000010
+struct vkd3d_tiled_region_extent +{ + unsigned int width; + unsigned int height; + unsigned int depth; +}; + +struct vkd3d_subresource_tile_info +{ + unsigned int offset; + unsigned int count; + struct vkd3d_tiled_region_extent extent; +}; + struct d3d12_resource_tile_info { + VkExtent3D tile_extent; + unsigned int total_count; + unsigned int standard_mip_count; unsigned int subresource_count; + struct vkd3d_subresource_tile_info *subresources; };
/* ID3D12Resource */ @@ -728,6 +746,10 @@ static inline bool d3d12_resource_is_texture(const struct d3d12_resource *resour
bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource); HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC *desc, struct d3d12_device *device); +void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource, + UINT *total_tile_count, D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape, + UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling, + D3D12_SUBRESOURCE_TILING *sub_resource_tilings);
HRESULT d3d12_committed_resource_create(struct d3d12_device *device, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
From: Conor McCarthy cmccarthy@codeweavers.com
--- include/vkd3d_d3d12.idl | 1 + libs/vkd3d/resource.c | 113 +++++++++++++++++++++++++++++++------ libs/vkd3d/vkd3d_private.h | 1 + 3 files changed, 98 insertions(+), 17 deletions(-)
diff --git a/include/vkd3d_d3d12.idl b/include/vkd3d_d3d12.idl index 9af75f402..4db9e10f4 100644 --- a/include/vkd3d_d3d12.idl +++ b/include/vkd3d_d3d12.idl @@ -45,6 +45,7 @@ const UINT D3D12_DEFAULT_STENCIL_WRITE_MASK = 0xff; const UINT D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND = 0xffffffff; cpp_quote("#define D3D12_FLOAT32_MAX (3.402823466e+38f)") const UINT D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT = 32; +const UINT D3D12_PACKED_TILE = 0xffffffff; const UINT D3D12_UAV_SLOT_COUNT = 64; const UINT D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT = 4096; const UINT D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT = 4096; diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 86466b8c3..0be4903b0 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -1064,29 +1064,38 @@ static void d3d12_resource_get_level_box(const struct d3d12_resource *resource, box->back = d3d12_resource_desc_get_depth(&resource->desc, level); }
+static void compute_image_subresource_size_in_tiles(const VkExtent3D *tile_extent, + const struct D3D12_RESOURCE_DESC *desc, unsigned int miplevel_idx, + struct vkd3d_tiled_region_extent *size) +{ + unsigned int width, height, depth; + + width = d3d12_resource_desc_get_width(desc, miplevel_idx); + height = d3d12_resource_desc_get_height(desc, miplevel_idx); + depth = d3d12_resource_desc_get_depth(desc, miplevel_idx); + size->width = (width + tile_extent->width - 1) / tile_extent->width; + size->height = (height + tile_extent->height - 1) / tile_extent->height; + size->depth = (depth + tile_extent->depth - 1) / tile_extent->depth; +} + void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource, UINT *total_tile_count, D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape, UINT *subresource_tiling_count, UINT first_subresource_tiling, D3D12_SUBRESOURCE_TILING *subresource_tilings) { - unsigned int i, subresource, subresource_count, count; + unsigned int i, subresource, subresource_count, miplevel_idx, count; const struct vkd3d_subresource_tile_info *tile_info; const VkExtent3D *tile_extent;
- if (d3d12_resource_is_texture(resource)) - { - FIXME("Not implemented for textures.\n"); - return; - } - tile_extent = &resource->tiles.tile_extent;
if (packed_mip_info) { packed_mip_info->NumStandardMips = resource->tiles.standard_mip_count; - packed_mip_info->NumPackedMips = 0; - packed_mip_info->NumTilesForPackedMips = 0; - packed_mip_info->StartTileIndexInOverallResource = 0; + packed_mip_info->NumPackedMips = resource->desc.MipLevels - packed_mip_info->NumStandardMips; + packed_mip_info->NumTilesForPackedMips = !!resource->tiles.packed_mip_tile_count; /* non-zero dummy value */ + packed_mip_info->StartTileIndexInOverallResource = packed_mip_info->NumPackedMips + ? resource->tiles.subresources[resource->tiles.standard_mip_count].offset : 0; }
if (standard_tile_shape) @@ -1111,6 +1120,14 @@ void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_r for (i = 0; i < count; ++i) { subresource = i + first_subresource_tiling; + miplevel_idx = subresource % resource->desc.MipLevels; + if (miplevel_idx >= resource->tiles.standard_mip_count) + { + memset(&subresource_tilings[i], 0, sizeof(subresource_tilings[i])); + subresource_tilings[i].StartTileIndexInOverallResource = D3D12_PACKED_TILE; + continue; + } + tile_info = &resource->tiles.subresources[subresource]; subresource_tilings[i].StartTileIndexInOverallResource = tile_info->offset; subresource_tilings[i].WidthInTiles = tile_info->extent.width; @@ -1122,19 +1139,26 @@ void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_r
static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3d12_device *device) { + unsigned int i, start_idx, subresource_count, tile_count, miplevel_idx; + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + /* Multiple planes are not supported. 2 requirements should be enough but use 4 for robustness. */ + VkSparseImageMemoryRequirements sparse_requirements_array[4]; + VkSparseImageMemoryRequirements sparse_requirements = {0}; struct vkd3d_subresource_tile_info *tile_info; - unsigned int subresource_count; + VkMemoryRequirements requirements; + const VkExtent3D *tile_extent; + uint32_t requirement_count;
subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
- if (d3d12_resource_is_buffer(resource)) + if (!(resource->tiles.subresources = vkd3d_calloc(subresource_count, sizeof(*resource->tiles.subresources)))) { - if (!(resource->tiles.subresources = vkd3d_calloc(subresource_count, sizeof(*resource->tiles.subresources)))) - { - ERR("Failed to allocate subresource info array.\n"); - return false; - } + ERR("Failed to allocate subresource info array.\n"); + return false; + }
+ if (d3d12_resource_is_buffer(resource)) + { tile_info = &resource->tiles.subresources[0]; tile_info->offset = 0; tile_info->extent.width = align(resource->desc.Width, D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES) @@ -1149,6 +1173,61 @@ static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3 resource->tiles.total_count = tile_info->extent.width; resource->tiles.subresource_count = 1; resource->tiles.standard_mip_count = 1; + resource->tiles.packed_mip_tile_count = 0; + } + else + { + VK_CALL(vkGetImageMemoryRequirements(device->vk_device, resource->u.vk_image, &requirements)); + if (requirements.alignment > D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES) + FIXME("Vulkan device tile size is greater than the standard D3D12 tile size.\n"); + + requirement_count = ARRAY_SIZE(sparse_requirements_array); + VK_CALL(vkGetImageSparseMemoryRequirements(device->vk_device, resource->u.vk_image, + &requirement_count, sparse_requirements_array)); + for (i = 0; i < requirement_count; ++i) + { + if (!(sparse_requirements_array[i].formatProperties.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT)) + { + sparse_requirements = sparse_requirements_array[i]; + break; + } + } + if (i == requirement_count) + { + WARN("Failed to get sparse requirements.\n"); + return false; + } + + resource->tiles.tile_extent = sparse_requirements.formatProperties.imageGranularity; + resource->tiles.subresource_count = subresource_count; + resource->tiles.standard_mip_count = sparse_requirements.imageMipTailSize + ? sparse_requirements.imageMipTailFirstLod : resource->desc.MipLevels; + resource->tiles.packed_mip_tile_count = (resource->tiles.standard_mip_count < resource->desc.MipLevels) + ? sparse_requirements.imageMipTailSize / requirements.alignment : 0; + + for (i = 0, start_idx = 0; i < subresource_count; ++i) + { + miplevel_idx = i % resource->desc.MipLevels; + + tile_extent = &sparse_requirements.formatProperties.imageGranularity; + tile_info = &resource->tiles.subresources[i]; + compute_image_subresource_size_in_tiles(tile_extent, &resource->desc, miplevel_idx, &tile_info->extent); + tile_info->offset = start_idx; + tile_info->count = 0; + + if (miplevel_idx < resource->tiles.standard_mip_count) + { + tile_count = tile_info->extent.width * tile_info->extent.height * tile_info->extent.depth; + start_idx += tile_count; + tile_info->count = tile_count; + } + else if (miplevel_idx == resource->tiles.standard_mip_count) + { + tile_info->count = 1; /* Non-zero dummy value */ + start_idx += 1; + } + } + resource->tiles.total_count = start_idx; }
return true; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 459354b07..efb0bffa2 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -692,6 +692,7 @@ struct d3d12_resource_tile_info VkExtent3D tile_extent; unsigned int total_count; unsigned int standard_mip_count; + unsigned int packed_mip_tile_count; unsigned int subresource_count; struct vkd3d_subresource_tile_info *subresources; };
+ /* Multiple planes are not supported. 2 requirements should be enough but use 4 for robustness. */ + VkSparseImageMemoryRequirements sparse_requirements_array[4];
This doesn't seem all that robust. In particular, I don't think there's anything in the spec putting an upper bound on the number of requirements returned, or anything preventing (future) extensions from increasing that.
+ for (i = 0; i < requirement_count; ++i) + { + if (!(sparse_requirements_array[i].formatProperties.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT)) + { + sparse_requirements = sparse_requirements_array[i]; + break; + } + }
Somewhat similarly, we seem to be making assumptions here about the possible aspect mask bits.