2019-04-01 14:50:26 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2018 Henri Verbeet 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "wine/port.h"
|
|
|
|
#include "wined3d_private.h"
|
|
|
|
|
2019-04-03 11:11:32 +02:00
|
|
|
#include "wine/vulkan_driver.h"
|
|
|
|
|
2019-04-01 14:50:26 +02:00
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
|
|
|
|
2019-04-03 11:11:33 +02:00
|
|
|
#ifdef USE_WIN32_VULKAN
|
|
|
|
static BOOL wined3d_load_vulkan(struct wined3d_vk_info *vk_info)
|
|
|
|
{
|
|
|
|
struct vulkan_ops *vk_ops = &vk_info->vk_ops;
|
|
|
|
|
|
|
|
if (!(vk_info->vulkan_lib = LoadLibraryA("vulkan-1.dll")))
|
|
|
|
{
|
|
|
|
WARN("Failed to load vulkan-1.dll.\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
vk_ops->vkGetInstanceProcAddr = (void *)GetProcAddress(vk_info->vulkan_lib, "vkGetInstanceProcAddr");
|
|
|
|
if (!vk_ops->vkGetInstanceProcAddr)
|
|
|
|
{
|
|
|
|
FreeLibrary(vk_info->vulkan_lib);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wined3d_unload_vulkan(struct wined3d_vk_info *vk_info)
|
|
|
|
{
|
|
|
|
if (vk_info->vulkan_lib)
|
|
|
|
{
|
|
|
|
FreeLibrary(vk_info->vulkan_lib);
|
|
|
|
vk_info->vulkan_lib = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static BOOL wined3d_load_vulkan(struct wined3d_vk_info *vk_info)
|
|
|
|
{
|
|
|
|
struct vulkan_ops *vk_ops = &vk_info->vk_ops;
|
|
|
|
const struct vulkan_funcs *vk_funcs;
|
|
|
|
HDC dc;
|
|
|
|
|
|
|
|
dc = GetDC(0);
|
|
|
|
vk_funcs = __wine_get_vulkan_driver(dc, WINE_VULKAN_DRIVER_VERSION);
|
|
|
|
ReleaseDC(0, dc);
|
|
|
|
|
|
|
|
if (!vk_funcs)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
vk_ops->vkGetInstanceProcAddr = (void *)vk_funcs->p_vkGetInstanceProcAddr;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wined3d_unload_vulkan(struct wined3d_vk_info *vk_info) {}
|
|
|
|
#endif
|
|
|
|
|
2019-04-01 14:50:26 +02:00
|
|
|
static void adapter_vk_destroy(struct wined3d_adapter *adapter)
|
|
|
|
{
|
2019-04-03 11:11:32 +02:00
|
|
|
struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk(adapter);
|
2019-04-03 11:11:33 +02:00
|
|
|
struct wined3d_vk_info *vk_info = &adapter_vk->vk_info;
|
2019-04-03 11:11:32 +02:00
|
|
|
|
|
|
|
VK_CALL(vkDestroyInstance(vk_info->instance, NULL));
|
2019-04-03 11:11:33 +02:00
|
|
|
wined3d_unload_vulkan(vk_info);
|
2019-04-03 11:11:32 +02:00
|
|
|
wined3d_adapter_cleanup(&adapter_vk->a);
|
|
|
|
heap_free(adapter_vk);
|
2019-04-01 14:50:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL adapter_vk_create_context(struct wined3d_context *context,
|
|
|
|
struct wined3d_texture *target, const struct wined3d_format *ds_format)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void adapter_vk_get_wined3d_caps(const struct wined3d_adapter *adapter, struct wined3d_caps *caps)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL adapter_vk_check_format(const struct wined3d_adapter *adapter,
|
|
|
|
const struct wined3d_format *adapter_format, const struct wined3d_format *rt_format,
|
|
|
|
const struct wined3d_format *ds_format)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wined3d_adapter_ops wined3d_adapter_vk_ops =
|
|
|
|
{
|
|
|
|
adapter_vk_destroy,
|
|
|
|
adapter_vk_create_context,
|
|
|
|
adapter_vk_get_wined3d_caps,
|
|
|
|
adapter_vk_check_format,
|
|
|
|
};
|
|
|
|
|
2019-04-03 11:11:34 +02:00
|
|
|
static unsigned int wined3d_get_wine_vk_version(void)
|
|
|
|
{
|
|
|
|
const char *ptr = PACKAGE_VERSION;
|
|
|
|
int major, minor;
|
|
|
|
|
|
|
|
major = atoi(ptr);
|
|
|
|
|
|
|
|
while (isdigit(*ptr) || *ptr == '.')
|
|
|
|
++ptr;
|
|
|
|
|
|
|
|
minor = atoi(ptr);
|
|
|
|
|
|
|
|
return VK_MAKE_VERSION(major, minor, 0);
|
|
|
|
}
|
|
|
|
|
2019-04-03 11:11:32 +02:00
|
|
|
static BOOL wined3d_init_vulkan(struct wined3d_vk_info *vk_info)
|
|
|
|
{
|
|
|
|
struct vulkan_ops *vk_ops = &vk_info->vk_ops;
|
2019-04-03 11:11:33 +02:00
|
|
|
VkInstance instance = VK_NULL_HANDLE;
|
2019-04-03 11:11:32 +02:00
|
|
|
VkInstanceCreateInfo instance_info;
|
2019-04-03 11:11:34 +02:00
|
|
|
VkApplicationInfo app_info;
|
|
|
|
char app_name[MAX_PATH];
|
2019-04-03 11:11:32 +02:00
|
|
|
VkResult vr;
|
|
|
|
|
2019-04-03 11:11:33 +02:00
|
|
|
if (!wined3d_load_vulkan(vk_info))
|
2019-04-03 11:11:32 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!(vk_ops->vkCreateInstance = (void *)VK_CALL(vkGetInstanceProcAddr(NULL, "vkCreateInstance"))))
|
|
|
|
{
|
|
|
|
ERR("Could not get 'vkCreateInstance'.\n");
|
2019-04-03 11:11:33 +02:00
|
|
|
goto fail;
|
2019-04-03 11:11:32 +02:00
|
|
|
}
|
|
|
|
|
2019-04-03 11:11:34 +02:00
|
|
|
memset(&app_info, 0, sizeof(app_info));
|
|
|
|
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
|
|
if (wined3d_get_app_name(app_name, ARRAY_SIZE(app_name)))
|
|
|
|
app_info.pApplicationName = app_name;
|
|
|
|
app_info.pEngineName = "Damavand";
|
|
|
|
app_info.engineVersion = wined3d_get_wine_vk_version();
|
|
|
|
app_info.apiVersion = VK_API_VERSION_1_0;
|
|
|
|
|
2019-04-03 11:11:32 +02:00
|
|
|
memset(&instance_info, 0, sizeof(instance_info));
|
|
|
|
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
2019-04-03 11:11:34 +02:00
|
|
|
instance_info.pApplicationInfo = &app_info;
|
2019-04-03 11:11:32 +02:00
|
|
|
if ((vr = VK_CALL(vkCreateInstance(&instance_info, NULL, &instance))) < 0)
|
|
|
|
{
|
|
|
|
WARN("Failed to create Vulkan instance, vr %d.\n", vr);
|
2019-04-03 11:11:33 +02:00
|
|
|
goto fail;
|
2019-04-03 11:11:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Created Vulkan instance %p.\n", instance);
|
|
|
|
|
|
|
|
#define LOAD_INSTANCE_PFN(name) \
|
|
|
|
if (!(vk_ops->name = (void *)VK_CALL(vkGetInstanceProcAddr(instance, #name)))) \
|
|
|
|
{ \
|
|
|
|
WARN("Could not get instance proc addr for '" #name "'.\n"); \
|
2019-04-03 11:11:33 +02:00
|
|
|
goto fail; \
|
2019-04-03 11:11:32 +02:00
|
|
|
}
|
|
|
|
#define VK_INSTANCE_PFN LOAD_INSTANCE_PFN
|
|
|
|
#define VK_DEVICE_PFN LOAD_INSTANCE_PFN
|
|
|
|
VK_INSTANCE_FUNCS()
|
|
|
|
VK_DEVICE_FUNCS()
|
|
|
|
#undef VK_INSTANCE_PFN
|
|
|
|
#undef VK_DEVICE_PFN
|
|
|
|
|
|
|
|
vk_info->instance = instance;
|
|
|
|
|
|
|
|
return TRUE;
|
2019-04-03 11:11:33 +02:00
|
|
|
|
|
|
|
fail:
|
|
|
|
if (vk_ops->vkDestroyInstance)
|
|
|
|
VK_CALL(vkDestroyInstance(instance, NULL));
|
|
|
|
wined3d_unload_vulkan(vk_info);
|
|
|
|
return FALSE;
|
2019-04-03 11:11:32 +02:00
|
|
|
}
|
|
|
|
|
2019-04-05 10:52:07 +02:00
|
|
|
static VkPhysicalDevice get_vulkan_physical_device(struct wined3d_vk_info *vk_info)
|
|
|
|
{
|
|
|
|
VkPhysicalDevice physical_devices[1];
|
|
|
|
uint32_t count;
|
|
|
|
VkResult vr;
|
|
|
|
|
|
|
|
if ((vr = VK_CALL(vkEnumeratePhysicalDevices(vk_info->instance, &count, NULL))) < 0)
|
|
|
|
{
|
|
|
|
WARN("Failed to enumerate physical devices, vr %d.\n", vr);
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
if (!count)
|
|
|
|
{
|
|
|
|
WARN("No physical device.\n");
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
if (count > 1)
|
|
|
|
{
|
|
|
|
/* TODO: Create wined3d_adapter for each device. */
|
|
|
|
FIXME("Multiple physical devices available.\n");
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((vr = VK_CALL(vkEnumeratePhysicalDevices(vk_info->instance, &count, physical_devices))) < 0)
|
|
|
|
{
|
|
|
|
WARN("Failed to get physical devices, vr %d.\n", vr);
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return physical_devices[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct wined3d_gpu_description *get_vulkan_gpu_description(const struct wined3d_vk_info *vk_info,
|
|
|
|
VkPhysicalDevice physical_device)
|
|
|
|
{
|
|
|
|
const struct wined3d_gpu_description *description;
|
|
|
|
VkPhysicalDeviceProperties properties;
|
|
|
|
|
|
|
|
VK_CALL(vkGetPhysicalDeviceProperties(physical_device, &properties));
|
|
|
|
|
|
|
|
TRACE("Device name: %s.\n", debugstr_a(properties.deviceName));
|
|
|
|
TRACE("Vendor ID: 0x%04x, Device ID: 0x%04x.\n", properties.vendorID, properties.deviceID);
|
|
|
|
TRACE("Driver version: %#x.\n", properties.driverVersion);
|
|
|
|
TRACE("API version: %u.%u.%u.\n", VK_VERSION_MAJOR(properties.apiVersion),
|
|
|
|
VK_VERSION_MINOR(properties.apiVersion), VK_VERSION_PATCH(properties.apiVersion));
|
|
|
|
|
|
|
|
if ((description = wined3d_get_gpu_description(properties.vendorID, properties.deviceID)))
|
|
|
|
return description;
|
|
|
|
|
|
|
|
FIXME("Failed to retrieve GPU description for device %s %04x:%04x.\n",
|
|
|
|
debugstr_a(properties.deviceName), properties.vendorID, properties.deviceID);
|
|
|
|
|
|
|
|
return wined3d_get_gpu_description(HW_VENDOR_AMD, CARD_AMD_RADEON_RX_VEGA);
|
|
|
|
}
|
|
|
|
|
2019-04-01 14:50:26 +02:00
|
|
|
static BOOL wined3d_adapter_vk_init(struct wined3d_adapter_vk *adapter_vk,
|
|
|
|
unsigned int ordinal, unsigned int wined3d_creation_flags)
|
|
|
|
{
|
2019-04-03 11:11:32 +02:00
|
|
|
struct wined3d_vk_info *vk_info = &adapter_vk->vk_info;
|
2019-04-01 14:50:26 +02:00
|
|
|
const struct wined3d_gpu_description *gpu_description;
|
|
|
|
struct wined3d_adapter *adapter = &adapter_vk->a;
|
|
|
|
|
|
|
|
TRACE("adapter_vk %p, ordinal %u, wined3d_creation_flags %#x.\n",
|
|
|
|
adapter_vk, ordinal, wined3d_creation_flags);
|
|
|
|
|
|
|
|
if (!wined3d_adapter_init(adapter, ordinal))
|
|
|
|
return FALSE;
|
|
|
|
|
2019-04-03 11:11:32 +02:00
|
|
|
if (!wined3d_init_vulkan(vk_info))
|
|
|
|
{
|
|
|
|
WARN("Failed to initialize Vulkan.\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2019-04-05 10:52:07 +02:00
|
|
|
if (!(adapter_vk->physical_device = get_vulkan_physical_device(vk_info)))
|
|
|
|
goto fail_vulkan;
|
|
|
|
|
|
|
|
if (!(gpu_description = get_vulkan_gpu_description(vk_info, adapter_vk->physical_device)))
|
2019-04-01 14:50:26 +02:00
|
|
|
{
|
|
|
|
ERR("Failed to get GPU description.\n");
|
2019-04-03 11:11:33 +02:00
|
|
|
goto fail_vulkan;
|
2019-04-01 14:50:26 +02:00
|
|
|
}
|
|
|
|
wined3d_driver_info_init(&adapter->driver_info, gpu_description, wined3d_settings.emulated_textureram);
|
|
|
|
|
2019-04-05 10:52:09 +02:00
|
|
|
if (!wined3d_adapter_vk_init_format_info(adapter_vk, vk_info))
|
2019-04-03 11:11:33 +02:00
|
|
|
goto fail_vulkan;
|
2019-04-01 14:50:26 +02:00
|
|
|
|
|
|
|
adapter->vertex_pipe = &none_vertex_pipe;
|
|
|
|
adapter->fragment_pipe = &none_fragment_pipe;
|
|
|
|
adapter->shader_backend = &none_shader_backend;
|
|
|
|
adapter->adapter_ops = &wined3d_adapter_vk_ops;
|
|
|
|
|
|
|
|
adapter->d3d_info.wined3d_creation_flags = wined3d_creation_flags;
|
|
|
|
|
|
|
|
return TRUE;
|
2019-04-03 11:11:32 +02:00
|
|
|
|
2019-04-03 11:11:33 +02:00
|
|
|
fail_vulkan:
|
|
|
|
VK_CALL(vkDestroyInstance(vk_info->instance, NULL));
|
|
|
|
wined3d_unload_vulkan(vk_info);
|
2019-04-03 11:11:32 +02:00
|
|
|
fail:
|
|
|
|
wined3d_adapter_cleanup(adapter);
|
|
|
|
return FALSE;
|
2019-04-01 14:50:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct wined3d_adapter *wined3d_adapter_vk_create(unsigned int ordinal,
|
|
|
|
unsigned int wined3d_creation_flags)
|
|
|
|
{
|
|
|
|
struct wined3d_adapter_vk *adapter_vk;
|
|
|
|
|
|
|
|
if (!(adapter_vk = heap_alloc_zero(sizeof(*adapter_vk))))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!wined3d_adapter_vk_init(adapter_vk, ordinal, wined3d_creation_flags))
|
|
|
|
{
|
|
|
|
heap_free(adapter_vk);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Created adapter %p.\n", adapter_vk);
|
|
|
|
|
|
|
|
return &adapter_vk->a;
|
|
|
|
}
|