diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index 0249c4c7af1..8cbd8206617 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -321,8 +321,20 @@ static HRESULT wined3d_select_vulkan_queue_family(const struct wined3d_adapter_v return E_FAIL; } -static void wined3d_disable_vulkan_features(VkPhysicalDeviceFeatures *features) +struct wined3d_physical_device_info { + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features; + + VkPhysicalDeviceFeatures2 features2; +}; + +static void wined3d_disable_vulkan_features(struct wined3d_physical_device_info *info) +{ + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features = &info->vertex_divisor_features; + VkPhysicalDeviceFeatures *features = &info->features2.features; + + vertex_divisor_features->vertexAttributeInstanceRateZeroDivisor = VK_FALSE; + features->depthBounds = VK_FALSE; features->alphaToOne = VK_FALSE; features->textureCompressionETC2 = VK_FALSE; @@ -405,6 +417,7 @@ static const struct } vulkan_device_extensions[] = { + {VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, ~0u}, {VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_API_VERSION_1_1}, {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_API_VERSION_1_1}, }; @@ -472,12 +485,14 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi { const struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk_const(adapter); const char *enabled_device_extensions[ARRAY_SIZE(vulkan_device_extensions)]; + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features; const struct wined3d_vk_info *vk_info = &adapter_vk->vk_info; + struct wined3d_physical_device_info physical_device_info; static const float priorities[] = {1.0f}; + VkPhysicalDeviceFeatures2 *features2; struct wined3d_device_vk *device_vk; VkDevice vk_device = VK_NULL_HANDLE; VkDeviceQueueCreateInfo queue_info; - VkPhysicalDeviceFeatures features; VkPhysicalDevice physical_device; VkDeviceCreateInfo device_info; uint32_t queue_family_index; @@ -492,8 +507,28 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi physical_device = adapter_vk->physical_device; - VK_CALL(vkGetPhysicalDeviceFeatures(physical_device, &features)); - wined3d_disable_vulkan_features(&features); + memset(&physical_device_info, 0, sizeof(physical_device_info)); + + vertex_divisor_features = &physical_device_info.vertex_divisor_features; + vertex_divisor_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; + + features2 = &physical_device_info.features2; + features2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features2->pNext = vertex_divisor_features; + + if (vk_info->vk_ops.vkGetPhysicalDeviceFeatures2) + VK_CALL(vkGetPhysicalDeviceFeatures2(physical_device, features2)); + else + VK_CALL(vkGetPhysicalDeviceFeatures(physical_device, &features2->features)); + + if (!vertex_divisor_features->vertexAttributeInstanceRateDivisor) + { + WARN("Vertex attribute divisors not supported.\n"); + hr = E_FAIL; + goto fail; + } + + wined3d_disable_vulkan_features(&physical_device_info); queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_info.pNext = NULL; @@ -503,7 +538,7 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi queue_info.pQueuePriorities = priorities; device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_info.pNext = NULL; + device_info.pNext = features2->pNext; device_info.flags = 0; device_info.queueCreateInfoCount = 1; device_info.pQueueCreateInfos = &queue_info; @@ -516,7 +551,7 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi hr = E_FAIL; goto fail; } - device_info.pEnabledFeatures = &features; + device_info.pEnabledFeatures = &features2->features; if ((vr = VK_CALL(vkCreateDevice(physical_device, &device_info, NULL, &vk_device))) < 0) { @@ -1914,6 +1949,7 @@ static BOOL wined3d_init_vulkan(struct wined3d_vk_info *vk_info) if (!vk_ops->core_pfn) \ vk_ops->core_pfn = (void *)VK_CALL(vkGetInstanceProcAddr(instance, #ext_pfn)); MAP_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties2, vkGetPhysicalDeviceProperties2KHR) + MAP_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures2, vkGetPhysicalDeviceFeaturess2KHR) #undef MAP_INSTANCE_FUNCTION vk_info->instance = instance; diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 13d3b4c5445..3a6671036e2 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -1440,6 +1440,12 @@ static int wined3d_graphics_pipeline_vk_compare(const void *key, const struct wi return a->stages[i].module - b->stages[i].module; } + if (a->divisor_desc.vertexBindingDivisorCount != b->divisor_desc.vertexBindingDivisorCount) + return a->divisor_desc.vertexBindingDivisorCount - b->divisor_desc.vertexBindingDivisorCount; + if ((ret = memcmp(a->divisors, b->divisors, + a->divisor_desc.vertexBindingDivisorCount * sizeof(*a->divisors)))) + return ret; + if (a->input_desc.vertexAttributeDescriptionCount != b->input_desc.vertexAttributeDescriptionCount) return a->input_desc.vertexAttributeDescriptionCount - b->input_desc.vertexAttributeDescriptionCount; if ((ret = memcmp(a->attributes, b->attributes, @@ -1526,6 +1532,9 @@ static void wined3d_context_vk_init_graphics_pipeline_key(struct wined3d_context key->input_desc.pVertexBindingDescriptions = key->bindings; key->input_desc.pVertexAttributeDescriptions = key->attributes; + key->divisor_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; + key->divisor_desc.pVertexBindingDivisors = key->divisors; + key->ia_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; key->ts_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; @@ -1706,8 +1715,8 @@ static void wined3d_context_vk_update_blend_state(const struct wined3d_context_v static bool wined3d_context_vk_update_graphics_pipeline_key(struct wined3d_context_vk *context_vk, const struct wined3d_state *state, VkPipelineLayout vk_pipeline_layout) { + unsigned int i, attribute_count, binding_count, divisor_count, stage_count; const struct wined3d_d3d_info *d3d_info = context_vk->c.d3d_info; - unsigned int i, attribute_count, binding_count, stage_count; struct wined3d_graphics_pipeline_key_vk *key; VkPipelineShaderStageCreateInfo *stage; struct wined3d_stream_info stream_info; @@ -1741,8 +1750,10 @@ static bool wined3d_context_vk_update_graphics_pipeline_key(struct wined3d_conte || wined3d_context_is_graphics_state_dirty(&context_vk->c, STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX))) { wined3d_stream_info_from_declaration(&stream_info, state, d3d_info); + divisor_count = 0; for (i = 0, mask = 0, attribute_count = 0, binding_count = 0; i < ARRAY_SIZE(stream_info.elements); ++i) { + VkVertexInputBindingDivisorDescriptionEXT *d; struct wined3d_stream_info_element *e; VkVertexInputAttributeDescription *a; VkVertexInputBindingDescription *b; @@ -1768,11 +1779,25 @@ static bool wined3d_context_vk_update_graphics_pipeline_key(struct wined3d_conte b->binding = binding; b->stride = e->stride; b->inputRate = e->divisor ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; + + if (e->divisor > 1) + { + d = &key->divisors[divisor_count++]; + d->binding = binding; + d->divisor = e->divisor; + } } + key->input_desc.pNext = NULL; key->input_desc.vertexBindingDescriptionCount = binding_count; key->input_desc.vertexAttributeDescriptionCount = attribute_count; + if (divisor_count) + { + key->input_desc.pNext = &key->divisor_desc; + key->divisor_desc.vertexBindingDivisorCount = divisor_count; + } + update = true; } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index ab5df330e76..e9081e5d17d 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2323,12 +2323,14 @@ struct wined3d_pipeline_layout_vk struct wined3d_graphics_pipeline_key_vk { VkPipelineShaderStageCreateInfo stages[WINED3D_SHADER_TYPE_GRAPHICS_COUNT]; + VkVertexInputBindingDivisorDescriptionEXT divisors[MAX_ATTRIBS]; VkVertexInputAttributeDescription attributes[MAX_ATTRIBS]; VkVertexInputBindingDescription bindings[MAX_ATTRIBS]; VkViewport viewport; VkRect2D scissor; VkPipelineColorBlendAttachmentState blend_attachments[WINED3D_MAX_RENDER_TARGETS]; + VkPipelineVertexInputDivisorStateCreateInfoEXT divisor_desc; VkPipelineVertexInputStateCreateInfo input_desc; VkPipelineInputAssemblyStateCreateInfo ia_desc; VkPipelineTessellationStateCreateInfo ts_desc; diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index 0c0c1e16cd2..4a872bcdaa0 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -40,6 +40,7 @@ VK_INSTANCE_PFN(vkGetPhysicalDeviceQueueFamilyProperties) \ VK_INSTANCE_PFN(vkGetPhysicalDeviceSparseImageFormatProperties) \ /* Vulkan 1.1 */ \ + VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceFeatures2) \ VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceProperties2) #define VK_DEVICE_FUNCS() \