From: Evan Tang etang@codeweavers.com
--- tests/shader_runner.c | 23 +++++++ tests/shader_runner.h | 4 ++ tests/shader_runner_d3d11.c | 29 +++++++++ tests/shader_runner_d3d12.c | 30 ++++++++++ tests/shader_runner_vulkan.c | 113 +++++++++++++++++++++++++++++++++-- tests/vulkan_procs.h | 3 +- 6 files changed, 196 insertions(+), 6 deletions(-)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 19453df3f..ade65882e 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -58,6 +58,7 @@ typedef int HRESULT; #include "vkd3d_windows.h" #include "vkd3d_d3dcommon.h" #include "vkd3d_d3dcompiler.h" +#include "vkd3d_shader.h" #include "vkd3d_test.h" #include "shader_runner.h"
@@ -158,6 +159,27 @@ static void parse_require_directive(struct shader_runner *runner, const char *li runner->compile_options |= options[i].option; } } + else if (match_string(line, "features:", &line)) + { + static const struct feature + { + enum vkd3d_shader_spirv_extension extension; + const char* name; + } + features[] = + { + { VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK, "rov" }, + }; + + for (i = 0; i < ARRAY_SIZE(features); ++i) + { + if (match_string(line, features[i].name, &line)) + { + vkd3d_array_reserve((void**)&runner->required_extensions, &runner->required_extension_capacity, runner->required_extension_count + 1, sizeof(*runner->required_extensions)); + runner->required_extensions[runner->required_extension_count++] = features[i].extension; + } + } + } else { fatal_error("Unknown require directive '%s'.\n", line); @@ -1220,6 +1242,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o }
out: + free(runner->required_extensions); for (i = 0; i < runner->input_element_count; ++i) free(runner->input_elements[i].name); free(runner->input_elements); diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 0844943da..687c59876 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -99,6 +99,7 @@ struct input_element #define MAX_RESOURCES 32 #define MAX_SAMPLERS 32
+enum vkd3d_shader_spirv_extension; struct shader_runner { const struct shader_runner_ops *ops; @@ -125,6 +126,9 @@ struct shader_runner size_t input_element_count, input_element_capacity;
unsigned int compile_options; + + enum vkd3d_shader_spirv_extension *required_extensions; + size_t required_extension_count, required_extension_capacity; };
struct shader_runner_ops diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 25b585b14..98fcae620 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -29,6 +29,7 @@ #define __vkd3d_dxgibase_h__ #define __vkd3d_dxgiformat_h__ #include "vkd3d_d3dcompiler.h" +#include "vkd3d_shader.h" #include "shader_runner.h" #include "vkd3d_test.h"
@@ -336,6 +337,33 @@ static ID3D11Buffer *create_buffer(ID3D11Device *device, unsigned int bind_flags return buffer; }
+static bool d3d11_runner_check_requirements(struct shader_runner *r) +{ + struct d3d11_shader_runner *runner = d3d11_shader_runner(r); + ID3D11Device *device = runner->device; + unsigned int i; + + D3D11_FEATURE_DATA_D3D11_OPTIONS2 options2; + + if (FAILED(ID3D11Device_CheckFeatureSupport(device, D3D11_FEATURE_D3D11_OPTIONS2, &options2, sizeof(options2)))) + memset(&options2, 0, sizeof(options2)); + + for (i = 0; i < r->required_extension_count; i++) + { + switch (r->required_extensions[i]) + { + case VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK: + if (!options2.ROVsSupported) + return false; + break; + default: + return false; + } + } + + return true; +} + static struct resource *d3d11_runner_create_resource(struct shader_runner *r, const struct resource_params *params) { struct d3d11_shader_runner *runner = d3d11_shader_runner(r); @@ -724,6 +752,7 @@ static void d3d11_runner_release_readback(struct shader_runner *r, struct resour
static const struct shader_runner_ops d3d11_runner_ops = { + .check_requirements = d3d11_runner_check_requirements, .create_resource = d3d11_runner_create_resource, .destroy_resource = d3d11_runner_destroy_resource, .dispatch = d3d11_runner_dispatch, diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index d620f1e2d..65bdb6a98 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -23,6 +23,7 @@ #define VKD3D_TEST_NO_DEFS #include "d3d12_crosstest.h" #include "shader_runner.h" +#include "vkd3d_shader.h"
struct d3d12_resource { @@ -84,6 +85,34 @@ static ID3D10Blob *compile_shader(const struct d3d12_shader_runner *runner, cons return blob; }
+static bool d3d12_runner_check_requirements(struct shader_runner *r) +{ + struct d3d12_shader_runner *runner = d3d12_shader_runner(r); + ID3D12Device *device = runner->test_context.device; + unsigned int i; + + D3D12_FEATURE_DATA_D3D12_OPTIONS options; + + if (FAILED(ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)))) + memset(&options, 0, sizeof(options)); + + for (i = 0; i < r->required_extension_count; i++) + { + switch (r->required_extensions[i]) + { + case VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK: + if (!options.ROVsSupported) + return false; + break; + default: + return false; + } + } + + return true; +} + + #define MAX_RESOURCE_DESCRIPTORS (MAX_RESOURCES * 2)
static struct resource *d3d12_runner_create_resource(struct shader_runner *r, const struct resource_params *params) @@ -542,6 +571,7 @@ static void d3d12_runner_release_readback(struct shader_runner *r, struct resour
static const struct shader_runner_ops d3d12_runner_ops = { + .check_requirements = d3d12_runner_check_requirements, .create_resource = d3d12_runner_create_resource, .destroy_resource = d3d12_runner_destroy_resource, .dispatch = d3d12_runner_dispatch, diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index a8e59eef2..6e41c31fa 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -70,6 +70,8 @@ struct vulkan_shader_runner uint32_t binding; } samplers[MAX_SAMPLERS];
+ bool EXT_fragment_shader_interlock; + DECLARE_VK_PFN(vkCreateInstance); #define VK_INSTANCE_PFN DECLARE_VK_PFN #define VK_DEVICE_PFN DECLARE_VK_PFN @@ -245,6 +247,27 @@ static VkImageView create_2d_image_view(const struct vulkan_shader_runner *runne return view; }
+static bool vulkan_runner_check_requirements(struct shader_runner *r) +{ + struct vulkan_shader_runner *runner = vulkan_shader_runner(r); + unsigned int i; + + for (i = 0; i < r->required_extension_count; i++) + { + switch (r->required_extensions[i]) + { + case VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK: + if (!runner->EXT_fragment_shader_interlock) + return false; + break; + default: + return false; + } + } + + return true; +} + static struct resource *vulkan_runner_create_resource(struct shader_runner *r, const struct resource_params *params) { struct vulkan_shader_runner *runner = vulkan_shader_runner(r); @@ -455,6 +478,8 @@ static bool compile_shader(const struct vulkan_shader_runner *runner, const char info.target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY;
spirv_info.next = &interface_info; + spirv_info.extensions = runner->r.required_extensions; + spirv_info.extension_count = runner->r.required_extension_count; spirv_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
push_constants.register_space = 0; @@ -1153,6 +1178,7 @@ static void vulkan_runner_release_readback(struct shader_runner *r, struct resou
static const struct shader_runner_ops vulkan_runner_ops = { + .check_requirements = vulkan_runner_check_requirements, .create_resource = vulkan_runner_create_resource, .destroy_resource = vulkan_runner_destroy_resource, .dispatch = vulkan_runner_dispatch, @@ -1185,6 +1211,11 @@ static bool get_graphics_queue_index(const struct vulkan_shader_runner *runner, return false; }
+static const char *const required_instance_extensions[] = +{ + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, +}; + static const char *const required_device_extensions[] = { VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, @@ -1202,6 +1233,24 @@ static bool has_extension(const VkExtensionProperties *extensions, uint32_t coun return false; }
+static bool check_instance_extensions(struct vulkan_shader_runner *runner) +{ + VkExtensionProperties *extensions; + uint32_t i, count; + VK_CALL(vkEnumerateInstanceExtensionProperties(NULL, &count, NULL)); + extensions = calloc(count, sizeof(*extensions)); + VK_CALL(vkEnumerateInstanceExtensionProperties(NULL, &count, extensions)); + for (i = 0; i < ARRAY_SIZE(required_instance_extensions); ++i) + { + if (!has_extension(extensions, count, required_instance_extensions[i])) + { + skip("The Vulkan instance does not support %s\n", required_instance_extensions[i]); + return false; + } + } + return true; +} + static bool check_device_extensions(struct vulkan_shader_runner *runner) { VkPhysicalDevice phys_device = runner->phys_device; @@ -1232,14 +1281,27 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) VkDeviceQueueCreateInfo queue_desc = {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; VkInstanceCreateInfo instance_desc = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; VkDeviceCreateInfo device_desc = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; - VkPhysicalDeviceFeatures ret_features, features; + VkPhysicalDeviceFeatures2 ret_features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fsi_features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT}; + VkExtensionProperties *extension_properties; VkDescriptorPoolSize descriptor_pool_sizes[4]; static const float queue_priority = 1.0f; VkFormatProperties format_props; uint32_t count, graphics_index; VkDevice device; void *libvulkan; + size_t i, j; VkResult vr; + static const struct optional_extension { + const char* name; + size_t offset; + } + optional_extensions[] = + { + { VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME, offsetof(struct vulkan_shader_runner, EXT_fragment_shader_interlock) }, + }; + const char* enabled_extensions[ARRAY_SIZE(optional_extensions) + ARRAY_SIZE(required_device_extensions)];
if (!(libvulkan = vkd3d_dlopen(SONAME_LIBVULKAN))) { @@ -1249,6 +1311,13 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) vkGetInstanceProcAddr = vkd3d_dlsym(libvulkan, "vkGetInstanceProcAddr");
runner->vkCreateInstance = (void *)vkGetInstanceProcAddr(NULL, "vkCreateInstance"); + runner->vkEnumerateInstanceExtensionProperties = (void*)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); + + if (!check_instance_extensions(runner)) + return false; + + instance_desc.enabledExtensionCount = ARRAY_SIZE(required_instance_extensions); + instance_desc.ppEnabledExtensionNames = required_instance_extensions;
if ((vr = VK_CALL(vkCreateInstance(&instance_desc, NULL, &runner->instance))) < 0) { @@ -1280,8 +1349,26 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner)
device_desc.pQueueCreateInfos = &queue_desc; device_desc.queueCreateInfoCount = 1; - device_desc.enabledExtensionCount = ARRAY_SIZE(required_device_extensions); - device_desc.ppEnabledExtensionNames = required_device_extensions; + device_desc.ppEnabledExtensionNames = enabled_extensions; + for (i = 0; i < ARRAY_SIZE(required_device_extensions); i++) + enabled_extensions[device_desc.enabledExtensionCount++] = required_device_extensions[i]; + + count = 0; + VK_CALL(vkEnumerateDeviceExtensionProperties(runner->phys_device, NULL, &count, NULL)); + extension_properties = malloc(count * sizeof(*extension_properties)); + VK_CALL(vkEnumerateDeviceExtensionProperties(runner->phys_device, NULL, &count, extension_properties)); + for (i = 0; i < ARRAY_SIZE(optional_extensions); i++) + { + for (j = 0; j < count; j++) + { + if (0 == strcmp(optional_extensions[i].name, extension_properties[j].extensionName)) + { + enabled_extensions[device_desc.enabledExtensionCount++] = optional_extensions[i].name; + *(bool*)((char*)runner + optional_extensions[i].offset) = true; + } + } + } + free(extension_properties);
queue_desc.queueFamilyIndex = graphics_index; queue_desc.queueCount = 1; @@ -1297,7 +1384,23 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) goto out_destroy_instance; }
- VK_CALL(vkGetPhysicalDeviceFeatures(runner->phys_device, &ret_features)); + if (runner->EXT_fragment_shader_interlock) + { + fsi_features.pNext = ret_features.pNext; + ret_features.pNext = &fsi_features; + } + VK_CALL(vkGetPhysicalDeviceFeatures2KHR(runner->phys_device, &ret_features)); + + if (fsi_features.fragmentShaderPixelInterlock && fsi_features.fragmentShaderSampleInterlock) + { + fsi_features.fragmentShaderShadingRateInterlock = VK_FALSE; + fsi_features.pNext = (void*)device_desc.pNext; + device_desc.pNext = &fsi_features; + } + else + { + runner->EXT_fragment_shader_interlock = false; + }
device_desc.pEnabledFeatures = &features; memset(&features, 0, sizeof(features)); @@ -1305,7 +1408,7 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) /* FIXME: Probably make these optional. */
#define ENABLE_FEATURE(x) \ - if (!ret_features.x) \ + if (!ret_features.features.x) \ { \ skip("The selected Vulkan device does not support " #x ".\n"); \ goto out_destroy_instance; \ diff --git a/tests/vulkan_procs.h b/tests/vulkan_procs.h index 1829133b2..078e93d3a 100644 --- a/tests/vulkan_procs.h +++ b/tests/vulkan_procs.h @@ -36,9 +36,10 @@ VK_INSTANCE_PFN(vkDestroyInstance) /* Load vkDestroyInstance() first. */ VK_INSTANCE_PFN(vkCreateDevice) VK_INSTANCE_PFN(vkEnumerateDeviceExtensionProperties) +VK_INSTANCE_PFN(vkEnumerateInstanceExtensionProperties) VK_INSTANCE_PFN(vkEnumeratePhysicalDevices) VK_INSTANCE_PFN(vkGetDeviceProcAddr) -VK_INSTANCE_PFN(vkGetPhysicalDeviceFeatures) +VK_INSTANCE_PFN(vkGetPhysicalDeviceFeatures2KHR) VK_INSTANCE_PFN(vkGetPhysicalDeviceFormatProperties) VK_INSTANCE_PFN(vkGetPhysicalDeviceMemoryProperties) VK_INSTANCE_PFN(vkGetPhysicalDeviceQueueFamilyProperties)