[PATCH 2/3] winevulkan: Implement vkEnumeratePhysicalDevices.

Józef Kucia joseph.kucia at gmail.com
Fri Mar 2 05:57:43 CST 2018


On Fri, Mar 2, 2018 at 7:13 AM, Roderick Colenbrander
<thunderbird2k at gmail.com> wrote:
> Signed-off-by: Roderick Colenbrander <thunderbird2k at gmail.com>
> ---
>  dlls/winevulkan/make_vulkan      |   1 +
>  dlls/winevulkan/vulkan.c         | 140 +++++++++++++++++++++++++++++++++++++++
>  dlls/winevulkan/vulkan_private.h |  14 ++++
>  dlls/winevulkan/vulkan_thunks.c  |   6 --
>  dlls/winevulkan/vulkan_thunks.h  |   1 +
>  5 files changed, 156 insertions(+), 6 deletions(-)
>
> diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
> index 5657b70c4c..3b045db8a9 100755
> --- a/dlls/winevulkan/make_vulkan
> +++ b/dlls/winevulkan/make_vulkan
> @@ -90,6 +90,7 @@ FUNCTION_OVERRIDES = {
>
>      # Instance functions
>      "vkDestroyInstance" : {"dispatch" : True, "driver" : True, "thunk" : False },
> +    "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
>  }
>
>
> diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
> index 0f48d971e2..234be589ae 100644
> --- a/dlls/winevulkan/vulkan.c
> +++ b/dlls/winevulkan/vulkan.c
> @@ -58,6 +58,85 @@ static BOOL wine_vk_init(void)
>      return TRUE;
>  }
>
> +/* Helper function which stores wrapped physical devices in the instance object. */
> +static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *instance)
> +{
> +    VkResult res;
> +    struct VkPhysicalDevice_T **tmp_phys_devs = NULL;
> +    uint32_t num_phys_devs = 0;
> +    unsigned int i;
> +
> +    res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, NULL);
> +    if (res != VK_SUCCESS)
> +    {
> +        ERR("Failed to enumerate physical devices, res=%d\n", res);
> +        return res;
> +    }
> +
> +    /* Don't bother with any of the rest if the system just lacks devices. */
> +    if (num_phys_devs == 0)
> +    {
> +        instance->num_phys_devs = 0;

instance->phys_devs isn't initialized.

> +        return VK_SUCCESS;
> +    }
> +
> +    tmp_phys_devs = heap_alloc(num_phys_devs * sizeof(*tmp_phys_devs));
> +    if (!tmp_phys_devs)
> +        return VK_ERROR_OUT_OF_HOST_MEMORY;

This leaves a lot of fields uninitialized in "instance". We don't want
to crash in wine_vk_instance_free().

> +
> +    res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, tmp_phys_devs);
> +    if (res != VK_SUCCESS)
> +        goto err;
> +
> +    instance->phys_devs = heap_alloc(num_phys_devs * sizeof(*instance->phys_devs));

heap_calloc() may be more suitable.

> +    if (!instance->phys_devs)
> +    {
> +        res = VK_ERROR_OUT_OF_HOST_MEMORY;
> +        goto err;
> +    }
> +
> +    /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
> +    for (i = 0; i < num_phys_devs; i++)
> +    {
> +        VkPhysicalDevice phys_dev = heap_alloc(sizeof(*phys_dev));

struct VkPhysicalDevice_T *

> +        if (!phys_dev)
> +        {
> +            ERR("Unable to allocate memory for physical device!\n");
> +            res = VK_ERROR_OUT_OF_HOST_MEMORY;
> +            goto err;
> +        }
> +
> +        phys_dev->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
> +        phys_dev->instance = instance;
> +        phys_dev->phys_dev = tmp_phys_devs[i];
> +
> +        instance->phys_devs[i] = phys_dev;
> +        instance->num_phys_devs = i;
> +    }
> +    instance->num_phys_devs = num_phys_devs;
> +
> +    heap_free(tmp_phys_devs);
> +    return VK_SUCCESS;
> +
> +err:
> +    if (tmp_phys_devs)
> +        heap_free(tmp_phys_devs);

It's fine to call heap_free() with NULL.

> +
> +    if (instance->phys_devs)
> +    {
> +        for (i = 0; i < instance->num_phys_devs; i++)
> +        {
> +            heap_free(instance->phys_devs[i]);
> +            instance->phys_devs[i] = NULL;
> +        }
> +        heap_free(instance->phys_devs);
> +        instance->num_phys_devs = 0;
> +        instance->phys_devs = NULL;
> +    }
> +
> +    return res;
> +}
> +
>  /* Helper function used for freeing an instance structure. This function supports full
>   * and partial object cleanups and can thus be used for vkCreateInstance failures.
>   */
> @@ -66,6 +145,17 @@ static void wine_vk_instance_free(struct VkInstance_T *instance)
>      if (!instance)
>          return;
>
> +    if (instance->phys_devs)
> +    {
> +        unsigned int i;
> +
> +        for (i = 0; i < instance->num_phys_devs; i++)
> +        {
> +            heap_free(&instance->phys_devs[i]);
> +        }
> +        heap_free(instance->phys_devs);
> +    }

