/* * Copyright 2016-2017 Józef Kucia for CodeWeavers * * 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" PFN_D3D12_CREATE_VERSIONED_ROOT_SIGNATURE_DESERIALIZER pfn_D3D12CreateVersionedRootSignatureDeserializer; PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE pfn_D3D12SerializeVersionedRootSignature; PFN_D3D12_CREATE_DEVICE pfn_D3D12CreateDevice; PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES pfn_D3D12EnableExperimentalFeatures; PFN_D3D12_GET_DEBUG_INTERFACE pfn_D3D12GetDebugInterface; const char *vkd3d_test_platform = "other"; struct vkd3d_test_state_context vkd3d_test_state; #ifdef _WIN32 RENDERDOC_API_1_0_0 *renderdoc_api; #endif bool compare_float(float f, float g, int ulps) { int x, y; union { float f; int i; } u; u.f = f; x = u.i; u.f = g; y = u.i; if (x < 0) x = INT_MIN - x; if (y < 0) y = INT_MIN - y; if (abs(x - y) > ulps) return false; return true; } bool compare_vec4(const struct vec4 *v1, const struct vec4 *v2, unsigned int ulps) { return compare_float(v1->x, v2->x, ulps) && compare_float(v1->y, v2->y, ulps) && compare_float(v1->z, v2->z, ulps) && compare_float(v1->w, v2->w, ulps); } bool compare_uvec4(const struct uvec4* v1, const struct uvec4 *v2) { return v1->x == v2->x && v1->y == v2->y && v1->z == v2->z && v1->w == v2->w; } bool compare_uint8(uint8_t a, uint8_t b, unsigned int max_diff) { return delta_uint8(a, b) <= max_diff; } bool compare_uint16(uint16_t a, uint16_t b, unsigned int max_diff) { return delta_uint16(a, b) <= max_diff; } bool compare_uint64(uint64_t a, uint64_t b, unsigned int max_diff) { return delta_uint64(a, b) <= max_diff; } ULONG get_refcount(void *iface) { IUnknown *unk = iface; IUnknown_AddRef(unk); return IUnknown_Release(unk); } void check_interface_(unsigned int line, IUnknown *iface, REFIID riid, bool supported) { HRESULT hr, expected_hr; IUnknown *unk; expected_hr = supported ? S_OK : E_NOINTERFACE; hr = IUnknown_QueryInterface(iface, riid, (void **)&unk); ok_(line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr); if (SUCCEEDED(hr)) IUnknown_Release(unk); } void check_heap_properties_(unsigned int line, const D3D12_HEAP_PROPERTIES *properties, const D3D12_HEAP_PROPERTIES *expected_properties) { D3D12_HEAP_PROPERTIES expected = *expected_properties; if (!expected.CreationNodeMask) expected.CreationNodeMask = 0x1; if (!expected.VisibleNodeMask) expected.VisibleNodeMask = 0x1; ok_(line)(properties->Type == expected.Type, "Got type %#x, expected %#x.\n", properties->Type, expected.Type); ok_(line)(properties->CPUPageProperty == expected.CPUPageProperty, "Got CPU page properties %#x, expected %#x.\n", properties->CPUPageProperty, expected.CPUPageProperty); ok_(line)(properties->MemoryPoolPreference == expected.MemoryPoolPreference, "Got memory pool %#x, expected %#x.\n", properties->MemoryPoolPreference, expected.MemoryPoolPreference); ok_(line)(properties->CreationNodeMask == expected.CreationNodeMask, "Got creation node mask %#x, expected %#x.\n", properties->CreationNodeMask, expected.CreationNodeMask); ok_(line)(properties->VisibleNodeMask == expected.VisibleNodeMask, "Got visible node mask %#x, expected %#x.\n", properties->VisibleNodeMask, expected.VisibleNodeMask); } void check_heap_desc_(unsigned int line, const D3D12_HEAP_DESC *desc, const D3D12_HEAP_DESC *expected_desc) { D3D12_HEAP_DESC expected = *expected_desc; if (!expected.Alignment) expected.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; ok_(line)(desc->SizeInBytes == expected.SizeInBytes, "Got size %"PRIu64", expected %"PRIu64".\n", desc->SizeInBytes, expected.SizeInBytes); check_heap_properties_(line, &desc->Properties, &expected.Properties); ok_(line)(desc->Alignment == expected.Alignment, "Got alignment %"PRIu64", expected %"PRIu64".\n", desc->Alignment, expected.Alignment); ok_(line)(desc->Flags == expected.Flags, "Got flags %#x, expected %#x.\n", desc->Flags, expected.Flags); } void check_alignment_(unsigned int line, uint64_t size, uint64_t alignment) { uint64_t aligned_size = align(size, alignment); ok_(line)(aligned_size == size, "Got unaligned size %"PRIu64", expected %"PRIu64".\n", size, aligned_size); } void uav_barrier(ID3D12GraphicsCommandList *list, ID3D12Resource *resource) { D3D12_RESOURCE_BARRIER barrier; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.UAV.pResource = resource; ID3D12GraphicsCommandList_ResourceBarrier(list, 1, &barrier); } void copy_sub_resource_data(const D3D12_MEMCPY_DEST *dst, const D3D12_SUBRESOURCE_DATA *src, unsigned int row_count, unsigned int slice_count, size_t row_size) { const BYTE *src_slice_ptr; BYTE *dst_slice_ptr; unsigned int z, y; for (z = 0; z < slice_count; ++z) { dst_slice_ptr = (BYTE *)dst->pData + z * dst->SlicePitch; src_slice_ptr = (const BYTE*)src->pData + z * src->SlicePitch; for (y = 0; y < row_count; ++y) memcpy(dst_slice_ptr + y * dst->RowPitch, src_slice_ptr + y * src->RowPitch, row_size); } } void upload_buffer_data_(unsigned int line, ID3D12Resource *buffer, size_t offset, size_t size, const void *data, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list) { ID3D12Resource *upload_buffer; ID3D12Device *device; HRESULT hr; hr = ID3D12Resource_GetDevice(buffer, &IID_ID3D12Device, (void **)&device); ok_(line)(SUCCEEDED(hr), "Failed to get device, hr %#x.\n", hr); upload_buffer = create_upload_buffer_(line, device, size, data); ID3D12GraphicsCommandList_CopyBufferRegion(command_list, buffer, offset, upload_buffer, 0, size); hr = ID3D12GraphicsCommandList_Close(command_list); ok_(line)(SUCCEEDED(hr), "Failed to close command list, hr %#x.\n", hr); exec_command_list(queue, command_list); wait_queue_idle(device, queue); ID3D12Resource_Release(upload_buffer); ID3D12Device_Release(device); } void upload_texture_data_(unsigned int line, ID3D12Resource *texture, const D3D12_SUBRESOURCE_DATA *data, unsigned int sub_resource_count, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list) { D3D12_TEXTURE_COPY_LOCATION dst_location, src_location; D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts; D3D12_RESOURCE_DESC resource_desc; UINT64 *row_sizes, required_size; ID3D12Resource *upload_buffer; D3D12_MEMCPY_DEST dst_data; ID3D12Device *device; UINT *row_counts; unsigned int i; HRESULT hr; void *ptr; layouts = calloc(sub_resource_count, sizeof(*layouts)); ok(layouts, "Failed to allocate memory.\n"); row_counts = calloc(sub_resource_count, sizeof(*row_counts)); ok(row_counts, "Failed to allocate memory.\n"); row_sizes = calloc(sub_resource_count, sizeof(*row_sizes)); ok(row_sizes, "Failed to allocate memory.\n"); resource_desc = ID3D12Resource_GetDesc(texture); hr = ID3D12Resource_GetDevice(texture, &IID_ID3D12Device, (void **)&device); ok_(line)(SUCCEEDED(hr), "Failed to get device, hr %#x.\n", hr); ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, 0, layouts, row_counts, row_sizes, &required_size); upload_buffer = create_upload_buffer_(line, device, required_size, NULL); hr = ID3D12Resource_Map(upload_buffer, 0, NULL, (void **)&ptr); ok_(line)(SUCCEEDED(hr), "Failed to map upload buffer, hr %#x.\n", hr); for (i = 0; i < sub_resource_count; ++i) { dst_data.pData = (BYTE *)ptr + layouts[i].Offset; dst_data.RowPitch = layouts[i].Footprint.RowPitch; dst_data.SlicePitch = layouts[i].Footprint.RowPitch * row_counts[i]; copy_sub_resource_data(&dst_data, &data[i], row_counts[i], layouts[i].Footprint.Depth, row_sizes[i]); } ID3D12Resource_Unmap(upload_buffer, 0, NULL); for (i = 0; i < sub_resource_count; ++i) { dst_location.pResource = texture; dst_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dst_location.SubresourceIndex = i; src_location.pResource = upload_buffer; src_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; src_location.PlacedFootprint = layouts[i]; ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &dst_location, 0, 0, 0, &src_location, NULL); } hr = ID3D12GraphicsCommandList_Close(command_list); ok_(line)(SUCCEEDED(hr), "Failed to close command list, hr %#x.\n", hr); exec_command_list(queue, command_list); wait_queue_idle(device, queue); ID3D12Resource_Release(upload_buffer); ID3D12Device_Release(device); free(layouts); free(row_counts); free(row_sizes); } void init_readback(struct resource_readback *rb, ID3D12Resource *buffer, uint64_t buffer_size, uint64_t width, uint64_t height, unsigned int depth, uint64_t row_pitch) { D3D12_RANGE read_range; HRESULT hr; rb->width = width; rb->height = height; rb->depth = depth; rb->resource = buffer; rb->row_pitch = row_pitch; rb->data = NULL; ID3D12Resource_AddRef(rb->resource); read_range.Begin = 0; read_range.End = buffer_size; hr = ID3D12Resource_Map(rb->resource, 0, &read_range, &rb->data); ok(hr == S_OK, "Failed to map readback buffer, hr %#x.\n", hr); } void get_buffer_readback_with_command_list(ID3D12Resource *buffer, DXGI_FORMAT format, struct resource_readback *rb, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list) { D3D12_HEAP_PROPERTIES heap_properties; D3D12_RESOURCE_DESC resource_desc; ID3D12Resource *rb_buffer; D3D12_RANGE read_range; ID3D12Device *device; HRESULT hr; hr = ID3D12Resource_GetDevice(buffer, &IID_ID3D12Device, (void **)&device); ok(SUCCEEDED(hr), "Failed to get device, hr %#x.\n", hr); resource_desc = ID3D12Resource_GetDesc(buffer); assert(resource_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER); resource_desc.Flags = D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; hr = ID3D12Resource_GetHeapProperties(buffer, &heap_properties, NULL); if (SUCCEEDED(hr) && heap_properties.Type == D3D12_HEAP_TYPE_READBACK) { rb_buffer = buffer; ID3D12Resource_AddRef(rb_buffer); } else { rb_buffer = create_readback_buffer(device, resource_desc.Width); ID3D12GraphicsCommandList_CopyBufferRegion(command_list, rb_buffer, 0, buffer, 0, resource_desc.Width); } hr = ID3D12GraphicsCommandList_Close(command_list); ok(SUCCEEDED(hr), "Failed to close command list, hr %#x.\n", hr); exec_command_list(queue, command_list); wait_queue_idle(device, queue); ID3D12Device_Release(device); rb->width = resource_desc.Width / format_size(format); rb->height = 1; rb->depth = 1; rb->resource = rb_buffer; rb->row_pitch = resource_desc.Width; rb->data = NULL; read_range.Begin = 0; read_range.End = resource_desc.Width; hr = ID3D12Resource_Map(rb_buffer, 0, &read_range, &rb->data); ok(SUCCEEDED(hr), "Failed to map readback buffer, hr %#x.\n", hr); } uint8_t get_readback_uint8(struct resource_readback *rb, unsigned int x, unsigned int y) { return *(uint8_t *)get_readback_data(rb, x, y, 0, sizeof(uint8_t)); } uint16_t get_readback_uint16(struct resource_readback *rb, unsigned int x, unsigned int y) { return *(uint16_t *)get_readback_data(rb, x, y, 0, sizeof(uint16_t)); } uint64_t get_readback_uint64(struct resource_readback *rb, unsigned int x, unsigned int y) { return *(uint64_t *)get_readback_data(rb, x, y, 0, sizeof(uint64_t)); } float get_readback_float(struct resource_readback *rb, unsigned int x, unsigned int y) { return *(float *)get_readback_data(rb, x, y, 0, sizeof(float)); } const struct vec4 *get_readback_vec4(struct resource_readback *rb, unsigned int x, unsigned int y) { return get_readback_data(rb, x, y, 0, sizeof(struct vec4)); } const struct uvec4 *get_readback_uvec4(struct resource_readback *rb, unsigned int x, unsigned int y) { return get_readback_data(rb, x, y, 0, sizeof(struct uvec4)); } void check_readback_data_float_(unsigned int line, struct resource_readback *rb, const RECT *rect, float expected, unsigned int max_diff) { RECT r = {0, 0, rb->width, rb->height}; int x = 0, y; bool all_match = true; float got = 0; if (rect) r = *rect; for (y = r.top; y < r.bottom; ++y) { for (x = r.left; x < r.right; ++x) { got = get_readback_float(rb, x, y); if (!compare_float(got, expected, max_diff)) { all_match = false; break; } } if (!all_match) break; } ok_(line)(all_match, "Got %.8e, expected %.8e at (%u, %u).\n", got, expected, x, y); } void check_sub_resource_float_(unsigned int line, ID3D12Resource *texture, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, float expected, unsigned int max_diff) { struct resource_readback rb; get_texture_readback_with_command_list(texture, sub_resource_idx, &rb, queue, command_list); check_readback_data_float_(line, &rb, NULL, expected, max_diff); release_resource_readback(&rb); } void check_readback_data_uint8_(unsigned int line, struct resource_readback *rb, const RECT *rect, uint8_t expected, unsigned int max_diff) { RECT r = {0, 0, rb->width, rb->height}; int x = 0, y; bool all_match = true; uint8_t got = 0; if (rect) r = *rect; for (y = r.top; y < r.bottom; ++y) { for (x = r.left; x < r.right; ++x) { got = get_readback_uint8(rb, x, y); if (!compare_uint8(got, expected, max_diff)) { all_match = false; break; } } if (!all_match) break; } ok_(line)(all_match, "Got 0x%02x, expected 0x%02x at (%u, %u).\n", got, expected, x, y); } void check_sub_resource_uint8_(unsigned int line, ID3D12Resource *texture, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, uint8_t expected, unsigned int max_diff) { struct resource_readback rb; get_texture_readback_with_command_list(texture, sub_resource_idx, &rb, queue, command_list); check_readback_data_uint8_(line, &rb, NULL, expected, max_diff); release_resource_readback(&rb); } void check_readback_data_uint16_(unsigned int line, struct resource_readback *rb, const RECT *rect, uint16_t expected, unsigned int max_diff) { RECT r = {0, 0, rb->width, rb->height}; int x = 0, y; bool all_match = true; uint16_t got = 0; if (rect) r = *rect; for (y = r.top; y < r.bottom; ++y) { for (x = r.left; x < r.right; ++x) { got = get_readback_uint16(rb, x, y); if (!compare_uint16(got, expected, max_diff)) { all_match = false; break; } } if (!all_match) break; } ok_(line)(all_match, "Got 0x%04x, expected 0x%04x at (%u, %u).\n", got, expected, x, y); } void check_sub_resource_uint16_(unsigned int line, ID3D12Resource *texture, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, uint16_t expected, unsigned int max_diff) { struct resource_readback rb; get_texture_readback_with_command_list(texture, sub_resource_idx, &rb, queue, command_list); check_readback_data_uint16_(line, &rb, NULL, expected, max_diff); release_resource_readback(&rb); } void check_readback_data_uint64_(unsigned int line, struct resource_readback *rb, const RECT *rect, uint64_t expected, unsigned int max_diff) { RECT r = {0, 0, rb->width, rb->height}; int x = 0, y; bool all_match = true; uint64_t got = 0; if (rect) r = *rect; for (y = r.top; y < r.bottom; ++y) { for (x = r.left; x < r.right; ++x) { got = get_readback_uint64(rb, x, y); if (!compare_uint64(got, expected, max_diff)) { all_match = false; break; } } if (!all_match) break; } ok_(line)(all_match, "Got %#"PRIx64", expected %#"PRIx64" at (%u, %u).\n", got, expected, x, y); } void check_sub_resource_uint64_(unsigned int line, ID3D12Resource *texture, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, uint64_t expected, unsigned int max_diff) { struct resource_readback rb; get_texture_readback_with_command_list(texture, sub_resource_idx, &rb, queue, command_list); check_readback_data_uint64_(line, &rb, NULL, expected, max_diff); release_resource_readback(&rb); } void check_sub_resource_vec4_(unsigned int line, ID3D12Resource *texture, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, const struct vec4 *expected, unsigned int max_diff) { struct resource_readback rb; unsigned int x = 0, y; bool all_match = true; struct vec4 got = {0}; get_texture_readback_with_command_list(texture, sub_resource_idx, &rb, queue, command_list); for (y = 0; y < rb.height; ++y) { for (x = 0; x < rb.width; ++x) { got = *get_readback_vec4(&rb, x, y); if (!compare_vec4(&got, expected, max_diff)) { all_match = false; break; } } if (!all_match) break; } release_resource_readback(&rb); ok_(line)(all_match, "Got {%.8e, %.8e, %.8e, %.8e}, expected {%.8e, %.8e, %.8e, %.8e} at (%u, %u).\n", got.x, got.y, got.z, got.w, expected->x, expected->y, expected->z, expected->w, x, y); } void check_sub_resource_uvec4_(unsigned int line, ID3D12Resource *texture, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, const struct uvec4 *expected_value) { struct resource_readback rb; struct uvec4 value = {0}; unsigned int x = 0, y; bool all_match = true; get_texture_readback_with_command_list(texture, sub_resource_idx, &rb, queue, command_list); for (y = 0; y < rb.height; ++y) { for (x = 0; x < rb.width; ++x) { value = *get_readback_uvec4(&rb, x, y); if (!compare_uvec4(&value, expected_value)) { all_match = false; break; } } if (!all_match) break; } release_resource_readback(&rb); ok_(line)(all_match, "Got {0x%08x, 0x%08x, 0x%08x, 0x%08x}, expected {0x%08x, 0x%08x, 0x%08x, 0x%08x} at (%u, %u).\n", value.x, value.y, value.z, value.w, expected_value->x, expected_value->y, expected_value->z, expected_value->w, x, y); } bool broken_on_warp(bool condition) { return broken(use_warp_device && condition); } bool is_min_max_filtering_supported(ID3D12Device *device) { D3D12_FEATURE_DATA_D3D12_OPTIONS options; HRESULT hr; if (FAILED(hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)))) { trace("Failed to check feature support, hr %#x.\n", hr); return false; } /* D3D12 validation layer says tiled resource tier 2+ support implies min/max filtering support. */ return options.TiledResourcesTier >= D3D12_TILED_RESOURCES_TIER_2; } D3D12_TILED_RESOURCES_TIER get_tiled_resources_tier(ID3D12Device *device) { D3D12_FEATURE_DATA_D3D12_OPTIONS options; HRESULT hr; if (FAILED(hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)))) { trace("Failed to check feature support, hr %#x.\n", hr); return D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED; } return options.TiledResourcesTier; } bool is_standard_swizzle_64kb_supported(ID3D12Device *device) { D3D12_FEATURE_DATA_D3D12_OPTIONS options; HRESULT hr; if (FAILED(hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)))) { trace("Failed to check feature support, hr %#x.\n", hr); return false; } return options.StandardSwizzle64KBSupported; } bool is_memory_pool_L1_supported(ID3D12Device *device) { D3D12_FEATURE_DATA_ARCHITECTURE architecture; HRESULT hr; memset(&architecture, 0, sizeof(architecture)); if (FAILED(hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_ARCHITECTURE, &architecture, sizeof(architecture)))) { trace("Failed to check feature support, hr %#x.\n", hr); return false; } return !architecture.UMA; } bool is_vrs_tier1_supported(ID3D12Device *device, bool *additional_shading_rates) { D3D12_FEATURE_DATA_D3D12_OPTIONS6 options; HRESULT hr; if (additional_shading_rates) *additional_shading_rates = false; if (FAILED(hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS6, &options, sizeof(options)))) { trace("Failed to check feature support, hr %#x.\n", hr); return false; } if (additional_shading_rates) *additional_shading_rates = options.AdditionalShadingRatesSupported; return options.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_1; } bool is_vrs_tier2_supported(ID3D12Device *device) { D3D12_FEATURE_DATA_D3D12_OPTIONS6 options; HRESULT hr; if (FAILED(hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS6, &options, sizeof(options)))) { trace("Failed to check feature support, hr %#x.\n", hr); return false; } return options.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_2; } ID3D12RootSignature *create_cb_root_signature_(unsigned int line, ID3D12Device *device, unsigned int reg_idx, D3D12_SHADER_VISIBILITY shader_visibility, D3D12_ROOT_SIGNATURE_FLAGS flags) { D3D12_ROOT_SIGNATURE_DESC root_signature_desc; ID3D12RootSignature *root_signature = NULL; D3D12_ROOT_PARAMETER root_parameter; HRESULT hr; root_parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; root_parameter.Descriptor.ShaderRegister = reg_idx; root_parameter.Descriptor.RegisterSpace = 0; root_parameter.ShaderVisibility = shader_visibility; memset(&root_signature_desc, 0, sizeof(root_signature_desc)); root_signature_desc.NumParameters = 1; root_signature_desc.pParameters = &root_parameter; root_signature_desc.Flags = flags; hr = create_root_signature(device, &root_signature_desc, &root_signature); ok_(line)(SUCCEEDED(hr), "Failed to create root signature, hr %#x.\n", hr); return root_signature; } ID3D12RootSignature *create_32bit_constants_root_signature_(unsigned int line, ID3D12Device *device, unsigned int reg_idx, unsigned int element_count, D3D12_SHADER_VISIBILITY shader_visibility, D3D12_ROOT_SIGNATURE_FLAGS flags) { D3D12_ROOT_SIGNATURE_DESC root_signature_desc; ID3D12RootSignature *root_signature = NULL; D3D12_ROOT_PARAMETER root_parameter; HRESULT hr; root_parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; root_parameter.Constants.ShaderRegister = reg_idx; root_parameter.Constants.RegisterSpace = 0; root_parameter.Constants.Num32BitValues = element_count; root_parameter.ShaderVisibility = shader_visibility; memset(&root_signature_desc, 0, sizeof(root_signature_desc)); root_signature_desc.NumParameters = 1; root_signature_desc.pParameters = &root_parameter; root_signature_desc.Flags = flags; hr = create_root_signature(device, &root_signature_desc, &root_signature); ok_(line)(SUCCEEDED(hr), "Failed to create root signature, hr %#x.\n", hr); return root_signature; } ID3D12RootSignature *create_texture_root_signature_(unsigned int line, ID3D12Device *device, D3D12_SHADER_VISIBILITY shader_visibility, unsigned int constant_count, D3D12_ROOT_SIGNATURE_FLAGS flags, const D3D12_STATIC_SAMPLER_DESC *sampler_desc) { D3D12_ROOT_SIGNATURE_DESC root_signature_desc; ID3D12RootSignature *root_signature = NULL; D3D12_STATIC_SAMPLER_DESC static_sampler; D3D12_DESCRIPTOR_RANGE descriptor_range; D3D12_ROOT_PARAMETER root_parameters[2]; HRESULT hr; if (sampler_desc) { static_sampler = *sampler_desc; } else { memset(&static_sampler, 0, sizeof(static_sampler)); static_sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; static_sampler.MaxLOD = D3D12_FLOAT32_MAX; static_sampler.ShaderRegister = 0; static_sampler.RegisterSpace = 0; static_sampler.ShaderVisibility = shader_visibility; } 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 = shader_visibility; 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 = constant_count; root_parameters[1].ShaderVisibility = shader_visibility; memset(&root_signature_desc, 0, sizeof(root_signature_desc)); root_signature_desc.NumParameters = constant_count ? 2 : 1; root_signature_desc.pParameters = root_parameters; root_signature_desc.NumStaticSamplers = 1; root_signature_desc.pStaticSamplers = &static_sampler; root_signature_desc.Flags = flags; hr = create_root_signature(device, &root_signature_desc, &root_signature); ok_(line)(SUCCEEDED(hr), "Failed to create root signature, hr %#x.\n", hr); return root_signature; } ID3D12PipelineState *create_compute_pipeline_state_(unsigned int line, ID3D12Device *device, ID3D12RootSignature *root_signature, const D3D12_SHADER_BYTECODE cs) { D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline_state_desc; ID3D12PipelineState *pipeline_state = NULL; HRESULT hr; memset(&pipeline_state_desc, 0, sizeof(pipeline_state_desc)); pipeline_state_desc.pRootSignature = root_signature; pipeline_state_desc.CS = cs; pipeline_state_desc.NodeMask = 0; pipeline_state_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; hr = ID3D12Device_CreateComputePipelineState(device, &pipeline_state_desc, &IID_ID3D12PipelineState, (void **)&pipeline_state); ok_(line)(SUCCEEDED(hr), "Failed to create compute pipeline state, hr %#x.\n", hr); return pipeline_state; } ID3D12CommandSignature *create_command_signature_(unsigned int line, ID3D12Device *device, D3D12_INDIRECT_ARGUMENT_TYPE argument_type) { ID3D12CommandSignature *command_signature = NULL; D3D12_COMMAND_SIGNATURE_DESC signature_desc; D3D12_INDIRECT_ARGUMENT_DESC argument_desc; HRESULT hr; argument_desc.Type = argument_type; switch (argument_type) { case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW: signature_desc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); break; case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED: signature_desc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); break; case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH: signature_desc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); break; case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_RAYS: signature_desc.ByteStride = sizeof(D3D12_DISPATCH_RAYS_DESC); break; default: return NULL; } signature_desc.NumArgumentDescs = 1; signature_desc.pArgumentDescs = &argument_desc; signature_desc.NodeMask = 0; hr = ID3D12Device_CreateCommandSignature(device, &signature_desc, NULL, &IID_ID3D12CommandSignature, (void **)&command_signature); ok_(line)(hr == S_OK, "Failed to create command signature, hr %#x.\n", hr); return command_signature; } bool init_compute_test_context_(unsigned int line, struct test_context *context) { D3D12_COMMAND_LIST_TYPE command_list_type = D3D12_COMMAND_LIST_TYPE_COMPUTE; ID3D12Device *device; HRESULT hr; memset(context, 0, sizeof(*context)); if (!(context->device = create_device())) { skip_(line)("Failed to create device.\n"); return false; } device = context->device; #ifdef _WIN32 begin_renderdoc_capturing(device); /* Workaround RenderDoc bug. It expects a DIRECT command queue to exist. */ if (renderdoc_api) command_list_type = D3D12_COMMAND_LIST_TYPE_DIRECT; #endif context->queue = create_command_queue_(line, device, command_list_type, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL); hr = ID3D12Device_CreateCommandAllocator(device, command_list_type, &IID_ID3D12CommandAllocator, (void **)&context->allocator); ok_(line)(hr == S_OK, "Failed to create command allocator, hr %#x.\n", hr); hr = ID3D12Device_CreateCommandList(device, 0, command_list_type, context->allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&context->list); ok_(line)(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); return true; } bool context_supports_dxil_(unsigned int line, struct test_context *context) { D3D12_FEATURE_DATA_SHADER_MODEL model; HRESULT hr; model.HighestShaderModel = D3D_SHADER_MODEL_6_0; hr = ID3D12Device_CheckFeatureSupport(context->device, D3D12_FEATURE_SHADER_MODEL, &model, sizeof(model)); ok_(line)(hr == S_OK, "Failed to query shader model support, hr %#x.\n", hr); if (hr != S_OK) return false; if (model.HighestShaderModel < D3D_SHADER_MODEL_6_0) { skip_(line)("Device does not support shader model 6.0, skipping DXIL tests.\n"); return false; } else return true; } void init_depth_stencil_(unsigned int line, struct depth_stencil_resource *ds, ID3D12Device *device, unsigned int width, unsigned int height, unsigned int array_size, unsigned int level_count, DXGI_FORMAT format, DXGI_FORMAT view_format, const D3D12_CLEAR_VALUE *clear_value) { D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc, *view_desc; D3D12_HEAP_PROPERTIES heap_properties; D3D12_RESOURCE_DESC resource_desc; HRESULT hr; memset(ds, 0, sizeof(*ds)); ds->heap = create_cpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); memset(&heap_properties, 0, sizeof(heap_properties)); heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT; resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; resource_desc.Alignment = 0; resource_desc.Width = width; resource_desc.Height = height; resource_desc.DepthOrArraySize = array_size; resource_desc.MipLevels = level_count; resource_desc.Format = format; resource_desc.SampleDesc.Count = 1; resource_desc.SampleDesc.Quality = 0; resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_DEPTH_WRITE, clear_value, &IID_ID3D12Resource, (void **)&ds->texture); ok_(line)(SUCCEEDED(hr), "Failed to create texture, hr %#x.\n", hr); view_desc = NULL; if (view_format) { memset(&dsv_desc, 0, sizeof(dsv_desc)); dsv_desc.Format = view_format; dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; view_desc = &dsv_desc; } ds->dsv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(ds->heap); ID3D12Device_CreateDepthStencilView(device, ds->texture, view_desc, ds->dsv_handle); } void destroy_depth_stencil_(unsigned int line, struct depth_stencil_resource *ds) { ID3D12DescriptorHeap_Release(ds->heap); ID3D12Resource_Release(ds->texture); }