| /* | |
| * Copyright 2016-2017 Józef Kucia for CodeWeavers | |
| * Copyright 2020-2021 Philip Rebohle for Valve Corporation | |
| * Copyright 2020-2021 Joshua Ashton for Valve Corporation | |
| * Copyright 2020-2021 Hans-Kristian Arntzen for Valve Corporation | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API | |
| #include "d3d12_crosstest.h" | |
| #define TILE_SIZE 65536 | |
| 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) + (mip_size % tile_size ? 1 : 0); | |
| } | |
| void test_get_resource_tiling(void) | |
| { | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_SUBRESOURCE_TILING tilings_alt[64]; | |
| D3D12_PACKED_MIP_INFO packed_mip_info; | |
| D3D12_SUBRESOURCE_TILING tilings[64]; | |
| UINT num_resource_tiles, num_tilings; | |
| 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, 1, 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 }, | |
| /* Array images with full mip chain; now allowed with tier 4 */ | |
| { D3D12_RESOURCE_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 512, 512, 4, 10, 88, 40, 3, 128, 128, 1, D3D12_TILED_RESOURCES_TIER_4 }, | |
| }; | |
| 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; | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (!options.TiledResourcesTier) | |
| { | |
| 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 num_tilings is NULL, tilings_alt is ignored. */ | |
| memset(tilings, 0, sizeof(tilings)); | |
| memset(tilings_alt, 0, sizeof(tilings_alt)); | |
| ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, NULL, 0, tilings_alt); | |
| ok(memcmp(tilings, tilings_alt, sizeof(tilings_alt)) == 0, "Mismatch.\n"); | |
| num_tilings = 0; | |
| ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &num_tilings, 0, NULL); | |
| ok(num_tilings == 0, "Unexpected tiling count %u.\n", num_tilings); | |
| num_tilings = ARRAY_SIZE(tilings); | |
| ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &num_tilings, 10, tilings); | |
| ok(num_tilings == 0, "Unexpected tiling count %u.\n", num_tilings); | |
| num_tilings = ARRAY_SIZE(tilings); | |
| ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &num_tilings, 2, tilings); | |
| ok(num_tilings == 8, "Unexpected tiling count %u.\n", num_tilings); | |
| ok(tilings[0].StartTileIndexInOverallResource == 20, "Unexpected start tile index %u.\n", tilings[0].StartTileIndexInOverallResource); | |
| num_tilings = 1; | |
| memset(&tilings, 0xaa, sizeof(tilings)); | |
| ID3D12Device_GetResourceTiling(context.device, resource, NULL, NULL, NULL, &num_tilings, 2, tilings); | |
| ok(num_tilings == 1, "Unexpected tiling count %u.\n", num_tilings); | |
| 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++) | |
| { | |
| unsigned int tile_index = 0; | |
| vkd3d_test_set_context("test %u", i); | |
| if (tests[i].min_tier > options.TiledResourcesTier) | |
| { | |
| 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)); | |
| num_resource_tiles = 0xdeadbeef; | |
| num_tilings = 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, &num_resource_tiles, &packed_mip_info, &tile_shape, &num_tilings, 0, tilings); | |
| ok(num_resource_tiles >= tests[i].expected_tile_count, "Unexpected resource tile count %u.\n", num_resource_tiles); | |
| ok(num_tilings == tests[i].expected_tiling_count, "Unexpected subresource tiling count %u.\n", num_tilings); | |
| ok(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.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(num_resource_tiles == tile_index + packed_mip_info.NumTilesForPackedMips, | |
| "Unexpected resource tile count %u.\n", num_resource_tiles); | |
| 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); | |
| } | |
| vkd3d_test_set_context(NULL); | |
| destroy_test_context(&context); | |
| } | |
| static void set_region_offset(D3D12_TILED_RESOURCE_COORDINATE *region, uint32_t x, uint32_t y, uint32_t z, uint32_t subresource) | |
| { | |
| region->X = x; | |
| region->Y = y; | |
| region->Z = z; | |
| region->Subresource = subresource; | |
| } | |
| static void set_region_size(D3D12_TILE_REGION_SIZE *region, uint32_t num_tiles, bool use_box, uint32_t w, uint32_t h, uint32_t d) | |
| { | |
| region->NumTiles = num_tiles; | |
| region->UseBox = use_box; | |
| region->Width = w; | |
| region->Height = h; | |
| region->Depth = d; | |
| } | |
| void test_update_tile_mappings_remap_stress(void) | |
| { | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_ROOT_SIGNATURE_DESC rs_desc; | |
| D3D12_ROOT_PARAMETER rs_params[2]; | |
| D3D12_RESOURCE_DESC resource_desc; | |
| D3D12_HEAP_PROPERTIES heap_props; | |
| ID3D12Resource *output_resource; | |
| struct test_context_desc desc; | |
| struct test_context context; | |
| struct resource_readback rb; | |
| D3D12_HEAP_DESC heap_desc; | |
| ID3D12Resource *resource; | |
| unsigned int i, j, iter; | |
| ID3D12Heap *heap = NULL; | |
| HRESULT hr; | |
| #include "shaders/sparse/headers/update_tile_mappings.h" | |
| memset(&desc, 0, sizeof(desc)); | |
| desc.no_render_target = true; | |
| desc.no_pipeline = true; | |
| desc.no_root_signature = true; | |
| if (!init_test_context(&context, &desc)) | |
| return; | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (!options.TiledResourcesTier) | |
| { | |
| skip("Tiled resources not supported by device.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| memset(&heap_props, 0, sizeof(heap_props)); | |
| heap_props.Type = D3D12_HEAP_TYPE_DEFAULT; | |
| heap_desc.Properties = heap_props; | |
| heap_desc.Alignment = 0; | |
| heap_desc.SizeInBytes = 64 * TILE_SIZE; | |
| heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS; | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; | |
| resource_desc.Alignment = 0; | |
| resource_desc.Width = 64 * TILE_SIZE; | |
| resource_desc.Height = 1; | |
| resource_desc.DepthOrArraySize = 1; | |
| resource_desc.MipLevels = 1; | |
| resource_desc.Format = DXGI_FORMAT_UNKNOWN; | |
| resource_desc.SampleDesc.Count = 1; | |
| resource_desc.SampleDesc.Quality = 0; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; | |
| resource_desc.Flags = 0; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&resource); | |
| ok(hr == S_OK, "Failed to create reserved buffer, hr %#x.\n", hr); | |
| output_resource = create_default_buffer(context.device, 64 * sizeof(uint32_t), | |
| D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| memset(rs_params, 0, sizeof(rs_params)); | |
| memset(&rs_desc, 0, sizeof(rs_desc)); | |
| rs_desc.NumParameters = ARRAY_SIZE(rs_params); | |
| rs_desc.pParameters = rs_params; | |
| rs_params[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; | |
| rs_params[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; | |
| create_root_signature(context.device, &rs_desc, &context.root_signature); | |
| context.pipeline_state = create_compute_pipeline_state( | |
| context.device, context.root_signature, update_tile_mappings_dxbc); | |
| for (iter = 0; iter < 100; iter++) | |
| { | |
| D3D12_TILE_REGION_SIZE resource_tile_region_size; | |
| D3D12_TILED_RESOURCE_COORDINATE resource_coord; | |
| D3D12_TILE_RANGE_FLAGS heap_range_flags; | |
| ID3D12Resource *placed_resource; | |
| ID3D12Resource *upload; | |
| UINT heap_tile_offset; | |
| uint32_t *upload_data; | |
| UINT heap_tile_count; | |
| ID3D12Heap *new_heap; | |
| const struct mappings | |
| { | |
| UINT resource_tile; | |
| UINT heap_tile; | |
| UINT count; | |
| D3D12_TILE_RANGE_FLAGS flags; | |
| } mappings[] = { | |
| { 0, 0, 64, D3D12_TILE_RANGE_FLAG_NULL }, | |
| { 4 + (iter & 31), 8 + (iter & 1), 3, D3D12_TILE_RANGE_FLAG_NONE }, | |
| { 1 + (iter & 14), 2 + (iter & 4), 40, D3D12_TILE_RANGE_FLAG_NONE }, | |
| { 13 + (iter & 9), 0, 9, D3D12_TILE_RANGE_FLAG_NULL }, | |
| { 13 + (iter & 7), 19 + (iter & 4), 8, D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE }, | |
| { 30 + (iter & 5), 0, 7, D3D12_TILE_RANGE_FLAG_NULL }, | |
| { 1 + (iter & 3), 0, 7, D3D12_TILE_RANGE_FLAG_NULL }, | |
| }; | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&new_heap); | |
| ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr); | |
| hr = ID3D12Device_CreatePlacedResource(context.device, new_heap, 0, &resource_desc, | |
| D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&placed_resource); | |
| ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr); | |
| /* Destroy the old heap while it has mappings to the heap, then rebind those pages. Should not explode. */ | |
| if (heap) | |
| ID3D12Heap_Release(heap); | |
| heap = new_heap; | |
| upload_data = malloc(resource_desc.Width); | |
| for (i = 0; i < resource_desc.Width / 4; i++) | |
| upload_data[i] = i + 1; | |
| upload = create_upload_buffer(context.device, resource_desc.Width, upload_data); | |
| ID3D12GraphicsCommandList_CopyResource(context.list, placed_resource, upload); | |
| ID3D12GraphicsCommandList_Close(context.list); | |
| exec_command_list(context.queue, context.list); | |
| ID3D12GraphicsCommandList_Reset(context.list, context.allocator, NULL); | |
| free(upload_data); | |
| for (i = 0; i < ARRAY_SIZE(mappings); i++) | |
| { | |
| memset(&resource_coord, 0, sizeof(resource_coord)); | |
| memset(&resource_tile_region_size, 0, sizeof(resource_tile_region_size)); | |
| resource_coord.X = mappings[i].resource_tile; | |
| resource_tile_region_size.NumTiles = mappings[i].count; | |
| resource_tile_region_size.UseBox = FALSE; | |
| heap_range_flags = mappings[i].flags; | |
| heap_tile_offset = mappings[i].heap_tile; | |
| heap_tile_count = mappings[i].count; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 1, &resource_coord, &resource_tile_region_size, heap, 1, | |
| &heap_range_flags, &heap_tile_offset, &heap_tile_count, D3D12_TILE_MAPPING_FLAG_NONE); | |
| } | |
| #define OFFSET_INTO_PAGE 50000 | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, context.root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state); | |
| ID3D12GraphicsCommandList_SetComputeRootShaderResourceView(context.list, 0, | |
| ID3D12Resource_GetGPUVirtualAddress(resource) + OFFSET_INTO_PAGE); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, | |
| ID3D12Resource_GetGPUVirtualAddress(output_resource)); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, output_resource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, | |
| D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(output_resource, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| reset_command_list(context.list, context.allocator); | |
| for (i = 0; i < 64; i++) | |
| { | |
| uint32_t expected = 0; | |
| for (j = 0; j < ARRAY_SIZE(mappings); j++) | |
| { | |
| if (i >= mappings[j].resource_tile && i < mappings[j].resource_tile + mappings[j].count) | |
| { | |
| if (mappings[j].flags == D3D12_TILE_RANGE_FLAG_NULL) | |
| expected = 0; | |
| else if (mappings[j].flags == D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE) | |
| expected = mappings[j].heap_tile * TILE_SIZE / 4 + OFFSET_INTO_PAGE / 4 + 1; | |
| else | |
| expected = (mappings[j].heap_tile + (i - mappings[j].resource_tile)) * TILE_SIZE / 4 + OFFSET_INTO_PAGE / 4 + 1; | |
| } | |
| } | |
| ok(expected == get_readback_uint(&rb, i, 0, 0), | |
| "Iter %u: value %u: Expected %u, got %u.\n", iter, i, expected, get_readback_uint(&rb, i, 0, 0)); | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(placed_resource); | |
| ID3D12Resource_Release(upload); | |
| } | |
| ID3D12Resource_Release(resource); | |
| ID3D12Resource_Release(output_resource); | |
| ID3D12Heap_Release(heap); | |
| destroy_test_context(&context); | |
| } | |
| void test_update_tile_mappings(void) | |
| { | |
| D3D12_TILED_RESOURCE_COORDINATE region_offsets[8]; | |
| ID3D12PipelineState *check_texture_array_pipeline; | |
| ID3D12PipelineState *check_texture_3d_pipeline; | |
| D3D12_ROOT_SIGNATURE_DESC root_signature_desc; | |
| ID3D12PipelineState *clear_texture_pipeline; | |
| ID3D12PipelineState *check_texture_pipeline; | |
| ID3D12PipelineState *check_buffer_pipeline; | |
| ID3D12Resource *resource, *readback_buffer; | |
| D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc; | |
| ID3D12DescriptorHeap *cpu_heap, *gpu_heap; | |
| ID3D12RootSignature *clear_root_signature; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; | |
| D3D12_DESCRIPTOR_RANGE descriptor_range; | |
| D3D12_ROOT_PARAMETER root_parameters[2]; | |
| D3D12_TILE_REGION_SIZE region_sizes[8]; | |
| D3D12_GPU_VIRTUAL_ADDRESS readback_va; | |
| D3D12_PACKED_MIP_INFO packed_mip_info; | |
| D3D12_HEAP_PROPERTIES heap_properties; | |
| D3D12_SUBRESOURCE_TILING tilings[10]; | |
| D3D12_TILE_RANGE_FLAGS tile_flags[8]; | |
| ID3D12RootSignature *root_signature; | |
| D3D12_RESOURCE_DESC resource_desc; | |
| struct test_context_desc desc; | |
| struct resource_readback rb; | |
| struct test_context context; | |
| D3D12_TILE_SHAPE tile_shape; | |
| unsigned int i, j, x, y, z; | |
| D3D12_HEAP_DESC heap_desc; | |
| UINT tile_offsets[8]; | |
| UINT tile_counts[8]; | |
| ID3D12Heap *heap; | |
| UINT num_tilings; | |
| D3D12_BOX box; | |
| HRESULT hr; | |
| #include "shaders/sparse/headers/update_tile_mappings.h" | |
| #include "shaders/sparse/headers/update_tile_mappings_texture.h" | |
| #include "shaders/sparse/headers/update_tile_mappings_texture_array.h" | |
| #include "shaders/sparse/headers/update_tile_mappings_texture_3d.h" | |
| #include "shaders/sparse/headers/update_tile_mappings_cs_clear.h" | |
| static const uint32_t buffer_region_tiles[] = | |
| { | |
| /* 0 1 2 3 4 5 6 7 8 9 */ | |
| /*0*/ 33, 34, 35, 36, 37, 6, 7, 8, 9, 10, | |
| /*1*/ 11, 12, 38, 39, 40, 41, 1, 18, 2, 20, | |
| /*2*/ 21, 22, 23, 3, 4, 4, 4, 0, 0, 25, | |
| /*3*/ 26, 27, 28, 29, 30, 36, 37, 38, 39, 40, | |
| /*4*/ 9, 11, 43, 44, 45, 46, 45, 46, 49, 50, | |
| /*5*/ 0, 0, 17, 18, 19, 20, 21, 22, 23, 24, | |
| /*6*/ 61, 62, 63, 12, | |
| }; | |
| static const uint32_t texture_region_tiles[] = | |
| { | |
| 1, 2, 4, 5, 6, 7, 1, 1, 9, 1, 17, 14, 8, 14, 3, 0, | |
| 17, 18, 19, 18, 19, 22, 23, 24, 25, 26, 27, 28, | |
| }; | |
| static const uint32_t texture_3d_region_tiles[] = | |
| { | |
| 3, 2, 0, 7, 8, 2, 4, 5, 6, | |
| }; | |
| 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; | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (!options.TiledResourcesTier) | |
| { | |
| 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; | |
| descriptor_range.RegisterSpace = 0; | |
| descriptor_range.OffsetInDescriptorsFromTableStart = 0; | |
| root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; | |
| root_parameters[0].DescriptorTable.NumDescriptorRanges = 1; | |
| root_parameters[0].DescriptorTable.pDescriptorRanges = &descriptor_range; | |
| root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; | |
| root_parameters[1].Descriptor.ShaderRegister = 0; | |
| root_parameters[1].Descriptor.RegisterSpace = 0; | |
| root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters); | |
| root_signature_desc.pParameters = root_parameters; | |
| root_signature_desc.NumStaticSamplers = 0; | |
| root_signature_desc.pStaticSamplers = NULL; | |
| root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; | |
| hr = create_root_signature(context.device, &root_signature_desc, &root_signature); | |
| ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); | |
| descriptor_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; | |
| root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; | |
| root_parameters[1].Constants.ShaderRegister = 0; | |
| root_parameters[1].Constants.RegisterSpace = 0; | |
| root_parameters[1].Constants.Num32BitValues = 4; | |
| root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| hr = create_root_signature(context.device, &root_signature_desc, &clear_root_signature); | |
| ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); | |
| clear_texture_pipeline = create_compute_pipeline_state(context.device, clear_root_signature, update_tile_mappings_cs_clear_dxbc); | |
| check_texture_pipeline = create_compute_pipeline_state(context.device, root_signature, update_tile_mappings_texture_dxbc); | |
| check_texture_array_pipeline = create_compute_pipeline_state(context.device, root_signature, update_tile_mappings_texture_array_dxbc); | |
| check_texture_3d_pipeline = create_compute_pipeline_state(context.device, root_signature, update_tile_mappings_texture_3d_dxbc); | |
| check_buffer_pipeline = create_compute_pipeline_state(context.device, root_signature, update_tile_mappings_dxbc); | |
| cpu_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 64); | |
| gpu_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 64); | |
| memset(&heap_properties, 0, sizeof(heap_properties)); | |
| heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT; | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; | |
| resource_desc.Alignment = 0; | |
| resource_desc.Width = 64 * sizeof(uint32_t); | |
| resource_desc.Height = 1; | |
| resource_desc.DepthOrArraySize = 1; | |
| resource_desc.MipLevels = 1; | |
| resource_desc.Format = DXGI_FORMAT_UNKNOWN; | |
| resource_desc.SampleDesc.Count = 1; | |
| resource_desc.SampleDesc.Quality = 0; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties, D3D12_HEAP_FLAG_NONE, | |
| &resource_desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&readback_buffer); | |
| ok(hr == S_OK, "Failed to create readback buffer, hr %#x.\n", hr); | |
| readback_va = ID3D12Resource_GetGPUVirtualAddress(readback_buffer); | |
| /* Test buffer tile mappings */ | |
| heap_desc.Properties = heap_properties; | |
| heap_desc.Alignment = 0; | |
| heap_desc.SizeInBytes = 64 * 65536; | |
| heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS; | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap); | |
| ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr); | |
| resource_desc.Width = 64 * 65536; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&resource); | |
| ok(hr == S_OK, "Failed to create reserved buffer, hr %#x.\n", hr); | |
| srv_desc.Format = DXGI_FORMAT_UNKNOWN; | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| srv_desc.Buffer.FirstElement = 0; | |
| srv_desc.Buffer.NumElements = resource_desc.Width / sizeof(uint32_t); | |
| srv_desc.Buffer.StructureByteStride = sizeof(uint32_t); | |
| srv_desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; | |
| ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, gpu_heap, 0)); | |
| uav_desc.Format = DXGI_FORMAT_R32_UINT; | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; | |
| uav_desc.Buffer.FirstElement = 0; | |
| uav_desc.Buffer.NumElements = resource_desc.Width / sizeof(uint32_t); | |
| uav_desc.Buffer.StructureByteStride = 0; | |
| uav_desc.Buffer.CounterOffsetInBytes = 0; | |
| uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, cpu_heap, 1)); | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, gpu_heap, 1)); | |
| /* Map entire buffer, linearly, and initialize tile data */ | |
| tile_offsets[0] = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 1, NULL, NULL, heap, 1, NULL, tile_offsets, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| for (i = 0; i < 64; i++) | |
| { | |
| UINT clear_value[4] = { 0, 0, 0, 0 }; | |
| D3D12_RECT clear_rect; | |
| set_rect(&clear_rect, 16384 * i, 0, 16384 * (i + 1), 1); | |
| clear_value[0] = i + 1; | |
| ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list, | |
| get_gpu_descriptor_handle(&context, gpu_heap, 1), | |
| get_cpu_descriptor_handle(&context, cpu_heap, 1), | |
| resource, clear_value, 1, &clear_rect); | |
| } | |
| transition_resource_state(context.list, resource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_buffer_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < 64; i++) | |
| { | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, i + 1, 0); | |
| } | |
| release_resource_readback(&rb); | |
| /* Test arbitrary tile mappings */ | |
| set_region_offset(®ion_offsets[0], 16, 0, 0, 0); | |
| set_region_offset(®ion_offsets[1], 18, 0, 0, 0); | |
| set_region_offset(®ion_offsets[2], 23, 0, 0, 0); | |
| set_region_offset(®ion_offsets[3], 40, 0, 0, 0); | |
| set_region_offset(®ion_offsets[4], 41, 0, 0, 0); | |
| set_region_offset(®ion_offsets[5], 63, 0, 0, 0); | |
| tile_offsets[0] = 0; | |
| tile_offsets[1] = 8; | |
| tile_offsets[2] = 10; | |
| tile_counts[0] = 3; | |
| tile_counts[1] = 1; | |
| tile_counts[2] = 2; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 6, region_offsets, NULL, heap, 3, NULL, tile_offsets, tile_counts, | |
| D3D12_TILE_MAPPING_FLAG_NONE); | |
| set_region_offset(®ion_offsets[0], 24, 0, 0, 0); | |
| set_region_offset(®ion_offsets[1], 50, 0, 0, 0); | |
| set_region_offset(®ion_offsets[2], 0, 0, 0, 0); | |
| set_region_offset(®ion_offsets[3], 52, 0, 0, 0); | |
| set_region_offset(®ion_offsets[4], 29, 0, 0, 0); | |
| set_region_size(®ion_sizes[0], 5, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[1], 2, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[2], 16, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[3], 8, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[4], 6, false, 0, 0, 0); | |
| tile_flags[0] = D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE; | |
| tile_flags[1] = D3D12_TILE_RANGE_FLAG_NULL; | |
| tile_flags[2] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_flags[3] = D3D12_TILE_RANGE_FLAG_SKIP; | |
| tile_flags[4] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_flags[5] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_offsets[0] = 3; | |
| tile_offsets[1] = 0; | |
| tile_offsets[2] = 32; | |
| tile_offsets[3] = 0; | |
| tile_offsets[4] = 37; | |
| tile_offsets[5] = 16; | |
| tile_counts[0] = 3; | |
| tile_counts[1] = 4; | |
| tile_counts[2] = 5; | |
| tile_counts[3] = 7; | |
| tile_counts[4] = 4; | |
| tile_counts[5] = 14; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 5, region_offsets, region_sizes, heap, 6, tile_flags, tile_offsets, tile_counts, | |
| D3D12_TILE_MAPPING_FLAG_NONE); | |
| set_region_offset(®ion_offsets[0], 46, 0, 0, 0); | |
| set_region_offset(®ion_offsets[1], 44, 0, 0, 0); | |
| set_region_size(®ion_sizes[0], 2, false, 0, 0, 0); | |
| ID3D12CommandQueue_CopyTileMappings(context.queue, | |
| resource, ®ion_offsets[0], resource, ®ion_offsets[1], | |
| ®ion_sizes[0], D3D12_TILE_MAPPING_FLAG_NONE); | |
| reset_command_list(context.list, context.allocator); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_buffer_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < ARRAY_SIZE(buffer_region_tiles); i++) | |
| { | |
| if (options.TiledResourcesTier > D3D12_TILED_RESOURCES_TIER_2 || buffer_region_tiles[i]) | |
| { | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, buffer_region_tiles[i], 0); | |
| } | |
| } | |
| release_resource_readback(&rb); | |
| /* Test mapping a single tile twice in one call */ | |
| set_region_offset(®ion_offsets[0], 0, 0, 0, 0); | |
| set_region_offset(®ion_offsets[1], 15, 0, 0, 0); | |
| set_region_size(®ion_sizes[0], 64, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[1], 3, false, 0, 0, 0); | |
| tile_flags[0] = D3D12_TILE_RANGE_FLAG_NULL; | |
| tile_flags[1] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_offsets[0] = 0; | |
| tile_offsets[1] = 8; | |
| tile_counts[0] = 64; | |
| tile_counts[1] = 4; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 2, region_offsets, region_sizes, heap, 2, tile_flags, tile_offsets, tile_counts, | |
| D3D12_TILE_MAPPING_FLAG_NONE); | |
| reset_command_list(context.list, context.allocator); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_buffer_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < ARRAY_SIZE(buffer_region_tiles); i++) | |
| { | |
| uint32_t expected = 0u; | |
| if (i >= region_offsets[1].X && i < region_offsets[1].X + region_sizes[1].NumTiles) | |
| expected = tile_offsets[1] + i + 1 - region_offsets[1].X; | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| /* WARP binds everything to NULL */ | |
| bug_if(use_warp_device) | |
| check_readback_data_uint(&rb, &box, expected, 0); | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(resource); | |
| ID3D12Heap_Release(heap); | |
| /* Test 2D image tile mappings */ | |
| heap_desc.Properties = heap_properties; | |
| heap_desc.Alignment = 0; | |
| heap_desc.SizeInBytes = 64 * 65536; | |
| heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES; | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap); | |
| ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr); | |
| 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_R32_UINT; | |
| 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_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&resource); | |
| ok(hr == S_OK, "Failed to create reserved texture, hr %#x.\n", hr); | |
| num_tilings = resource_desc.MipLevels; | |
| ID3D12Device_GetResourceTiling(context.device, resource, NULL, &packed_mip_info, &tile_shape, &num_tilings, 0, tilings); | |
| ok(packed_mip_info.NumStandardMips >= 3, "Unexpected number of standard mips %u.\n", packed_mip_info.NumStandardMips); | |
| srv_desc.Format = DXGI_FORMAT_R32_UINT; | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| srv_desc.Texture2D.MostDetailedMip = 0; | |
| srv_desc.Texture2D.MipLevels = resource_desc.MipLevels; | |
| srv_desc.Texture2D.PlaneSlice = 0; | |
| srv_desc.Texture2D.ResourceMinLODClamp = 0.0f; | |
| ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, gpu_heap, 0)); | |
| /* Map entire image */ | |
| tile_offsets[0] = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 1, NULL, NULL, heap, 1, NULL, tile_offsets, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| reset_command_list(context.list, context.allocator); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| for (i = 0, j = 0; i < resource_desc.MipLevels; i++) | |
| { | |
| uav_desc.Format = DXGI_FORMAT_R32_UINT; | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; | |
| uav_desc.Texture2D.MipSlice = i; | |
| uav_desc.Texture2D.PlaneSlice = 0; | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, cpu_heap, 1 + i)); | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, gpu_heap, 1 + i)); | |
| for (y = 0; y < max(1u, tilings[i].HeightInTiles); y++) | |
| { | |
| for (x = 0; x < max(1u, tilings[i].WidthInTiles); x++) | |
| { | |
| UINT clear_value[4] = { 0, 0, 0, 0 }; | |
| D3D12_RECT clear_rect; | |
| clear_value[0] = ++j; | |
| set_rect(&clear_rect, | |
| x * tile_shape.WidthInTexels, y * tile_shape.HeightInTexels, | |
| min(resource_desc.Width >> i, (x + 1) * tile_shape.WidthInTexels), | |
| min(resource_desc.Height >> i, (y + 1) * tile_shape.HeightInTexels)); | |
| ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list, | |
| get_gpu_descriptor_handle(&context, gpu_heap, 1 + i), | |
| get_cpu_descriptor_handle(&context, cpu_heap, 1 + i), | |
| resource, clear_value, 1, &clear_rect); | |
| } | |
| } | |
| } | |
| transition_resource_state(context.list, resource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_texture_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < j; i++) | |
| { | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, i + 1, 0); | |
| } | |
| release_resource_readback(&rb); | |
| set_region_offset(®ion_offsets[0], 2, 0, 0, 0); | |
| set_region_offset(®ion_offsets[1], 1, 1, 0, 0); | |
| set_region_offset(®ion_offsets[2], 1, 1, 0, 1); | |
| set_region_offset(®ion_offsets[3], 0, 3, 0, 0); | |
| set_region_size(®ion_sizes[0], 3, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[1], 4, true, 2, 2, 1); | |
| set_region_size(®ion_sizes[2], 2, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[3], 4, true, 4, 1, 1); | |
| tile_flags[0] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_flags[1] = D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE; | |
| tile_flags[2] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_flags[3] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_flags[4] = D3D12_TILE_RANGE_FLAG_SKIP; | |
| tile_flags[5] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_flags[6] = D3D12_TILE_RANGE_FLAG_NULL; | |
| tile_offsets[0] = 3; | |
| tile_offsets[1] = 0; | |
| tile_offsets[2] = 16; | |
| tile_offsets[3] = 7; | |
| tile_offsets[4] = 0; | |
| tile_offsets[5] = 2; | |
| tile_offsets[6] = 0; | |
| tile_counts[0] = 4; | |
| tile_counts[1] = 2; | |
| tile_counts[2] = 3; | |
| tile_counts[3] = 1; | |
| tile_counts[4] = 1; | |
| tile_counts[5] = 1; | |
| tile_counts[6] = 1; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 4, region_offsets, region_sizes, heap, 7, tile_flags, tile_offsets, tile_counts, | |
| D3D12_TILE_MAPPING_FLAG_NONE); | |
| set_region_offset(®ion_offsets[0], 3, 1, 0, 0); | |
| set_region_offset(®ion_offsets[1], 1, 2, 0, 0); | |
| set_region_size(®ion_sizes[0], 2, true, 1, 2, 1); | |
| ID3D12CommandQueue_CopyTileMappings(context.queue, | |
| resource, ®ion_offsets[0], resource, ®ion_offsets[1], | |
| ®ion_sizes[0], D3D12_TILE_MAPPING_FLAG_NONE); | |
| reset_command_list(context.list, context.allocator); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_texture_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < j; i++) | |
| { | |
| if (options.TiledResourcesTier > D3D12_TILED_RESOURCES_TIER_2 || texture_region_tiles[i]) | |
| { | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, texture_region_tiles[i], 0); | |
| } | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(resource); | |
| if (options.TiledResourcesTier >= D3D12_TILED_RESOURCES_TIER_3) | |
| { | |
| /* Test 3D image tile mappings */ | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; | |
| resource_desc.Alignment = 0; | |
| resource_desc.Width = 64; | |
| resource_desc.Height = 64; | |
| resource_desc.DepthOrArraySize = 32; | |
| resource_desc.MipLevels = 2; | |
| resource_desc.Format = DXGI_FORMAT_R32_UINT; | |
| 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_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&resource); | |
| ok(hr == S_OK, "Failed to create reserved texture, hr %#x.\n", hr); | |
| num_tilings = resource_desc.MipLevels; | |
| ID3D12Device_GetResourceTiling(context.device, resource, NULL, &packed_mip_info, &tile_shape, &num_tilings, 0, tilings); | |
| ok(packed_mip_info.NumStandardMips == 2, "Unexpected number of standard mips %u.\n", packed_mip_info.NumStandardMips); | |
| srv_desc.Format = DXGI_FORMAT_R32_UINT; | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| srv_desc.Texture3D.MostDetailedMip = 0; | |
| srv_desc.Texture3D.MipLevels = resource_desc.MipLevels; | |
| srv_desc.Texture3D.ResourceMinLODClamp = 0.0f; | |
| ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, gpu_heap, 0)); | |
| /* Map entire image */ | |
| tile_offsets[0] = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 1, NULL, NULL, heap, 1, NULL, tile_offsets, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| reset_command_list(context.list, context.allocator); | |
| for (i = 0, j = 0; i < resource_desc.MipLevels; i++) | |
| { | |
| uav_desc.Format = DXGI_FORMAT_R32_UINT; | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; | |
| uav_desc.Texture3D.MipSlice = i; | |
| uav_desc.Texture3D.FirstWSlice = 0; | |
| uav_desc.Texture3D.WSize = resource_desc.DepthOrArraySize >> i; | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, cpu_heap, 1 + i)); | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, gpu_heap, 1 + i)); | |
| /* ClearUnorderedAccessView only takes 2D coordinates so we have to | |
| * bring our own shader to initialize portions of a 3D image */ | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, clear_root_signature); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 1 + i)); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, clear_texture_pipeline); | |
| for (z = 0; z < max(1u, tilings[i].DepthInTiles); z++) | |
| { | |
| for (y = 0; y < max(1u, tilings[i].HeightInTiles); y++) | |
| { | |
| for (x = 0; x < max(1u, tilings[i].WidthInTiles); x++) | |
| { | |
| UINT shader_args[4]; | |
| shader_args[0] = tile_shape.WidthInTexels * x; | |
| shader_args[1] = tile_shape.HeightInTexels * y; | |
| shader_args[2] = tile_shape.DepthInTexels * z; | |
| shader_args[3] = ++j; | |
| ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, | |
| 1, ARRAY_SIZE(shader_args), shader_args, 0); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, | |
| tile_shape.WidthInTexels / 4, | |
| tile_shape.HeightInTexels / 4, | |
| tile_shape.DepthInTexels / 4); | |
| } | |
| } | |
| } | |
| } | |
| transition_resource_state(context.list, resource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_texture_3d_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < j; i++) | |
| { | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, i + 1, 0); | |
| } | |
| release_resource_readback(&rb); | |
| set_region_offset(®ion_offsets[0], 0, 0, 0, 0); | |
| set_region_offset(®ion_offsets[1], 0, 1, 1, 0); | |
| set_region_offset(®ion_offsets[2], 1, 1, 0, 0); | |
| set_region_offset(®ion_offsets[3], 1, 0, 0, 0); | |
| set_region_offset(®ion_offsets[4], 0, 1, 0, 0); | |
| set_region_size(®ion_sizes[0], 1, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[1], 3, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[2], 2, false, 0, 0, 0); | |
| set_region_size(®ion_sizes[3], 2, true, 1, 1, 2); | |
| set_region_size(®ion_sizes[4], 1, true, 1, 1, 1); | |
| tile_flags[0] = D3D12_TILE_RANGE_FLAG_NONE; | |
| tile_flags[1] = D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE; | |
| tile_flags[2] = D3D12_TILE_RANGE_FLAG_NULL; | |
| tile_offsets[0] = 2; | |
| tile_offsets[1] = 1; | |
| tile_offsets[2] = 0; | |
| tile_counts[0] = 6; | |
| tile_counts[1] = 2; | |
| tile_counts[2] = 1; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 5, region_offsets, region_sizes, heap, 3, tile_flags, tile_offsets, tile_counts, | |
| D3D12_TILE_MAPPING_FLAG_NONE); | |
| reset_command_list(context.list, context.allocator); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_texture_3d_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < j; i++) | |
| { | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, texture_3d_region_tiles[i], 0); | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(resource); | |
| } | |
| else | |
| { | |
| skip("Tiled resources tier 3 not supported.\n"); | |
| } | |
| if (options.TiledResourcesTier >= D3D12_TILED_RESOURCES_TIER_4) | |
| { | |
| /* Test 2D array image with mip tail */ | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; | |
| resource_desc.Alignment = 0; | |
| resource_desc.Width = 256; | |
| resource_desc.Height = 256; | |
| resource_desc.DepthOrArraySize = 4; | |
| resource_desc.MipLevels = 9; | |
| resource_desc.Format = DXGI_FORMAT_R32_UINT; | |
| 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_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&resource); | |
| ok(hr == S_OK, "Failed to create reserved texture, hr %#x.\n", hr); | |
| /* Map entire image */ | |
| tile_offsets[0] = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, resource, | |
| 1, NULL, NULL, heap, 1, NULL, tile_offsets, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| srv_desc.Format = DXGI_FORMAT_R32_UINT; | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| srv_desc.Texture2DArray.MostDetailedMip = 0; | |
| srv_desc.Texture2DArray.MipLevels = resource_desc.MipLevels; | |
| srv_desc.Texture2DArray.FirstArraySlice = 0; | |
| srv_desc.Texture2DArray.ArraySize = resource_desc.DepthOrArraySize; | |
| srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f; | |
| srv_desc.Texture2DArray.PlaneSlice = 0; | |
| ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, gpu_heap, 0)); | |
| reset_command_list(context.list, context.allocator); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| for (i = 0; i < (unsigned int)(resource_desc.MipLevels * resource_desc.DepthOrArraySize); i++) | |
| { | |
| UINT clear_value[4] = { 0, 0, 0, 0 }; | |
| clear_value[0] = i; | |
| uav_desc.Format = DXGI_FORMAT_R32_UINT; | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; | |
| uav_desc.Texture2DArray.MipSlice = i % resource_desc.MipLevels; | |
| uav_desc.Texture2DArray.FirstArraySlice = i / resource_desc.MipLevels; | |
| uav_desc.Texture2DArray.ArraySize = 1; | |
| uav_desc.Texture2DArray.PlaneSlice = 0; | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, cpu_heap, 1 + i)); | |
| ID3D12Device_CreateUnorderedAccessView(context.device, resource, NULL, &uav_desc, get_cpu_descriptor_handle(&context, gpu_heap, 1 + i)); | |
| ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list, | |
| get_gpu_descriptor_handle(&context, gpu_heap, 1 + i), | |
| get_cpu_descriptor_handle(&context, cpu_heap, 1 + i), | |
| resource, clear_value, 0, NULL); | |
| } | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, check_texture_array_pipeline); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, readback_va); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, readback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < (unsigned int)(resource_desc.MipLevels * resource_desc.DepthOrArraySize); i++) | |
| { | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, i, 0); | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(resource); | |
| } | |
| else | |
| { | |
| skip("Tiled resources tier 4 not supported.\n"); | |
| } | |
| ID3D12Heap_Release(heap); | |
| ID3D12DescriptorHeap_Release(gpu_heap); | |
| ID3D12DescriptorHeap_Release(cpu_heap); | |
| ID3D12Resource_Release(readback_buffer); | |
| ID3D12PipelineState_Release(clear_texture_pipeline); | |
| ID3D12PipelineState_Release(check_texture_3d_pipeline); | |
| ID3D12PipelineState_Release(check_texture_array_pipeline); | |
| ID3D12PipelineState_Release(check_texture_pipeline); | |
| ID3D12PipelineState_Release(check_buffer_pipeline); | |
| ID3D12RootSignature_Release(clear_root_signature); | |
| ID3D12RootSignature_Release(root_signature); | |
| destroy_test_context(&context); | |
| } | |
| void test_copy_tiles(void) | |
| { | |
| ID3D12Resource *tiled_resource, *dst_buffer, *src_buffer; | |
| D3D12_TILED_RESOURCE_COORDINATE region_offset; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| uint32_t tile_offset, buffer_offset; | |
| D3D12_TILE_REGION_SIZE region_size; | |
| D3D12_RESOURCE_DESC resource_desc; | |
| struct test_context_desc desc; | |
| struct resource_readback rb; | |
| struct test_context context; | |
| D3D12_HEAP_DESC heap_desc; | |
| uint32_t *buffer_data; | |
| unsigned int i, x, y; | |
| ID3D12Heap *heap; | |
| D3D12_BOX box; | |
| HRESULT hr; | |
| static const struct | |
| { | |
| uint32_t x; | |
| uint32_t y; | |
| uint32_t tile_idx; | |
| } | |
| image_tiles[] = | |
| { | |
| {1, 0, 0}, {2, 0, 1}, {1, 1, 2}, {2, 1, 3}, | |
| {3, 1, 4}, {0, 2, 5}, {1, 2, 6}, | |
| }; | |
| 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; | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (!options.TiledResourcesTier) | |
| { | |
| 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; | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; | |
| resource_desc.Alignment = 0; | |
| resource_desc.Width = heap_desc.SizeInBytes; | |
| resource_desc.Height = 1; | |
| resource_desc.DepthOrArraySize = 1; | |
| resource_desc.MipLevels = 1; | |
| resource_desc.Format = DXGI_FORMAT_UNKNOWN; | |
| resource_desc.SampleDesc.Count = 1; | |
| resource_desc.SampleDesc.Quality = 0; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE; | |
| hr = ID3D12Device_CreateCommittedResource(context.device, &heap_desc.Properties, D3D12_HEAP_FLAG_NONE, | |
| &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, (void **)&src_buffer); | |
| ok(hr == S_OK, "Failed to create buffer, hr %#x.\n", hr); | |
| hr = ID3D12Device_CreateCommittedResource(context.device, &heap_desc.Properties, D3D12_HEAP_FLAG_NONE, | |
| &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, (void **)&dst_buffer); | |
| ok(hr == S_OK, "Failed to create buffer, hr %#x.\n", hr); | |
| buffer_data = malloc(resource_desc.Width); | |
| for (i = 0; i < resource_desc.Width / sizeof(*buffer_data); i++) | |
| buffer_data[i] = i; | |
| upload_buffer_data(src_buffer, 0, resource_desc.Width, buffer_data, context.queue, context.list); | |
| reset_command_list(context.list, context.allocator); | |
| transition_resource_state(context.list, src_buffer, | |
| D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| /* Test buffer */ | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, (void **)&tiled_resource); | |
| ok(hr == S_OK, "Failed to create tiled buffer, hr %#x.\n", hr); | |
| heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS; | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap); | |
| ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr); | |
| tile_offset = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, tiled_resource, | |
| 1, NULL, NULL, heap, 1, NULL, &tile_offset, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| /* Copy source tiles 0-2 with a 32-byte offset to buffer tiles 4-6 */ | |
| set_region_offset(®ion_offset, 4, 0, 0, 0); | |
| set_region_size(®ion_size, 3, false, 0, 0, 0); | |
| buffer_offset = 32; | |
| ID3D12GraphicsCommandList_CopyTiles(context.list, tiled_resource, | |
| ®ion_offset, ®ion_size, src_buffer, buffer_offset, | |
| D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE); | |
| transition_resource_state(context.list, tiled_resource, | |
| D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(tiled_resource, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < 3 * TILE_SIZE / sizeof(*buffer_data); i += 1024) | |
| { | |
| uint32_t offset = i + 4 * TILE_SIZE / sizeof(*buffer_data); | |
| set_box(&box, offset, 0, 0, offset + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, buffer_data[i + buffer_offset / sizeof(*buffer_data)], 0); | |
| } | |
| release_resource_readback(&rb); | |
| reset_command_list(context.list, context.allocator); | |
| /* Read tiles 5-6 from the tiled resource */ | |
| set_region_offset(®ion_offset, 5, 0, 0, 0); | |
| set_region_size(®ion_size, 1, false, 0, 0, 0); | |
| ID3D12GraphicsCommandList_CopyTiles(context.list, tiled_resource, | |
| ®ion_offset, ®ion_size, dst_buffer, 0, | |
| D3D12_TILE_COPY_FLAG_SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER); | |
| /* NONE behaves the same as SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER */ | |
| set_region_offset(®ion_offset, 6, 0, 0, 0); | |
| ID3D12GraphicsCommandList_CopyTiles(context.list, tiled_resource, | |
| ®ion_offset, ®ion_size, dst_buffer, TILE_SIZE, | |
| D3D12_TILE_COPY_FLAG_NONE); | |
| transition_resource_state(context.list, dst_buffer, | |
| D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(dst_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < 2 * TILE_SIZE / sizeof(*buffer_data); i += 1024) | |
| { | |
| uint32_t offset = i + (TILE_SIZE + buffer_offset) / sizeof(*buffer_data); | |
| set_box(&box, i, 0, 0, i + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, buffer_data[offset], 0); | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(tiled_resource); | |
| ID3D12Heap_Release(heap); | |
| /* Test image */ | |
| 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 = 1; | |
| resource_desc.Format = DXGI_FORMAT_R32_UINT; | |
| 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_COPY_DEST, NULL, &IID_ID3D12Resource, (void **)&tiled_resource); | |
| ok(hr == S_OK, "Failed to create tiled buffer, hr %#x.\n", hr); | |
| heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES; | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap); | |
| ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr); | |
| tile_offset = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, tiled_resource, | |
| 1, NULL, NULL, heap, 1, NULL, &tile_offset, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| reset_command_list(context.list, context.allocator); | |
| /* Copy source tiles 0-3 to 2x2 region at (1,0) */ | |
| set_region_offset(®ion_offset, 1, 0, 0, 0); | |
| set_region_size(®ion_size, 4, true, 2, 2, 1); | |
| ID3D12GraphicsCommandList_CopyTiles(context.list, tiled_resource, | |
| ®ion_offset, ®ion_size, src_buffer, 0, | |
| D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE); | |
| /* Copy source tiles 4-6 to (3,1), (0,2) and (1,2) */ | |
| set_region_offset(®ion_offset, 3, 1, 0, 0); | |
| set_region_size(®ion_size, 3, false, 0, 0, 0); | |
| ID3D12GraphicsCommandList_CopyTiles(context.list, tiled_resource, | |
| ®ion_offset, ®ion_size, src_buffer, 4 * TILE_SIZE, | |
| D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE); | |
| transition_resource_state(context.list, tiled_resource, | |
| D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_texture_readback_with_command_list(tiled_resource, 0, &rb, context.queue, context.list); | |
| for (i = 0; i < ARRAY_SIZE(image_tiles); i++) | |
| { | |
| for (y = 0; y < 128; y += 32) | |
| { | |
| for (x = 0; x < 128; x += 32) | |
| { | |
| 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); | |
| check_readback_data_uint(&rb, &box, buffer_data[offset], 0); | |
| } | |
| } | |
| } | |
| release_resource_readback(&rb); | |
| reset_command_list(context.list, context.allocator); | |
| transition_resource_state(context.list, dst_buffer, | |
| D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST); | |
| /* Read 0-3 to 2x2 region at (1,0) */ | |
| set_region_offset(®ion_offset, 1, 0, 0, 0); | |
| set_region_size(®ion_size, 4, true, 2, 2, 1); | |
| ID3D12GraphicsCommandList_CopyTiles(context.list, tiled_resource, | |
| ®ion_offset, ®ion_size, dst_buffer, 0, | |
| D3D12_TILE_COPY_FLAG_SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER); | |
| /* Read tiles (3,1), (0,2) and (1,2) */ | |
| set_region_offset(®ion_offset, 3, 1, 0, 0); | |
| set_region_size(®ion_size, 3, false, 0, 0, 0); | |
| ID3D12GraphicsCommandList_CopyTiles(context.list, tiled_resource, | |
| ®ion_offset, ®ion_size, dst_buffer, 4 * TILE_SIZE, | |
| D3D12_TILE_COPY_FLAG_NONE); | |
| transition_resource_state(context.list, dst_buffer, | |
| D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(dst_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < ARRAY_SIZE(image_tiles); i++) | |
| { | |
| for (x = 0; x < TILE_SIZE / sizeof(uint32_t); x += 1024) | |
| { | |
| uint32_t offset = image_tiles[i].tile_idx * TILE_SIZE / sizeof(uint32_t) + x; | |
| set_box(&box, offset, 0, 0, offset + 1, 1, 1); | |
| check_readback_data_uint(&rb, &box, buffer_data[offset], 0); | |
| } | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(tiled_resource); | |
| ID3D12Heap_Release(heap); | |
| ID3D12Resource_Release(src_buffer); | |
| ID3D12Resource_Release(dst_buffer); | |
| free(buffer_data); | |
| destroy_test_context(&context); | |
| #undef TILE_SIZE | |
| } | |
| static void test_buffer_feedback_instructions(bool use_dxil) | |
| { | |
| #define TILE_SIZE 65536 | |
| D3D12_TILED_RESOURCE_COORDINATE tile_regions[2]; | |
| D3D12_ROOT_SIGNATURE_DESC root_signature_desc; | |
| D3D12_DESCRIPTOR_RANGE descriptor_ranges[2]; | |
| ID3D12DescriptorHeap *cpu_heap, *gpu_heap; | |
| ID3D12Resource *tiled_buffer, *out_buffer; | |
| D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; | |
| D3D12_ROOT_PARAMETER root_parameters[3]; | |
| ID3D12PipelineState *pipeline_state; | |
| ID3D12RootSignature *root_signature; | |
| D3D12_RESOURCE_DESC resource_desc; | |
| struct test_context_desc desc; | |
| struct resource_readback rb; | |
| struct test_context context; | |
| D3D12_HEAP_DESC heap_desc; | |
| unsigned int i, j; | |
| ID3D12Heap *heap; | |
| UINT tile_offset; | |
| bool test_is_raw; | |
| HRESULT hr; | |
| #include "shaders/sparse/headers/buffer_feedback_ld_typed.h" | |
| #include "shaders/sparse/headers/buffer_feedback_ld_raw.h" | |
| #include "shaders/sparse/headers/buffer_feedback_ld_structured.h" | |
| #include "shaders/sparse/headers/buffer_feedback_ld_typed_uav.h" | |
| const struct | |
| { | |
| D3D12_SHADER_BYTECODE cs_dxbc; | |
| D3D12_SHADER_BYTECODE cs_dxil; | |
| bool is_structured; | |
| bool is_raw; | |
| bool is_uav; | |
| } | |
| tests[] = | |
| { | |
| { buffer_feedback_ld_typed_dxbc, buffer_feedback_ld_typed_dxil, false, false, false }, | |
| { buffer_feedback_ld_typed_uav_dxbc, buffer_feedback_ld_typed_uav_dxil, false, false, true }, | |
| { buffer_feedback_ld_raw_dxbc, buffer_feedback_ld_raw_dxil, false, true, false }, | |
| { buffer_feedback_ld_structured_dxbc, buffer_feedback_ld_structured_dxil, true, false, false }, | |
| }; | |
| struct shader_args | |
| { | |
| uint32_t stride; | |
| } | |
| shader_args; | |
| memset(&desc, 0, sizeof(desc)); | |
| desc.no_render_target = true; | |
| if (!init_test_context(&context, &desc)) | |
| return; | |
| if (use_dxil && !context_supports_dxil(&context)) | |
| { | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (options.TiledResourcesTier < D3D12_TILED_RESOURCES_TIER_2) | |
| { | |
| skip("Tiled resources Tier 2 not supported by device.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| descriptor_ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; | |
| descriptor_ranges[0].NumDescriptors = 1; | |
| descriptor_ranges[0].BaseShaderRegister = 0; | |
| descriptor_ranges[0].RegisterSpace = 0; | |
| descriptor_ranges[0].OffsetInDescriptorsFromTableStart = 0; | |
| descriptor_ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; | |
| descriptor_ranges[1].NumDescriptors = 1; | |
| descriptor_ranges[1].BaseShaderRegister = 1; | |
| descriptor_ranges[1].RegisterSpace = 0; | |
| descriptor_ranges[1].OffsetInDescriptorsFromTableStart = 1; | |
| root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; | |
| root_parameters[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(descriptor_ranges); | |
| root_parameters[0].DescriptorTable.pDescriptorRanges = descriptor_ranges; | |
| root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; | |
| root_parameters[1].Descriptor.ShaderRegister = 0; | |
| root_parameters[1].Descriptor.RegisterSpace = 0; | |
| root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; | |
| root_parameters[2].Constants.Num32BitValues = sizeof(shader_args) / sizeof(uint32_t); | |
| root_parameters[2].Constants.ShaderRegister = 0; | |
| root_parameters[2].Constants.RegisterSpace = 0; | |
| root_parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters); | |
| root_signature_desc.pParameters = root_parameters; | |
| root_signature_desc.NumStaticSamplers = 0; | |
| root_signature_desc.pStaticSamplers = NULL; | |
| root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; | |
| hr = create_root_signature(context.device, &root_signature_desc, &root_signature); | |
| ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); | |
| memset(&heap_desc, 0, sizeof(heap_desc)); | |
| heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; | |
| heap_desc.SizeInBytes = TILE_SIZE * 2; | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; | |
| resource_desc.Alignment = 0; | |
| resource_desc.Width = 128 * sizeof(uint32_t); | |
| resource_desc.Height = 1; | |
| resource_desc.DepthOrArraySize = 1; | |
| resource_desc.MipLevels = 1; | |
| resource_desc.Format = DXGI_FORMAT_UNKNOWN; | |
| resource_desc.SampleDesc.Count = 1; | |
| resource_desc.SampleDesc.Quality = 0; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateCommittedResource(context.device, &heap_desc.Properties, D3D12_HEAP_FLAG_NONE, | |
| &resource_desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, (void **)&out_buffer); | |
| ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr); | |
| resource_desc.Width = 4 * TILE_SIZE; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&tiled_buffer); | |
| ok(hr == S_OK, "Failed to create reserved resource, hr %#x.\n", hr); | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap); | |
| ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr); | |
| /* Map the 0k-64k range and the 128k-192k range, leave the rest unmapped */ | |
| set_region_offset(&tile_regions[0], 0, 0, 0, 0); | |
| set_region_offset(&tile_regions[1], 2, 0, 0, 0); | |
| tile_offset = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, tiled_buffer, | |
| ARRAY_SIZE(tile_regions), tile_regions, NULL, heap, 1, NULL, | |
| &tile_offset, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| gpu_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2); | |
| cpu_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1); | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; | |
| uav_desc.Format = DXGI_FORMAT_R32_UINT; | |
| uav_desc.Buffer.FirstElement = 0; | |
| uav_desc.Buffer.NumElements = resource_desc.Width / sizeof(uint32_t); | |
| uav_desc.Buffer.StructureByteStride = 0; | |
| uav_desc.Buffer.CounterOffsetInBytes = 0; | |
| uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; | |
| ID3D12Device_CreateUnorderedAccessView(context.device, tiled_buffer, NULL, &uav_desc, get_cpu_descriptor_handle(&context, cpu_heap, 0)); | |
| ID3D12Device_CreateUnorderedAccessView(context.device, tiled_buffer, NULL, &uav_desc, get_cpu_descriptor_handle(&context, gpu_heap, 1)); | |
| for (i = 0; i < resource_desc.Width / TILE_SIZE; i++) | |
| { | |
| UINT clear_values[] = { i + 1, 0, 0, 0 }; | |
| D3D12_RECT rect; | |
| set_rect(&rect, i * TILE_SIZE / sizeof(uint32_t), 0, (i + 1) * TILE_SIZE / sizeof(uint32_t), 1); | |
| ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list, | |
| get_gpu_descriptor_handle(&context, gpu_heap, 1), | |
| get_cpu_descriptor_handle(&context, cpu_heap, 0), | |
| tiled_buffer, clear_values, 1, &rect); | |
| }; | |
| transition_resource_state(context.list, tiled_buffer, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); | |
| for (i = 0; i < ARRAY_SIZE(tests); i++) | |
| { | |
| vkd3d_test_set_context("Test %u", i); | |
| test_is_raw = (i == 2) || (i == 3); | |
| todo_if(use_dxil && test_is_raw) | |
| pipeline_state = create_compute_pipeline_state(context.device, | |
| root_signature, use_dxil ? tests[i].cs_dxil : tests[i].cs_dxbc); | |
| /* This will fail for SSBO buffer feedback case on DXIL. */ | |
| todo_if(use_dxil && test_is_raw) | |
| ok(!!pipeline_state, "Failed to create pipeline state.\n"); | |
| if (!pipeline_state) | |
| continue; | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; | |
| srv_desc.Format = tests[i].is_structured ? DXGI_FORMAT_UNKNOWN : | |
| (tests[i].is_raw ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R32_UINT); | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| srv_desc.Buffer.FirstElement = 0; | |
| srv_desc.Buffer.NumElements = resource_desc.Width / sizeof(uint32_t); | |
| srv_desc.Buffer.StructureByteStride = tests[i].is_structured ? sizeof(uint32_t) : 0; | |
| srv_desc.Buffer.Flags = tests[i].is_raw ? D3D12_BUFFER_SRV_FLAG_RAW : D3D12_BUFFER_SRV_FLAG_NONE; | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; | |
| uav_desc.Format = srv_desc.Format; | |
| uav_desc.Buffer.FirstElement = srv_desc.Buffer.FirstElement; | |
| uav_desc.Buffer.NumElements = srv_desc.Buffer.NumElements; | |
| uav_desc.Buffer.StructureByteStride = srv_desc.Buffer.StructureByteStride; | |
| uav_desc.Buffer.CounterOffsetInBytes = 0; | |
| uav_desc.Buffer.Flags = tests[i].is_raw ? D3D12_BUFFER_UAV_FLAG_RAW : D3D12_BUFFER_UAV_FLAG_NONE; | |
| if (tests[i].is_uav) | |
| { | |
| ID3D12Device_CreateUnorderedAccessView(context.device, tiled_buffer, NULL, &uav_desc, get_cpu_descriptor_handle(&context, gpu_heap, 1)); | |
| transition_resource_state(context.list, tiled_buffer, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| } | |
| else | |
| ID3D12Device_CreateShaderResourceView(context.device, tiled_buffer, &srv_desc, get_cpu_descriptor_handle(&context, gpu_heap, 0)); | |
| transition_resource_state(context.list, out_buffer, | |
| D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| shader_args.stride = resource_desc.Width / 64; | |
| if (!tests[i].is_raw) | |
| shader_args.stride /= sizeof(uint32_t); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, pipeline_state); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 1, ID3D12Resource_GetGPUVirtualAddress(out_buffer)); | |
| ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, 2, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, out_buffer, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| if (tests[i].is_uav) | |
| { | |
| transition_resource_state(context.list, tiled_buffer, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); | |
| } | |
| get_buffer_readback_with_command_list(out_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (j = 0; j < 64; j++) | |
| { | |
| D3D12_BOX box; | |
| UINT tile_index = j / 16; | |
| set_box(&box, 2 * j, 0, 0, 2 * j + 1, 1, 1); | |
| todo_if(test_is_raw) check_readback_data_uint(&rb, &box, (tile_index & 1) ? 0 : (tile_index + 1), 0); | |
| set_box(&box, 2 * j + 1, 0, 0, 2 * j + 2, 1, 1); | |
| todo_if(test_is_raw) check_readback_data_uint(&rb, &box, (tile_index & 1) ? 0 : 1, 0); | |
| } | |
| release_resource_readback(&rb); | |
| reset_command_list(context.list, context.allocator); | |
| ID3D12PipelineState_Release(pipeline_state); | |
| } | |
| ID3D12DescriptorHeap_Release(cpu_heap); | |
| ID3D12DescriptorHeap_Release(gpu_heap); | |
| ID3D12Heap_Release(heap); | |
| ID3D12Resource_Release(tiled_buffer); | |
| ID3D12Resource_Release(out_buffer); | |
| ID3D12RootSignature_Release(root_signature); | |
| destroy_test_context(&context); | |
| #undef TILE_SIZE | |
| } | |
| void test_buffer_feedback_instructions_sm51(void) | |
| { | |
| test_buffer_feedback_instructions(false); | |
| } | |
| void test_buffer_feedback_instructions_dxil(void) | |
| { | |
| test_buffer_feedback_instructions(true); | |
| } | |
| static void test_texture_feedback_instructions(bool use_dxil) | |
| { | |
| #define TILE_SIZE 65536 | |
| ID3D12DescriptorHeap *gpu_heap, *sampler_heap, *rtv_heap; | |
| ID3D12Resource *tiled_image, *color_rt, *residency_rt; | |
| D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc; | |
| D3D12_TILED_RESOURCE_COORDINATE tile_regions[3]; | |
| D3D12_ROOT_SIGNATURE_DESC root_signature_desc; | |
| D3D12_DESCRIPTOR_RANGE descriptor_ranges[3]; | |
| D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; | |
| D3D12_ROOT_PARAMETER root_parameters[3]; | |
| D3D12_RENDER_TARGET_VIEW_DESC rtv_desc; | |
| ID3D12PipelineState *pipeline_state; | |
| ID3D12RootSignature *root_signature; | |
| D3D12_RESOURCE_DESC resource_desc; | |
| D3D12_SAMPLER_DESC sampler_desc; | |
| struct test_context_desc desc; | |
| struct resource_readback rb; | |
| struct test_context context; | |
| D3D12_HEAP_DESC heap_desc; | |
| D3D12_VIEWPORT viewport; | |
| D3D12_RECT scissor; | |
| ID3D12Heap *heap; | |
| UINT tile_offset; | |
| unsigned int i; | |
| HRESULT hr; | |
| #include "shaders/sparse/headers/texture_feedback_vs.h" | |
| #include "shaders/sparse/headers/texture_feedback_sample.h" | |
| #include "shaders/sparse/headers/texture_feedback_sample_bias.h" | |
| #include "shaders/sparse/headers/texture_feedback_sample_grad.h" | |
| #include "shaders/sparse/headers/texture_feedback_sample_lod.h" | |
| #include "shaders/sparse/headers/texture_feedback_gather.h" | |
| #include "shaders/sparse/headers/texture_feedback_gather_po.h" | |
| #include "shaders/sparse/headers/texture_feedback_ld.h" | |
| #include "shaders/sparse/headers/texture_feedback_ld_uav.h" | |
| struct shader_args | |
| { | |
| float args[4]; | |
| }; | |
| const struct | |
| { | |
| D3D12_SHADER_BYTECODE ps_dxbc; | |
| D3D12_SHADER_BYTECODE ps_dxil; | |
| uint32_t expected_mip; | |
| struct shader_args args; | |
| bool is_gather; | |
| } | |
| tests[] = | |
| { | |
| { texture_feedback_sample_dxbc, texture_feedback_sample_dxil, 0, {{0.0f}} }, | |
| { texture_feedback_sample_dxbc, texture_feedback_sample_dxil, 1, {{1.0f}} }, | |
| { texture_feedback_sample_bias_dxbc, texture_feedback_sample_bias_dxil, 0, {{0.0f, 0.0f}} }, | |
| { texture_feedback_sample_bias_dxbc, texture_feedback_sample_bias_dxil, 1, {{1.0f, 0.0f}} }, | |
| { texture_feedback_sample_bias_dxbc, texture_feedback_sample_bias_dxil, 1, {{0.0f, 1.0f}} }, | |
| { texture_feedback_sample_grad_dxbc, texture_feedback_sample_grad_dxil, 0, {{0.0f, 0.0f, 0.0f}} }, | |
| { texture_feedback_sample_grad_dxbc, texture_feedback_sample_grad_dxil, 1, {{0.0f, 1.0f, 1.0f}} }, | |
| { texture_feedback_sample_lod_dxbc, texture_feedback_sample_lod_dxil, 0, {{0.0f}} }, | |
| { texture_feedback_sample_lod_dxbc, texture_feedback_sample_lod_dxil, 1, {{1.0f}} }, | |
| { texture_feedback_gather_dxbc, texture_feedback_gather_dxil, 0, {{0.0f}}, true }, | |
| { texture_feedback_gather_po_dxbc, texture_feedback_gather_po_dxil, 0, {{0.0f, 0.0f}}, true }, | |
| { texture_feedback_ld_dxbc, texture_feedback_ld_dxil, 0, {{0.0f}} }, | |
| { texture_feedback_ld_uav_dxbc, texture_feedback_ld_uav_dxil, 0, {{0.0f}} }, | |
| }; | |
| static const FLOAT clear_colors[2][4] = { | |
| { 0.2f, 0.4f, 0.6f, 0.8f }, | |
| { 0.5f, 0.5f, 0.5f, 0.5f }, | |
| }; | |
| memset(&desc, 0, sizeof(desc)); | |
| desc.no_render_target = true; | |
| if (!init_test_context(&context, &desc)) | |
| return; | |
| if (use_dxil && !context_supports_dxil(&context)) | |
| { | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (options.TiledResourcesTier < D3D12_TILED_RESOURCES_TIER_2) | |
| { | |
| skip("Tiled resources Tier 2 not supported by device.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| descriptor_ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; | |
| descriptor_ranges[0].NumDescriptors = 1; | |
| descriptor_ranges[0].BaseShaderRegister = 0; | |
| descriptor_ranges[0].RegisterSpace = 0; | |
| descriptor_ranges[0].OffsetInDescriptorsFromTableStart = 0; | |
| descriptor_ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; | |
| descriptor_ranges[1].NumDescriptors = 1; | |
| descriptor_ranges[1].BaseShaderRegister = 2; | |
| descriptor_ranges[1].RegisterSpace = 0; | |
| descriptor_ranges[1].OffsetInDescriptorsFromTableStart = 1; | |
| descriptor_ranges[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; | |
| descriptor_ranges[2].NumDescriptors = 1; | |
| descriptor_ranges[2].BaseShaderRegister = 0; | |
| descriptor_ranges[2].RegisterSpace = 0; | |
| descriptor_ranges[2].OffsetInDescriptorsFromTableStart = 0; | |
| root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; | |
| root_parameters[0].DescriptorTable.NumDescriptorRanges = 2; | |
| root_parameters[0].DescriptorTable.pDescriptorRanges = &descriptor_ranges[0]; | |
| root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; | |
| root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; | |
| root_parameters[1].DescriptorTable.NumDescriptorRanges = 1; | |
| root_parameters[1].DescriptorTable.pDescriptorRanges = &descriptor_ranges[2]; | |
| root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; | |
| root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; | |
| root_parameters[2].Constants.Num32BitValues = sizeof(struct shader_args) / sizeof(uint32_t); | |
| root_parameters[2].Constants.ShaderRegister = 0; | |
| root_parameters[2].Constants.RegisterSpace = 0; | |
| root_parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; | |
| root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters); | |
| root_signature_desc.pParameters = root_parameters; | |
| root_signature_desc.NumStaticSamplers = 0; | |
| root_signature_desc.pStaticSamplers = NULL; | |
| root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; | |
| hr = create_root_signature(context.device, &root_signature_desc, &root_signature); | |
| ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); | |
| memset(&heap_desc, 0, sizeof(heap_desc)); | |
| heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; | |
| heap_desc.SizeInBytes = TILE_SIZE * 3; | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; | |
| resource_desc.Alignment = 0; | |
| resource_desc.Width = 256; | |
| resource_desc.Height = 256; | |
| resource_desc.DepthOrArraySize = 1; | |
| resource_desc.MipLevels = 1; | |
| resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| resource_desc.SampleDesc.Count = 1; | |
| resource_desc.SampleDesc.Quality = 0; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; | |
| hr = ID3D12Device_CreateCommittedResource(context.device, &heap_desc.Properties, D3D12_HEAP_FLAG_NONE, | |
| &resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&color_rt); | |
| ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr); | |
| resource_desc.Format = DXGI_FORMAT_R32_UINT; | |
| hr = ID3D12Device_CreateCommittedResource(context.device, &heap_desc.Properties, D3D12_HEAP_FLAG_NONE, | |
| &resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&residency_rt); | |
| ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr); | |
| resource_desc.MipLevels = 2; | |
| resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, | |
| D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&tiled_image); | |
| ok(hr == S_OK, "Failed to create reserved resource, hr %#x.\n", hr); | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap); | |
| ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr); | |
| /* Map top-left + bottom-right of mip 0 + entire mip 1 */ | |
| set_region_offset(&tile_regions[0], 0, 0, 0, 0); | |
| set_region_offset(&tile_regions[1], 1, 1, 0, 0); | |
| set_region_offset(&tile_regions[2], 0, 0, 0, 1); | |
| tile_offset = 0; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, tiled_image, | |
| ARRAY_SIZE(tile_regions), tile_regions, NULL, heap, 1, NULL, | |
| &tile_offset, NULL, D3D12_TILE_MAPPING_FLAG_NONE); | |
| rtv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 4); | |
| gpu_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2); | |
| sampler_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 1); | |
| rtv_desc.Format = DXGI_FORMAT_UNKNOWN; | |
| rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; | |
| rtv_desc.Texture2D.MipSlice = 0; | |
| rtv_desc.Texture2D.PlaneSlice = 0; | |
| ID3D12Device_CreateRenderTargetView(context.device, color_rt, &rtv_desc, get_cpu_rtv_handle(&context, rtv_heap, 0)); | |
| ID3D12Device_CreateRenderTargetView(context.device, residency_rt, &rtv_desc, get_cpu_rtv_handle(&context, rtv_heap, 1)); | |
| ID3D12Device_CreateRenderTargetView(context.device, tiled_image, &rtv_desc, get_cpu_rtv_handle(&context, rtv_heap, 2)); | |
| rtv_desc.Texture2D.MipSlice = 1; | |
| ID3D12Device_CreateRenderTargetView(context.device, tiled_image, &rtv_desc, get_cpu_rtv_handle(&context, rtv_heap, 3)); | |
| ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, get_cpu_rtv_handle(&context, rtv_heap, 2), clear_colors[0], 0, NULL); | |
| ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, get_cpu_rtv_handle(&context, rtv_heap, 3), clear_colors[1], 0, NULL); | |
| transition_resource_state(context.list, tiled_image, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; | |
| srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| srv_desc.Texture2D.MostDetailedMip = 0; | |
| srv_desc.Texture2D.MipLevels = ~0u; | |
| srv_desc.Texture2D.PlaneSlice = 0; | |
| srv_desc.Texture2D.ResourceMinLODClamp = 0; | |
| ID3D12Device_CreateShaderResourceView(context.device, tiled_image, &srv_desc, get_cpu_descriptor_handle(&context, gpu_heap, 0)); | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; | |
| uav_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| uav_desc.Texture2D.MipSlice = 0; | |
| uav_desc.Texture2D.PlaneSlice = 0; | |
| ID3D12Device_CreateUnorderedAccessView(context.device, tiled_image, NULL, &uav_desc, get_cpu_descriptor_handle(&context, gpu_heap, 1)); | |
| memset(&sampler_desc, 0, sizeof(sampler_desc)); | |
| sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; | |
| sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; | |
| sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; | |
| sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; | |
| sampler_desc.MipLODBias = 0.0f; | |
| sampler_desc.MaxAnisotropy = 1; | |
| sampler_desc.MinLOD = -16.0f; | |
| sampler_desc.MaxLOD = 16.0f; | |
| ID3D12Device_CreateSampler(context.device, &sampler_desc, get_cpu_sampler_handle(&context, sampler_heap, 0)); | |
| memset(&pipeline_desc, 0, sizeof(pipeline_desc)); | |
| pipeline_desc.pRootSignature = root_signature; | |
| pipeline_desc.VS = use_dxil ? texture_feedback_vs_dxil : texture_feedback_vs_dxbc; | |
| pipeline_desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; | |
| pipeline_desc.BlendState.RenderTarget[1].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; | |
| pipeline_desc.SampleMask = 0xFFFFFFFF; | |
| pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; | |
| pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; | |
| pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; | |
| pipeline_desc.NumRenderTargets = 2; | |
| pipeline_desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| pipeline_desc.RTVFormats[1] = DXGI_FORMAT_R32_UINT; | |
| pipeline_desc.SampleDesc.Count = 1; | |
| set_viewport(&viewport, 0.0f, 0.0f, 256.0f, 256.0f, 0.0f, 1.0f); | |
| set_rect(&scissor, 0, 0, 256, 256); | |
| for (i = 0; i < ARRAY_SIZE(tests); i++) | |
| { | |
| D3D12_CPU_DESCRIPTOR_HANDLE rt_handle = get_cpu_rtv_handle(&context, rtv_heap, 0); | |
| ID3D12DescriptorHeap *descriptor_heaps[2] = { gpu_heap, sampler_heap }; | |
| const FLOAT clear_residency_rt[] = { 100.0f, 0.0f, 0.0f, 0.0f }; | |
| const FLOAT clear_color_rt[] = { 1.0f, 1.0f, 1.0f, 1.0f }; | |
| unsigned int color, expected_a, expected_b; | |
| vkd3d_test_set_context("Test %u", i); | |
| expected_a = tests[i].expected_mip ? 0x80808080 : (tests[i].is_gather ? 0x33333333 : 0xcc996633); | |
| expected_b = tests[i].expected_mip ? expected_a : 0; | |
| pipeline_desc.PS = use_dxil ? tests[i].ps_dxil : tests[i].ps_dxbc; | |
| hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pipeline_desc, &IID_ID3D12PipelineState, (void **)&pipeline_state); | |
| ok(hr == S_OK, "Failed to compile graphics pipeline, hr %#x.\n", hr); | |
| ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 2, &rt_handle, true, NULL); | |
| ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, get_cpu_rtv_handle(&context, rtv_heap, 1), clear_residency_rt, 0, NULL); | |
| ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, get_cpu_rtv_handle(&context, rtv_heap, 0), clear_color_rt, 0, NULL); | |
| ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); | |
| ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &viewport); | |
| ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &scissor); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, ARRAY_SIZE(descriptor_heaps), descriptor_heaps); | |
| ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, pipeline_state); | |
| ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(context.list, 0, get_gpu_descriptor_handle(&context, gpu_heap, 0)); | |
| ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(context.list, 1, get_gpu_sampler_handle(&context, sampler_heap, 0)); | |
| ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(context.list, 2, sizeof(tests[i].args) / sizeof(uint32_t), tests[i].args.args, 0); | |
| ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0); | |
| transition_resource_state(context.list, color_rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| transition_resource_state(context.list, residency_rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_texture_readback_with_command_list(color_rt, 0, &rb, context.queue, context.list); | |
| color = get_readback_uint(&rb, 64, 64, 0); | |
| ok(compare_color(color, expected_a, 1), "Got color 0x%08x, expected %08x.\n", color, expected_a); | |
| color = get_readback_uint(&rb, 192, 64, 0); | |
| ok(compare_color(color, expected_b, 1), "Got color 0x%08x, expected %08x.\n", color, expected_b); | |
| color = get_readback_uint(&rb, 64, 192, 0); | |
| ok(compare_color(color, expected_b, 1), "Got color 0x%08x, expected %08x.\n", color, expected_b); | |
| color = get_readback_uint(&rb, 192, 192, 0); | |
| ok(compare_color(color, expected_a, 1), "Got color 0x%08x, expected %08x.\n", color, expected_a); | |
| release_resource_readback(&rb); | |
| reset_command_list(context.list, context.allocator); | |
| get_texture_readback_with_command_list(residency_rt, 0, &rb, context.queue, context.list); | |
| color = get_readback_uint(&rb, 64, 64, 0); | |
| ok(compare_color(color, !!expected_a, 0), "Got residency %#x, expected %#x.\n", color, !!expected_a); | |
| color = get_readback_uint(&rb, 192, 64, 0); | |
| ok(compare_color(color, !!expected_b, 0), "Got residency %#x, expected %#x.\n", color, !!expected_b); | |
| color = get_readback_uint(&rb, 64, 192, 0); | |
| ok(compare_color(color, !!expected_b, 0), "Got residency %#x, expected %#x.\n", color, !!expected_b); | |
| color = get_readback_uint(&rb, 192, 192, 0); | |
| ok(compare_color(color, !!expected_a, 0), "Got residency %#x, expected %#x.\n", color, !!expected_a); | |
| release_resource_readback(&rb); | |
| reset_command_list(context.list, context.allocator); | |
| transition_resource_state(context.list, color_rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); | |
| transition_resource_state(context.list, residency_rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); | |
| ID3D12PipelineState_Release(pipeline_state); | |
| } | |
| ID3D12DescriptorHeap_Release(rtv_heap); | |
| ID3D12DescriptorHeap_Release(gpu_heap); | |
| ID3D12DescriptorHeap_Release(sampler_heap); | |
| ID3D12Heap_Release(heap); | |
| ID3D12Resource_Release(tiled_image); | |
| ID3D12Resource_Release(color_rt); | |
| ID3D12Resource_Release(residency_rt); | |
| ID3D12RootSignature_Release(root_signature); | |
| destroy_test_context(&context); | |
| } | |
| void test_texture_feedback_instructions_sm51(void) | |
| { | |
| test_texture_feedback_instructions(false); | |
| } | |
| void test_texture_feedback_instructions_dxil(void) | |
| { | |
| test_texture_feedback_instructions(true); | |
| } | |
| void test_sparse_buffer_memory_lifetime(void) | |
| { | |
| /* Attempt to bind sparse memory, then free the underlying heap, but keep the sparse resource | |
| * alive. This should confuse drivers that attempt to track BO lifetimes. */ | |
| D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc; | |
| D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| const UINT values[] = { 42, 42, 42, 42 }; | |
| D3D12_ROOT_PARAMETER root_parameters[2]; | |
| D3D12_TILE_REGION_SIZE region_size; | |
| D3D12_GPU_DESCRIPTOR_HANDLE h_gpu; | |
| D3D12_CPU_DESCRIPTOR_HANDLE h_cpu; | |
| D3D12_ROOT_SIGNATURE_DESC rs_desc; | |
| D3D12_DESCRIPTOR_RANGE desc_range; | |
| struct test_context context; | |
| struct resource_readback rb; | |
| ID3D12DescriptorHeap *cpu; | |
| ID3D12DescriptorHeap *gpu; | |
| D3D12_HEAP_DESC heap_desc; | |
| D3D12_RESOURCE_DESC desc; | |
| ID3D12Resource *sparse; | |
| ID3D12Resource *buffer; | |
| ID3D12Heap *heap_live; | |
| ID3D12Heap *heap; | |
| unsigned int i; | |
| HRESULT hr; | |
| #include "shaders/sparse/headers/sparse_query.h" | |
| if (!init_compute_test_context(&context)) | |
| return; | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (options.TiledResourcesTier < 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)); | |
| rs_desc.NumParameters = ARRAY_SIZE(root_parameters); | |
| rs_desc.pParameters = root_parameters; | |
| root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; | |
| root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; | |
| root_parameters[1].DescriptorTable.NumDescriptorRanges = 1; | |
| root_parameters[1].DescriptorTable.pDescriptorRanges = &desc_range; | |
| desc_range.NumDescriptors = 1; | |
| desc_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; | |
| create_root_signature(context.device, &rs_desc, &context.root_signature); | |
| context.pipeline_state = create_compute_pipeline_state(context.device, context.root_signature, sparse_query_dxbc); | |
| memset(&heap_desc, 0, sizeof(heap_desc)); | |
| heap_desc.SizeInBytes = 4 * 1024 * 1024; | |
| heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; | |
| heap_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; | |
| heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS; | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void**)&heap); | |
| ok(SUCCEEDED(hr), "Failed to create heap, hr #%x.\n", hr); | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void**)&heap_live); | |
| ok(SUCCEEDED(hr), "Failed to create heap, hr #%x.\n", hr); | |
| memset(&desc, 0, sizeof(desc)); | |
| desc.Width = 64 * 1024 * 1024; | |
| desc.Height = 1; | |
| desc.DepthOrArraySize = 1; | |
| desc.SampleDesc.Count = 1; | |
| desc.Format = DXGI_FORMAT_UNKNOWN; | |
| desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; | |
| desc.MipLevels = 1; | |
| desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; | |
| desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; | |
| desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, | |
| NULL, &IID_ID3D12Resource, (void**)&sparse); | |
| ok(SUCCEEDED(hr), "Failed to create reserved resource, hr #%x.\n", hr); | |
| { | |
| const D3D12_TILED_RESOURCE_COORDINATE region_start_coordinate = { 0 }; | |
| const D3D12_TILE_RANGE_FLAGS range_flag = D3D12_TILE_RANGE_FLAG_NULL; | |
| const UINT offset = 0; | |
| const UINT count = desc.Width / (64 * 1024); | |
| region_size.UseBox = FALSE; | |
| region_size.NumTiles = desc.Width / (64 * 1024); | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, sparse, 1, ®ion_start_coordinate, ®ion_size, | |
| NULL, 1, &range_flag, &offset, &count, D3D12_TILE_MAPPING_FLAG_NONE); | |
| } | |
| region_size.UseBox = FALSE; | |
| region_size.NumTiles = 1; | |
| for (i = 0; i < 2; i++) | |
| { | |
| const D3D12_TILED_RESOURCE_COORDINATE region_start_coordinate = { i, 0, 0, 0 }; | |
| const D3D12_TILE_RANGE_FLAGS range_flag = D3D12_TILE_RANGE_FLAG_NONE; | |
| const UINT offset = i; | |
| const UINT count = 1; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, sparse, 1, ®ion_start_coordinate, ®ion_size, | |
| i == 0 ? heap : heap_live, 1, &range_flag, &offset, &count, D3D12_TILE_MAPPING_FLAG_NONE); | |
| } | |
| wait_queue_idle(context.device, context.queue); | |
| buffer = create_default_buffer(context.device, 128 * 1024, | |
| D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST); | |
| cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1); | |
| gpu = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2); | |
| memset(&uav_desc, 0, sizeof(uav_desc)); | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; | |
| uav_desc.Format = DXGI_FORMAT_R32_UINT; | |
| uav_desc.Buffer.NumElements = 128 * 1024 / 4; | |
| uav_desc.Buffer.FirstElement = 0; | |
| ID3D12Device_CreateUnorderedAccessView(context.device, sparse, NULL, &uav_desc, | |
| ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cpu)); | |
| ID3D12Device_CreateUnorderedAccessView(context.device, sparse, NULL, &uav_desc, | |
| ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(gpu)); | |
| memset(&srv_desc, 0, sizeof(srv_desc)); | |
| srv_desc.Buffer.FirstElement = 0; | |
| srv_desc.Buffer.NumElements = 2 * 1024 * 1024; | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; | |
| srv_desc.Format = DXGI_FORMAT_R32_UINT; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| h_cpu = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(gpu); | |
| h_cpu.ptr += ID3D12Device_GetDescriptorHandleIncrementSize(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); | |
| ID3D12Device_CreateShaderResourceView(context.device, sparse, &srv_desc, h_cpu); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu); | |
| ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list, | |
| ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(gpu), | |
| ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cpu), sparse, values, 0, NULL); | |
| transition_resource_state(context.list, sparse, | |
| D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| ID3D12GraphicsCommandList_CopyBufferRegion(context.list, buffer, 0, sparse, 0, 128 * 1024); | |
| transition_resource_state(context.list, buffer, | |
| D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(buffer, DXGI_FORMAT_R32_UINT, | |
| &rb, context.queue, context.list); | |
| reset_command_list(context.list, context.allocator); | |
| ok(get_readback_uint(&rb, 0, 0, 0) == 42, "Got #%x, expected 42.\n", get_readback_uint(&rb, 0, 0, 0)); | |
| ok(get_readback_uint(&rb, 64 * 1024 / 4, 0, 0) == 42, "Got #%x, expected 42.\n", get_readback_uint(&rb, 64 * 1024 / 4, 0, 0)); | |
| release_resource_readback(&rb); | |
| ID3D12Heap_Release(heap); | |
| /* Access a resource where we can hypothetically access the freed heap memory. */ | |
| /* On AMD Windows native at least, if we read the freed region, we read garbage, which proves it's not required to unbind explicitly. | |
| * We'd read 0 in that case. */ | |
| ID3D12GraphicsCommandList_CopyBufferRegion(context.list, buffer, 0, sparse, 64 * 1024, 64 * 1024); | |
| #define EXPLORE_UNDEFINED_BEHAVIOR 0 | |
| #if EXPLORE_UNDEFINED_BEHAVIOR | |
| /* This reads unmapped memory. */ | |
| ID3D12GraphicsCommandList_CopyBufferRegion(context.list, buffer, 1024, sparse, 1024, 1024); | |
| #endif | |
| transition_resource_state(context.list, buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| h_gpu = ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(gpu); | |
| h_gpu.ptr += ID3D12Device_GetDescriptorHandleIncrementSize(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &gpu); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, context.root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state); | |
| ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(context.list, 0, ID3D12Resource_GetGPUVirtualAddress(buffer)); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 1, h_gpu); | |
| #if EXPLORE_UNDEFINED_BEHAVIOR | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| #endif | |
| transition_resource_state(context.list, buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(buffer, DXGI_FORMAT_R32_UINT, | |
| &rb, context.queue, context.list); | |
| #if EXPLORE_UNDEFINED_BEHAVIOR | |
| skip("Reading undefined value #%x.\n", get_readback_uint(&rb, 0, 0, 0)); | |
| skip("Reading value #%x (expect 0).\n", get_readback_uint(&rb, 1, 0, 0)); | |
| skip("Reading undefined value #%x.\n", get_readback_uint(&rb, 1024 / 4, 0, 0)); | |
| #endif | |
| ok(get_readback_uint(&rb, 2048 / 4, 0, 0) == 42, "Got #%x, expected 42.\n", get_readback_uint(&rb, 2048 / 4, 0, 0)); | |
| ok(get_readback_uint(&rb, 64 * 1024 / 4, 0, 0) == 42, "Got #%x, expected 42.\n", get_readback_uint(&rb, 64 * 1024 / 4, 0, 0)); | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(buffer); | |
| ID3D12Resource_Release(sparse); | |
| ID3D12DescriptorHeap_Release(cpu); | |
| ID3D12DescriptorHeap_Release(gpu); | |
| ID3D12Heap_Release(heap_live); | |
| destroy_test_context(&context); | |
| } | |
| void test_reserved_resource_mapping(void) | |
| { | |
| struct test_context context; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_RESOURCE_DESC desc; | |
| ID3D12Resource *res; | |
| HRESULT hr; | |
| void *ptr; | |
| if (!init_compute_test_context(&context)) | |
| return; | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); | |
| ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr); | |
| if (!options.TiledResourcesTier) | |
| { | |
| skip("Tiled resources not supported by device.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| memset(&desc, 0, sizeof(desc)); | |
| desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; | |
| desc.MipLevels = 1; | |
| desc.DepthOrArraySize = 1; | |
| desc.Height = 1; | |
| desc.Width = 64 * 1024; | |
| desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; | |
| desc.SampleDesc.Count = 1; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&res); | |
| ok(SUCCEEDED(hr), "Failed to create reserved resource, hr #%x.\n", hr); | |
| hr = ID3D12Resource_Map(res, 0, NULL, &ptr); | |
| ok(hr == E_INVALIDARG, "Unexpected return value hr #%x.\n", hr); | |
| ID3D12Resource_Release(res); | |
| destroy_test_context(&context); | |
| } | |
| void test_sparse_depth_stencil_rendering(void) | |
| { | |
| D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_FEATURE_DATA_FORMAT_SUPPORT format; | |
| struct test_context_desc context_desc; | |
| D3D12_ROOT_SIGNATURE_DESC rs_desc; | |
| D3D12_ROOT_PARAMETER rs_params[3]; | |
| D3D12_RESOURCE_DESC resource_desc; | |
| ID3D12DescriptorHeap *dsv_heap; | |
| ID3D12DescriptorHeap *rtv_heap; | |
| ID3D12Resource *atomic_buffer; | |
| struct resource_readback rb; | |
| struct test_context context; | |
| D3D12_HEAP_DESC heap_desc; | |
| unsigned int iter, x, y; | |
| ID3D12Resource *ds; | |
| ID3D12Resource *rt; | |
| ID3D12Heap *heap; | |
| HRESULT hr; | |
| #include "shaders/sparse/headers/ds_sparse_vs.h" | |
| #include "shaders/sparse/headers/ds_sparse_ps.h" | |
| memset(&context_desc, 0, sizeof(context_desc)); | |
| context_desc.no_pipeline = true; | |
| context_desc.no_root_signature = true; | |
| context_desc.no_render_target = true; | |
| if (!init_test_context(&context, &context_desc)) | |
| return; | |
| if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options))) || | |
| options.TiledResourcesTier < D3D12_TILED_RESOURCES_TIER_2) | |
| { | |
| skip("Tiled resources TIER_2 not supported.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| format.Format = DXGI_FORMAT_D32_FLOAT; | |
| hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_FORMAT_SUPPORT, &format, sizeof(format)); | |
| ok(SUCCEEDED(hr), "Failed to query for format support.\n"); | |
| if (!(format.Support2 & D3D12_FORMAT_SUPPORT2_TILED)) | |
| { | |
| skip("Tiled is not supported for D32.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| memset(&rs_desc, 0, sizeof(rs_desc)); | |
| memset(rs_params, 0, sizeof(rs_params)); | |
| rs_desc.NumParameters = ARRAY_SIZE(rs_params); | |
| rs_desc.pParameters = rs_params; | |
| rs_params[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; | |
| rs_params[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; | |
| rs_params[0].Constants.Num32BitValues = 2; | |
| rs_params[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; | |
| rs_params[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; | |
| rs_params[1].Constants.Num32BitValues = 2; | |
| rs_params[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; | |
| rs_params[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; | |
| rs_params[2].Descriptor.ShaderRegister = 1; | |
| create_root_signature(context.device, &rs_desc, &context.root_signature); | |
| init_pipeline_state_desc_shaders(&pso_desc, context.root_signature, DXGI_FORMAT_R8_UNORM, NULL, | |
| ds_sparse_vs_dxbc.pShaderBytecode, ds_sparse_vs_dxbc.BytecodeLength, | |
| ds_sparse_ps_dxbc.pShaderBytecode, ds_sparse_ps_dxbc.BytecodeLength); | |
| pso_desc.DepthStencilState.DepthEnable = TRUE; | |
| pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; | |
| pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_GREATER; | |
| pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT; | |
| pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; | |
| hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&context.pipeline_state); | |
| ok(SUCCEEDED(hr), "Failed to create PSO, hr #%x.\n", hr); | |
| memset(&resource_desc, 0, sizeof(resource_desc)); | |
| resource_desc.Width = 256; | |
| resource_desc.Height = 256; | |
| resource_desc.Format = DXGI_FORMAT_D32_FLOAT; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; | |
| resource_desc.DepthOrArraySize = 1; | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; | |
| resource_desc.MipLevels = 1; | |
| resource_desc.SampleDesc.Count = 1; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, (void**)&ds); | |
| ok(SUCCEEDED(hr), "Failed to create reserved resource, hr #%x\n", hr); | |
| if (FAILED(hr)) | |
| { | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| rt = create_default_texture2d(context.device, 256, 256, 1, 1, | |
| DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| atomic_buffer = create_default_buffer(context.device, 16, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | |
| memset(&heap_desc, 0, sizeof(heap_desc)); | |
| heap_desc.SizeInBytes = 64 * 1024 * 4; | |
| heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES; | |
| heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; | |
| hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void**)&heap); | |
| ok(SUCCEEDED(hr), "Failed to create heap, hr #%x\n", hr); | |
| dsv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); | |
| rtv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1); | |
| ID3D12Device_CreateDepthStencilView(context.device, ds, NULL, get_cpu_dsv_handle(&context, dsv_heap, 0)); | |
| ID3D12Device_CreateRenderTargetView(context.device, rt, NULL, get_cpu_dsv_handle(&context, rtv_heap, 0)); | |
| for (iter = 0; iter < 4; iter++) | |
| { | |
| D3D12_TILED_RESOURCE_COORDINATE region_start_coordinates; | |
| D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle; | |
| D3D12_CPU_DESCRIPTOR_HANDLE rt_handle; | |
| D3D12_TILE_REGION_SIZE region_sizes; | |
| D3D12_TILE_RANGE_FLAGS range_flags; | |
| const FLOAT clear_value[4] = { 0 }; | |
| UINT heap_range_offsets; | |
| UINT range_tile_counts; | |
| D3D12_VIEWPORT vp; | |
| float params[2]; | |
| D3D12_RECT sci; | |
| region_start_coordinates.Subresource = 0; | |
| region_start_coordinates.X = iter & 1; | |
| region_start_coordinates.Y = iter / 2; | |
| region_start_coordinates.Z = 0; | |
| memset(®ion_sizes, 0, sizeof(region_sizes)); | |
| region_sizes.NumTiles = 1; | |
| heap_range_offsets = iter; | |
| range_tile_counts = 1; | |
| range_flags = D3D12_TILE_RANGE_FLAG_NONE; | |
| ID3D12CommandQueue_UpdateTileMappings(context.queue, ds, 1, ®ion_start_coordinates, ®ion_sizes, | |
| heap, 1, &range_flags, &heap_range_offsets, &range_tile_counts, D3D12_TILE_MAPPING_FLAG_NONE); | |
| transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE); | |
| transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); | |
| rt_handle = get_cpu_rtv_handle(&context, rtv_heap, 0); | |
| dsv_handle = get_cpu_dsv_handle(&context, dsv_heap, 0); | |
| /* https://learn.microsoft.com/en-us/windows/win32/direct3d11/rasterizer-behavior-with-non-mapped-tiles | |
| * It is allowed to temporarily cache writes to unmapped tiles in TIER 2 apparently. | |
| * Avoid this situation by forcing a full memory barrier in-between, making such caching impossible. | |
| * Unmapped tiles won't get cleared. */ | |
| ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, rt_handle, clear_value, 0, NULL); | |
| ID3D12GraphicsCommandList_ClearDepthStencilView(context.list, dsv_handle, D3D12_CLEAR_FLAG_DEPTH, 0.5f, 0, 0, NULL); | |
| ID3D12GraphicsCommandList_Close(context.list); | |
| exec_command_list(context.queue, context.list); | |
| ID3D12GraphicsCommandList_Reset(context.list, context.allocator, NULL); | |
| ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 1, &rt_handle, TRUE, &dsv_handle); | |
| ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state); | |
| /* Unmapped pages should pass the depth test. We enable write in the PSO, but this write should be masked when passing. | |
| * We draw two full-screen primitives, the first with depth 0.25, the second one with 0.25 - delta. | |
| * If sparse isn't working as intended, we'll draw 0.25 depth, then 0.25 - delta fails, meaning we end up with 200 in RT. | |
| * If sparse is working as intended, the depth test will always compare against 0, so we'll end up with 150 in RT. */ | |
| params[0] = 0.25f; | |
| params[1] = -0.05f; | |
| ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(context.list, 0, ARRAY_SIZE(params), params, 0); | |
| params[0] = 200.0f / 255.0f; | |
| params[1] = -50.0f / 255.0f; | |
| ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(context.list, 1, ARRAY_SIZE(params), params, 0); | |
| ID3D12GraphicsCommandList_SetGraphicsRootUnorderedAccessView(context.list, 2, ID3D12Resource_GetGPUVirtualAddress(atomic_buffer) + 4 * iter); | |
| set_viewport(&vp, 0, 0, 256, 256, 0, 1); | |
| set_rect(&sci, 0, 0, 256, 256); | |
| ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp); | |
| ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci); | |
| ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); | |
| ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 2, 0, 0); | |
| transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_texture_readback_with_command_list(rt, 0, &rb, context.queue, context.list); | |
| reset_command_list(context.list, context.allocator); | |
| for (y = 0; y < 2; y++) | |
| { | |
| for (x = 0; x < 2; x++) | |
| { | |
| uint8_t value, expected; | |
| value = get_readback_uint8(&rb, x * 128, y * 128); | |
| /* For mapped pages, we cleared to 0.5, so we don't expect to see FB write. */ | |
| expected = y * 2 + x <= iter ? 0 : 150; | |
| /* We work around lack of sparse support currently. */ | |
| todo_if(is_radv_device(context.device)) | |
| ok(value == expected, "Iter %u, tile %u, %u: expected %u, got %u.\n", iter, x, y, expected, value); | |
| } | |
| } | |
| release_resource_readback(&rb); | |
| } | |
| transition_resource_state(context.list, atomic_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(atomic_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| reset_command_list(context.list, context.allocator); | |
| /* Ensure that driver didn't try to mask draws. Pixel invocations must still happen as-is. */ | |
| for (iter = 0; iter < 4; iter++) | |
| { | |
| uint32_t value, expected; | |
| value = get_readback_uint(&rb, iter, 0, 0); | |
| expected = 256 * 256 * 2; | |
| ok(value == expected, "Iter %u: expected %u, got %u.\n", iter, expected, value); | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12Resource_Release(ds); | |
| ID3D12Resource_Release(rt); | |
| ID3D12Heap_Release(heap); | |
| ID3D12DescriptorHeap_Release(dsv_heap); | |
| ID3D12DescriptorHeap_Release(rtv_heap); | |
| ID3D12Resource_Release(atomic_buffer); | |
| destroy_test_context(&context); | |
| } | |
| void test_sparse_default_mapping(void) | |
| { | |
| #define TILE_SIZE 65536 | |
| ID3D12Resource *tiled_buffer, *tiled_image, *feedback_buffer; | |
| D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc; | |
| D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc; | |
| D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc; | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS options; | |
| D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; | |
| D3D12_DESCRIPTOR_RANGE rs_descriptors[2]; | |
| struct test_context_desc context_desc; | |
| D3D12_HEAP_PROPERTIES heap_properties; | |
| ID3D12DescriptorHeap *descriptor_heap; | |
| D3D12_RESOURCE_DESC resource_desc; | |
| D3D12_ROOT_SIGNATURE_DESC rs_desc; | |
| D3D12_ROOT_PARAMETER rs_args[2]; | |
| struct resource_readback rb; | |
| struct test_context context; | |
| ID3D12PipelineState *pso; | |
| ID3D12RootSignature *rs; | |
| unsigned int i; | |
| HRESULT hr; | |
| #include "shaders/sparse/headers/sparse_init_access.h" | |
| static const struct | |
| { | |
| uint32_t buf_fb; | |
| uint32_t img_fb; | |
| } | |
| expected_results[] = | |
| { | |
| { 0xffffffffu, 0x0033ffffu }, | |
| { 0xffffffffu, 0x00010001u }, | |
| { 0xffffffffu, 0x00010001u }, | |
| { 0xffffffffu, 0x00010001u }, | |
| { 0xffffffffu, 0x00010001u }, | |
| { 0xffffffffu, 0x00000001u }, | |
| { 0xffffffffu, 0x00000000u }, | |
| { 0xffffffffu, 0x00000000u }, | |
| }; | |
| struct | |
| { | |
| uint32_t image_tile_w; | |
| uint32_t image_tile_h; | |
| uint32_t image_w; | |
| uint32_t image_h; | |
| uint32_t image_mips; | |
| uint32_t buffer_stride; | |
| } | |
| shader_args = | |
| { | |
| 256, 256, 1024, 1024, 11, TILE_SIZE / 16 | |
| }; | |
| memset(&context_desc, 0, sizeof(context_desc)); | |
| context_desc.no_pipeline = true; | |
| context_desc.no_root_signature = true; | |
| context_desc.no_render_target = true; | |
| if (!init_test_context(&context, &context_desc)) | |
| return; | |
| if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options))) || | |
| options.TiledResourcesTier < D3D12_TILED_RESOURCES_TIER_2) | |
| { | |
| skip("Tiled resources TIER_2 not supported.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| if (is_amd_windows_device(context.device)) | |
| { | |
| /* AMD segfaults when compiling the compute shader */ | |
| skip("Skipping test to avoid crash inside AMD driver.\n"); | |
| destroy_test_context(&context); | |
| return; | |
| } | |
| memset(&heap_properties, 0, sizeof(heap_properties)); | |
| heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT; | |
| memset(&resource_desc, 0, sizeof(resource_desc)); | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; | |
| resource_desc.Width = 64u; | |
| resource_desc.Height = 1u; | |
| resource_desc.DepthOrArraySize = 1u; | |
| resource_desc.MipLevels = 1u; | |
| resource_desc.SampleDesc.Count = 1u; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; | |
| hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties, | |
| D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, | |
| NULL, &IID_ID3D12Resource, (void**)&feedback_buffer); | |
| ok(hr == S_OK, "Failed to create feedback buffer, hr %#x.\n", hr); | |
| resource_desc.Width = 256u * TILE_SIZE; | |
| resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, | |
| NULL, &IID_ID3D12Resource, (void**)&tiled_buffer); | |
| ok(hr == S_OK, "Failed to create tiled buffer, hr %#x.\n", hr); | |
| memset(&resource_desc, 0, sizeof(resource_desc)); | |
| resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; | |
| resource_desc.Format = DXGI_FORMAT_R8_UNORM; | |
| resource_desc.Width = 1024u; | |
| resource_desc.Height = 1024u; | |
| resource_desc.DepthOrArraySize = 1u; | |
| resource_desc.MipLevels = 11u; | |
| resource_desc.SampleDesc.Count = 1u; | |
| resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; | |
| hr = ID3D12Device_CreateReservedResource(context.device, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, | |
| NULL, &IID_ID3D12Resource, (void**)&tiled_image); | |
| ok(hr == S_OK, "Failed to create tiled image, hr %#x.\n", hr); | |
| memset(rs_descriptors, 0, sizeof(rs_descriptors)); | |
| rs_descriptors[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; | |
| rs_descriptors[0].NumDescriptors = 1u; | |
| rs_descriptors[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; | |
| rs_descriptors[1].NumDescriptors = 2u; | |
| rs_descriptors[1].OffsetInDescriptorsFromTableStart = 1u; | |
| memset(rs_args, 0, sizeof(rs_args)); | |
| rs_args[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; | |
| rs_args[0].Constants.Num32BitValues = sizeof(shader_args) / sizeof(uint32_t); | |
| rs_args[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| rs_args[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; | |
| rs_args[1].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(rs_descriptors); | |
| rs_args[1].DescriptorTable.pDescriptorRanges = rs_descriptors; | |
| rs_args[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; | |
| memset(&rs_desc, 0, sizeof(rs_desc)); | |
| rs_desc.NumParameters = ARRAY_SIZE(rs_args); | |
| rs_desc.pParameters = rs_args; | |
| hr = create_root_signature(context.device, &rs_desc, &rs); | |
| ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); | |
| memset(&pso_desc, 0, sizeof(pso_desc)); | |
| pso_desc.pRootSignature = rs; | |
| pso_desc.CS = sparse_init_access_dxil; | |
| hr = ID3D12Device_CreateComputePipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void**)&pso); | |
| ok(hr == S_OK, "Failed to create compute pipeline, hr %#x.\n", hr); | |
| memset(&descriptor_heap_desc, 0, sizeof(descriptor_heap_desc)); | |
| descriptor_heap_desc.NumDescriptors = 3; | |
| descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; | |
| descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; | |
| hr = ID3D12Device_CreateDescriptorHeap(context.device, &descriptor_heap_desc, &IID_ID3D12DescriptorHeap, (void**)&descriptor_heap); | |
| ok(hr == S_OK, "Failed to create descriptor heap, hr %#x.\n", hr); | |
| memset(&uav_desc, 0, sizeof(uav_desc)); | |
| uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; | |
| uav_desc.Buffer.NumElements = ARRAY_SIZE(expected_results); | |
| uav_desc.Buffer.StructureByteStride = sizeof(expected_results[0]); | |
| ID3D12Device_CreateUnorderedAccessView(context.device, feedback_buffer, | |
| NULL, &uav_desc, get_cpu_descriptor_handle(&context, descriptor_heap, 0)); | |
| memset(&srv_desc, 0, sizeof(srv_desc)); | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; | |
| srv_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; | |
| srv_desc.Buffer.NumElements = 256 * TILE_SIZE / 16; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| ID3D12Device_CreateShaderResourceView(context.device, tiled_buffer, | |
| &srv_desc, get_cpu_descriptor_handle(&context, descriptor_heap, 1)); | |
| memset(&srv_desc, 0, sizeof(srv_desc)); | |
| srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; | |
| srv_desc.Format = DXGI_FORMAT_R8_UNORM; | |
| srv_desc.Texture2D.MipLevels = 11; | |
| srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; | |
| ID3D12Device_CreateShaderResourceView(context.device, tiled_image, | |
| &srv_desc, get_cpu_descriptor_handle(&context, descriptor_heap, 2)); | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &descriptor_heap); | |
| ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, rs); | |
| ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, 0, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0); | |
| ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 1, get_gpu_descriptor_handle(&context, descriptor_heap, 0)); | |
| ID3D12GraphicsCommandList_SetPipelineState(context.list, pso); | |
| ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1); | |
| transition_resource_state(context.list, feedback_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | |
| get_buffer_readback_with_command_list(feedback_buffer, DXGI_FORMAT_R32_UINT, &rb, context.queue, context.list); | |
| for (i = 0; i < ARRAY_SIZE(expected_results); i++) | |
| { | |
| uint32_t buf = get_readback_uint(&rb, 2u * i, 0u, 0u); | |
| uint32_t img = get_readback_uint(&rb, 2u * i + 1u, 0u, 0u); | |
| ok(buf == expected_results[i].buf_fb, "Got %#x, expected %#x for tiled buffer at %u.\n", | |
| buf, expected_results[i].buf_fb, i); | |
| ok(img == expected_results[i].img_fb, "Got %#x, expected %#x for tiled texture at %u.\n", | |
| img, expected_results[i].img_fb, i); | |
| } | |
| release_resource_readback(&rb); | |
| ID3D12DescriptorHeap_Release(descriptor_heap); | |
| ID3D12PipelineState_Release(pso); | |
| ID3D12RootSignature_Release(rs); | |
| ID3D12Resource_Release(feedback_buffer); | |
| ID3D12Resource_Release(tiled_buffer); | |
| ID3D12Resource_Release(tiled_image); | |
| destroy_test_context(&context); | |
| #undef TILE_SIZE | |
| } |