It might crash because "phys_devs" is uninitialized. We probably want
to use heap_alloc_zero() to allocate "instance".

> +
>      if (instance->instance)
>          vk_funcs->p_vkDestroyInstance(instance->instance, NULL /* allocator */);
>
> @@ -108,6 +198,18 @@ static VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_
>      ALL_VK_INSTANCE_FUNCS()
>  #undef USE_VK_FUNC
>
> +    /* Cache physical devices for vkEnumeratePhysicalDevices within the instance as
> +     * each vkPhysicalDevice is a dispatchable object, which means we need to wrap
> +     * the native physical device and present those the application.
> +     * Cleanup happens as part of wine_vkDestroyInstance.
> +     */
> +    res = wine_vk_instance_load_physical_devices(object);
> +    if (res != VK_SUCCESS)
> +    {
> +        ERR("Failed to cache physical devices, res=%d\n", res);
> +        goto err;
> +    }
> +
>      *instance = object;
>      TRACE("Done, instance=%p native_instance=%p\n", object, object->instance);
>      return VK_SUCCESS;
> @@ -134,6 +236,44 @@ static VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *l
>      return vk_funcs->p_vkEnumerateInstanceExtensionProperties(layer_name, count, properties);
>  }
>
> +VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *device_count,
> +        VkPhysicalDevice *devices)
> +{
> +    VkResult res;
> +    unsigned int i, num_copies;
> +
> +    TRACE("%p %p %p\n", instance, device_count, devices);
> +
> +    if (!devices)
> +    {
> +        *device_count = instance->num_phys_devs;
> +        return VK_SUCCESS;
> +    }
> +
> +    if (*device_count < instance->num_phys_devs)
> +    {
> +        /* Incomplete is a type of success used to signal the application
> +         * that not all devices got copied.
> +         */
> +        num_copies = *device_count;
> +        res = VK_INCOMPLETE;
> +    }
> +    else
> +    {
> +        num_copies = instance->num_phys_devs;
> +        res = VK_SUCCESS;
> +    }
> +
> +    for (i = 0; i < num_copies; i++)
> +    {
> +        devices[i] = instance->phys_devs[i];
> +    }
> +    *device_count = num_copies;
> +
> +    TRACE("Returning %d devices\n", *device_count);
> +    return res;
> +}
> +
>  static PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const char *name)
>  {
>      void *func;
> diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
> index 16aa0ce55c..8ef4b924a2 100644
> --- a/dlls/winevulkan/vulkan_private.h
> +++ b/dlls/winevulkan/vulkan_private.h
> @@ -52,7 +52,21 @@ struct VkInstance_T
>  {
>      struct wine_vk_base base;
>      struct vulkan_instance_funcs funcs;
> +
> +    /* We cache devices as we need to wrap them as they are
> +     * dispatchable objects.
> +     */
> +    uint32_t num_phys_devs;
> +    struct VkPhysicalDevice_T **phys_devs;
> +
>      VkInstance instance; /* native instance */
>  };
>
> +struct VkPhysicalDevice_T
> +{
> +    struct wine_vk_base base;
> +    struct VkInstance_T *instance; /* parent */
> +    VkPhysicalDevice phys_dev; /* native physical device */
> +};
> +
>  #endif /* __WINE_VULKAN_PRIVATE_H */
> diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
> index c1c0b079a5..ae4f773ef0 100644
> --- a/dlls/winevulkan/vulkan_thunks.c
> +++ b/dlls/winevulkan/vulkan_thunks.c
> @@ -28,12 +28,6 @@ static VkResult WINAPI wine_vkEnumerateDeviceLayerProperties(VkPhysicalDevice ph
>      return VK_ERROR_OUT_OF_HOST_MEMORY;
>  }
>
> -static VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices)
> -{
> -    FIXME("stub: %p, %p, %p\n", instance, pPhysicalDeviceCount, pPhysicalDevices);
> -    return VK_ERROR_OUT_OF_HOST_MEMORY;
> -}
> -
>  static void WINAPI wine_vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures)
>  {
>      FIXME("stub: %p, %p\n", physicalDevice, pFeatures);
> diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
> index 087fa17d0e..26e114ab74 100644
> --- a/dlls/winevulkan/vulkan_thunks.h
> +++ b/dlls/winevulkan/vulkan_thunks.h
> @@ -8,6 +8,7 @@ void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
>
>  /* Functions for which we have custom implementations outside of the thunks. */
>  void WINAPI wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN;
> +VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) DECLSPEC_HIDDEN;
>
>  /* For use by vkInstance and children */
>  struct vulkan_instance_funcs
> --
> 2.14.3
>
>
>



More information about the wine-devel mailing list