1446 lines
50 KiB
C
1446 lines
50 KiB
C
/*
|
|
* 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"
|
|
|
|
#include "wine/vulkan_driver.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
|
|
|
static inline const struct wined3d_adapter_vk *wined3d_adapter_vk_const(const struct wined3d_adapter *adapter)
|
|
{
|
|
return CONTAINING_RECORD(adapter, struct wined3d_adapter_vk, a);
|
|
}
|
|
|
|
static const char *debug_vk_version(uint32_t version)
|
|
{
|
|
return wine_dbg_sprintf("%u.%u.%u",
|
|
VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version));
|
|
}
|
|
|
|
static HRESULT hresult_from_vk_result(VkResult vr)
|
|
{
|
|
switch (vr)
|
|
{
|
|
case VK_SUCCESS:
|
|
return S_OK;
|
|
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
|
WARN("Out of host memory.\n");
|
|
return E_OUTOFMEMORY;
|
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
|
WARN("Out of device memory.\n");
|
|
return E_OUTOFMEMORY;
|
|
case VK_ERROR_DEVICE_LOST:
|
|
WARN("Device lost.\n");
|
|
return E_FAIL;
|
|
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
|
WARN("Extension not present.\n");
|
|
return E_FAIL;
|
|
default:
|
|
FIXME("Unhandled VkResult %d.\n", vr);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
#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
|
|
|
|
static void adapter_vk_destroy(struct wined3d_adapter *adapter)
|
|
{
|
|
struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk(adapter);
|
|
struct wined3d_vk_info *vk_info = &adapter_vk->vk_info;
|
|
|
|
VK_CALL(vkDestroyInstance(vk_info->instance, NULL));
|
|
wined3d_unload_vulkan(vk_info);
|
|
wined3d_adapter_cleanup(&adapter_vk->a);
|
|
heap_free(adapter_vk);
|
|
}
|
|
|
|
static HRESULT wined3d_select_vulkan_queue_family(const struct wined3d_adapter_vk *adapter_vk,
|
|
uint32_t *queue_family_index)
|
|
{
|
|
VkPhysicalDevice physical_device = adapter_vk->physical_device;
|
|
const struct wined3d_vk_info *vk_info = &adapter_vk->vk_info;
|
|
VkQueueFamilyProperties *queue_properties;
|
|
uint32_t count, i;
|
|
|
|
VK_CALL(vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, NULL));
|
|
|
|
if (!(queue_properties = heap_calloc(count, sizeof(*queue_properties))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
VK_CALL(vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, queue_properties));
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (queue_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
|
{
|
|
*queue_family_index = i;
|
|
heap_free(queue_properties);
|
|
return WINED3D_OK;
|
|
}
|
|
}
|
|
heap_free(queue_properties);
|
|
|
|
WARN("Failed to find graphics queue.\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
static void wined3d_disable_vulkan_features(VkPhysicalDeviceFeatures *features)
|
|
{
|
|
features->depthBounds = VK_FALSE;
|
|
features->alphaToOne = VK_FALSE;
|
|
features->textureCompressionETC2 = VK_FALSE;
|
|
features->textureCompressionASTC_LDR = VK_FALSE;
|
|
features->shaderStorageImageMultisample = VK_FALSE;
|
|
features->shaderUniformBufferArrayDynamicIndexing = VK_FALSE;
|
|
features->shaderSampledImageArrayDynamicIndexing = VK_FALSE;
|
|
features->shaderStorageBufferArrayDynamicIndexing = VK_FALSE;
|
|
features->shaderStorageImageArrayDynamicIndexing = VK_FALSE;
|
|
features->shaderInt16 = VK_FALSE;
|
|
features->shaderResourceResidency = VK_FALSE;
|
|
features->shaderResourceMinLod = VK_FALSE;
|
|
features->sparseBinding = VK_FALSE;
|
|
features->sparseResidencyBuffer = VK_FALSE;
|
|
features->sparseResidencyImage2D = VK_FALSE;
|
|
features->sparseResidencyImage3D = VK_FALSE;
|
|
features->sparseResidency2Samples = VK_FALSE;
|
|
features->sparseResidency4Samples = VK_FALSE;
|
|
features->sparseResidency8Samples = VK_FALSE;
|
|
features->sparseResidency16Samples = VK_FALSE;
|
|
features->sparseResidencyAliased = VK_FALSE;
|
|
features->inheritedQueries = VK_FALSE;
|
|
}
|
|
|
|
static struct wined3d_allocator_chunk *wined3d_allocator_vk_create_chunk(struct wined3d_allocator *allocator,
|
|
struct wined3d_context *context, unsigned int memory_type, size_t chunk_size)
|
|
{
|
|
struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
|
|
struct wined3d_allocator_chunk_vk *chunk_vk;
|
|
|
|
if (!(chunk_vk = heap_alloc(sizeof(*chunk_vk))))
|
|
return NULL;
|
|
|
|
if (!wined3d_allocator_chunk_init(&chunk_vk->c, allocator))
|
|
{
|
|
heap_free(chunk_vk);
|
|
return NULL;
|
|
}
|
|
|
|
if (!(chunk_vk->vk_memory = wined3d_context_vk_allocate_vram_chunk_memory(context_vk, memory_type, chunk_size)))
|
|
{
|
|
wined3d_allocator_chunk_cleanup(&chunk_vk->c);
|
|
heap_free(chunk_vk);
|
|
return NULL;
|
|
}
|
|
list_add_head(&allocator->pools[memory_type].chunks, &chunk_vk->c.entry);
|
|
|
|
return &chunk_vk->c;
|
|
}
|
|
|
|
static void wined3d_allocator_vk_destroy_chunk(struct wined3d_allocator_chunk *chunk)
|
|
{
|
|
struct wined3d_allocator_chunk_vk *chunk_vk = wined3d_allocator_chunk_vk(chunk);
|
|
const struct wined3d_vk_info *vk_info;
|
|
struct wined3d_device_vk *device_vk;
|
|
|
|
TRACE("chunk %p.\n", chunk);
|
|
|
|
device_vk = CONTAINING_RECORD(chunk_vk->c.allocator, struct wined3d_device_vk, allocator);
|
|
vk_info = &device_vk->vk_info;
|
|
|
|
if (chunk_vk->c.map_ptr)
|
|
VK_CALL(vkUnmapMemory(device_vk->vk_device, chunk_vk->vk_memory));
|
|
VK_CALL(vkFreeMemory(device_vk->vk_device, chunk_vk->vk_memory, NULL));
|
|
TRACE("Freed memory 0x%s.\n", wine_dbgstr_longlong(chunk_vk->vk_memory));
|
|
wined3d_allocator_chunk_cleanup(&chunk_vk->c);
|
|
heap_free(chunk_vk);
|
|
}
|
|
|
|
static const struct wined3d_allocator_ops wined3d_allocator_vk_ops =
|
|
{
|
|
.allocator_create_chunk = wined3d_allocator_vk_create_chunk,
|
|
.allocator_destroy_chunk = wined3d_allocator_vk_destroy_chunk,
|
|
};
|
|
|
|
static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wined3d_adapter *adapter,
|
|
enum wined3d_device_type device_type, HWND focus_window, unsigned int flags, BYTE surface_alignment,
|
|
const enum wined3d_feature_level *levels, unsigned int level_count,
|
|
struct wined3d_device_parent *device_parent, struct wined3d_device **device)
|
|
{
|
|
const struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk_const(adapter);
|
|
const struct wined3d_vk_info *vk_info = &adapter_vk->vk_info;
|
|
static const float priorities[] = {1.0f};
|
|
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;
|
|
VkResult vr;
|
|
HRESULT hr;
|
|
|
|
if (!(device_vk = heap_alloc_zero(sizeof(*device_vk))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = wined3d_select_vulkan_queue_family(adapter_vk, &queue_family_index)))
|
|
goto fail;
|
|
|
|
physical_device = adapter_vk->physical_device;
|
|
|
|
VK_CALL(vkGetPhysicalDeviceFeatures(physical_device, &features));
|
|
wined3d_disable_vulkan_features(&features);
|
|
|
|
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queue_info.pNext = NULL;
|
|
queue_info.flags = 0;
|
|
queue_info.queueFamilyIndex = queue_family_index;
|
|
queue_info.queueCount = ARRAY_SIZE(priorities);
|
|
queue_info.pQueuePriorities = priorities;
|
|
|
|
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
device_info.pNext = NULL;
|
|
device_info.flags = 0;
|
|
device_info.queueCreateInfoCount = 1;
|
|
device_info.pQueueCreateInfos = &queue_info;
|
|
device_info.enabledLayerCount = 0;
|
|
device_info.ppEnabledLayerNames = NULL;
|
|
device_info.enabledExtensionCount = 0;
|
|
device_info.ppEnabledExtensionNames = NULL;
|
|
device_info.pEnabledFeatures = &features;
|
|
|
|
if ((vr = VK_CALL(vkCreateDevice(physical_device, &device_info, NULL, &vk_device))) < 0)
|
|
{
|
|
WARN("Failed to create Vulkan device, vr %s.\n", wined3d_debug_vkresult(vr));
|
|
vk_device = VK_NULL_HANDLE;
|
|
hr = hresult_from_vk_result(vr);
|
|
goto fail;
|
|
}
|
|
|
|
device_vk->vk_device = vk_device;
|
|
VK_CALL(vkGetDeviceQueue(vk_device, queue_family_index, 0, &device_vk->vk_queue));
|
|
device_vk->vk_queue_family_index = queue_family_index;
|
|
|
|
device_vk->vk_info = *vk_info;
|
|
#define LOAD_DEVICE_PFN(name) \
|
|
if (!(device_vk->vk_info.vk_ops.name = (void *)VK_CALL(vkGetDeviceProcAddr(vk_device, #name)))) \
|
|
{ \
|
|
WARN("Could not get device proc addr for '" #name "'.\n"); \
|
|
hr = E_FAIL; \
|
|
goto fail; \
|
|
}
|
|
#define VK_DEVICE_PFN LOAD_DEVICE_PFN
|
|
VK_DEVICE_FUNCS()
|
|
#undef VK_DEVICE_PFN
|
|
|
|
if (!wined3d_allocator_init(&device_vk->allocator,
|
|
adapter_vk->memory_properties.memoryTypeCount, &wined3d_allocator_vk_ops))
|
|
{
|
|
WARN("Failed to initialise allocator.\n");
|
|
hr = E_FAIL;
|
|
goto fail;
|
|
}
|
|
|
|
if (FAILED(hr = wined3d_device_init(&device_vk->d, wined3d, adapter->ordinal, device_type,
|
|
focus_window, flags, surface_alignment, levels, level_count, device_parent)))
|
|
{
|
|
WARN("Failed to initialize device, hr %#x.\n", hr);
|
|
wined3d_allocator_cleanup(&device_vk->allocator);
|
|
goto fail;
|
|
}
|
|
|
|
*device = &device_vk->d;
|
|
|
|
return WINED3D_OK;
|
|
|
|
fail:
|
|
VK_CALL(vkDestroyDevice(vk_device, NULL));
|
|
heap_free(device_vk);
|
|
return hr;
|
|
}
|
|
|
|
static void adapter_vk_destroy_device(struct wined3d_device *device)
|
|
{
|
|
struct wined3d_device_vk *device_vk = wined3d_device_vk(device);
|
|
const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
|
|
|
|
wined3d_device_cleanup(&device_vk->d);
|
|
wined3d_allocator_cleanup(&device_vk->allocator);
|
|
VK_CALL(vkDestroyDevice(device_vk->vk_device, NULL));
|
|
heap_free(device_vk);
|
|
}
|
|
|
|
struct wined3d_context *adapter_vk_acquire_context(struct wined3d_device *device,
|
|
struct wined3d_texture *texture, unsigned int sub_resource_idx)
|
|
{
|
|
TRACE("device %p, texture %p, sub_resource_idx %u.\n", device, texture, sub_resource_idx);
|
|
|
|
wined3d_from_cs(device->cs);
|
|
|
|
if (!device->context_count)
|
|
return NULL;
|
|
|
|
return &wined3d_device_vk(device)->context_vk.c;
|
|
}
|
|
|
|
void adapter_vk_release_context(struct wined3d_context *context)
|
|
{
|
|
TRACE("context %p.\n", context);
|
|
}
|
|
|
|
static void adapter_vk_get_wined3d_caps(const struct wined3d_adapter *adapter, struct wined3d_caps *caps)
|
|
{
|
|
const struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk_const(adapter);
|
|
const VkPhysicalDeviceLimits *limits = &adapter_vk->device_limits;
|
|
BOOL sampler_anisotropy = limits->maxSamplerAnisotropy > 1.0f;
|
|
|
|
caps->ddraw_caps.dds_caps |= WINEDDSCAPS_BACKBUFFER
|
|
| WINEDDSCAPS_COMPLEX
|
|
| WINEDDSCAPS_FRONTBUFFER
|
|
| WINEDDSCAPS_3DDEVICE
|
|
| WINEDDSCAPS_VIDEOMEMORY
|
|
| WINEDDSCAPS_OWNDC
|
|
| WINEDDSCAPS_LOCALVIDMEM
|
|
| WINEDDSCAPS_NONLOCALVIDMEM;
|
|
caps->ddraw_caps.caps |= WINEDDCAPS_3D;
|
|
|
|
caps->Caps2 |= WINED3DCAPS2_CANGENMIPMAP;
|
|
|
|
caps->PrimitiveMiscCaps |= WINED3DPMISCCAPS_BLENDOP
|
|
| WINED3DPMISCCAPS_INDEPENDENTWRITEMASKS
|
|
| WINED3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
|
|
| WINED3DPMISCCAPS_POSTBLENDSRGBCONVERT
|
|
| WINED3DPMISCCAPS_SEPARATEALPHABLEND;
|
|
|
|
caps->RasterCaps |= WINED3DPRASTERCAPS_MIPMAPLODBIAS;
|
|
|
|
if (sampler_anisotropy)
|
|
{
|
|
caps->RasterCaps |= WINED3DPRASTERCAPS_ANISOTROPY;
|
|
|
|
caps->TextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFANISOTROPIC
|
|
| WINED3DPTFILTERCAPS_MINFANISOTROPIC;
|
|
|
|
caps->MaxAnisotropy = limits->maxSamplerAnisotropy;
|
|
}
|
|
|
|
caps->SrcBlendCaps |= WINED3DPBLENDCAPS_BLENDFACTOR;
|
|
caps->DestBlendCaps |= WINED3DPBLENDCAPS_BLENDFACTOR
|
|
| WINED3DPBLENDCAPS_SRCALPHASAT;
|
|
|
|
caps->TextureCaps |= WINED3DPTEXTURECAPS_VOLUMEMAP
|
|
| WINED3DPTEXTURECAPS_MIPVOLUMEMAP
|
|
| WINED3DPTEXTURECAPS_VOLUMEMAP_POW2;
|
|
caps->VolumeTextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFLINEAR
|
|
| WINED3DPTFILTERCAPS_MAGFPOINT
|
|
| WINED3DPTFILTERCAPS_MINFLINEAR
|
|
| WINED3DPTFILTERCAPS_MINFPOINT
|
|
| WINED3DPTFILTERCAPS_MIPFLINEAR
|
|
| WINED3DPTFILTERCAPS_MIPFPOINT
|
|
| WINED3DPTFILTERCAPS_LINEAR
|
|
| WINED3DPTFILTERCAPS_LINEARMIPLINEAR
|
|
| WINED3DPTFILTERCAPS_LINEARMIPNEAREST
|
|
| WINED3DPTFILTERCAPS_MIPLINEAR
|
|
| WINED3DPTFILTERCAPS_MIPNEAREST
|
|
| WINED3DPTFILTERCAPS_NEAREST;
|
|
caps->VolumeTextureAddressCaps |= WINED3DPTADDRESSCAPS_INDEPENDENTUV
|
|
| WINED3DPTADDRESSCAPS_CLAMP
|
|
| WINED3DPTADDRESSCAPS_WRAP;
|
|
caps->VolumeTextureAddressCaps |= WINED3DPTADDRESSCAPS_BORDER
|
|
| WINED3DPTADDRESSCAPS_MIRROR
|
|
| WINED3DPTADDRESSCAPS_MIRRORONCE;
|
|
|
|
caps->MaxVolumeExtent = limits->maxImageDimension3D;
|
|
|
|
caps->TextureCaps |= WINED3DPTEXTURECAPS_CUBEMAP
|
|
| WINED3DPTEXTURECAPS_MIPCUBEMAP
|
|
| WINED3DPTEXTURECAPS_CUBEMAP_POW2;
|
|
caps->CubeTextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFLINEAR
|
|
| WINED3DPTFILTERCAPS_MAGFPOINT
|
|
| WINED3DPTFILTERCAPS_MINFLINEAR
|
|
| WINED3DPTFILTERCAPS_MINFPOINT
|
|
| WINED3DPTFILTERCAPS_MIPFLINEAR
|
|
| WINED3DPTFILTERCAPS_MIPFPOINT
|
|
| WINED3DPTFILTERCAPS_LINEAR
|
|
| WINED3DPTFILTERCAPS_LINEARMIPLINEAR
|
|
| WINED3DPTFILTERCAPS_LINEARMIPNEAREST
|
|
| WINED3DPTFILTERCAPS_MIPLINEAR
|
|
| WINED3DPTFILTERCAPS_MIPNEAREST
|
|
| WINED3DPTFILTERCAPS_NEAREST;
|
|
|
|
if (sampler_anisotropy)
|
|
{
|
|
caps->CubeTextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFANISOTROPIC
|
|
| WINED3DPTFILTERCAPS_MINFANISOTROPIC;
|
|
}
|
|
|
|
caps->TextureAddressCaps |= WINED3DPTADDRESSCAPS_BORDER
|
|
| WINED3DPTADDRESSCAPS_MIRROR
|
|
| WINED3DPTADDRESSCAPS_MIRRORONCE;
|
|
|
|
caps->StencilCaps |= WINED3DSTENCILCAPS_DECR
|
|
| WINED3DSTENCILCAPS_INCR
|
|
| WINED3DSTENCILCAPS_TWOSIDED;
|
|
|
|
caps->DeclTypes |= WINED3DDTCAPS_FLOAT16_2 | WINED3DDTCAPS_FLOAT16_4;
|
|
|
|
caps->MaxPixelShader30InstructionSlots = WINED3DMAX30SHADERINSTRUCTIONS;
|
|
caps->MaxVertexShader30InstructionSlots = WINED3DMAX30SHADERINSTRUCTIONS;
|
|
caps->PS20Caps.temp_count = WINED3DPS20_MAX_NUMTEMPS;
|
|
caps->VS20Caps.temp_count = WINED3DVS20_MAX_NUMTEMPS;
|
|
}
|
|
|
|
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 HRESULT adapter_vk_init_3d(struct wined3d_device *device)
|
|
{
|
|
struct wined3d_context_vk *context_vk;
|
|
struct wined3d_device_vk *device_vk;
|
|
HRESULT hr;
|
|
|
|
TRACE("device %p.\n", device);
|
|
|
|
device_vk = wined3d_device_vk(device);
|
|
context_vk = &device_vk->context_vk;
|
|
if (FAILED(hr = wined3d_context_vk_init(context_vk, device->swapchains[0])))
|
|
{
|
|
WARN("Failed to initialise context.\n");
|
|
return hr;
|
|
}
|
|
|
|
if (FAILED(hr = device->shader_backend->shader_alloc_private(device,
|
|
device->adapter->vertex_pipe, device->adapter->fragment_pipe)))
|
|
{
|
|
ERR("Failed to allocate shader private data, hr %#x.\n", hr);
|
|
wined3d_context_vk_cleanup(context_vk);
|
|
return hr;
|
|
}
|
|
|
|
if (!device_context_add(device, &context_vk->c))
|
|
{
|
|
ERR("Failed to add the newly created context to the context list.\n");
|
|
device->shader_backend->shader_free_private(device, NULL);
|
|
wined3d_context_vk_cleanup(context_vk);
|
|
return E_FAIL;
|
|
}
|
|
|
|
TRACE("Initialised context %p.\n", context_vk);
|
|
|
|
if (!(device_vk->d.blitter = wined3d_cpu_blitter_create()))
|
|
{
|
|
ERR("Failed to create CPU blitter.\n");
|
|
device_context_remove(device, &context_vk->c);
|
|
device->shader_backend->shader_free_private(device, NULL);
|
|
wined3d_context_vk_cleanup(context_vk);
|
|
return E_FAIL;
|
|
}
|
|
|
|
wined3d_device_create_default_samplers(device, &context_vk->c);
|
|
|
|
return WINED3D_OK;
|
|
}
|
|
|
|
static void adapter_vk_uninit_3d_cs(void *object)
|
|
{
|
|
struct wined3d_device_vk *device_vk = object;
|
|
struct wined3d_context_vk *context_vk;
|
|
struct wined3d_device *device;
|
|
struct wined3d_shader *shader;
|
|
|
|
TRACE("device_vk %p.\n", device_vk);
|
|
|
|
context_vk = &device_vk->context_vk;
|
|
device = &device_vk->d;
|
|
|
|
LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
|
|
{
|
|
device->shader_backend->shader_destroy(shader);
|
|
}
|
|
|
|
device->blitter->ops->blitter_destroy(device->blitter, NULL);
|
|
device->shader_backend->shader_free_private(device, &context_vk->c);
|
|
wined3d_device_destroy_default_samplers(device, &context_vk->c);
|
|
}
|
|
|
|
static void adapter_vk_uninit_3d(struct wined3d_device *device)
|
|
{
|
|
struct wined3d_context_vk *context_vk;
|
|
struct wined3d_device_vk *device_vk;
|
|
|
|
TRACE("device %p.\n", device);
|
|
|
|
device_vk = wined3d_device_vk(device);
|
|
context_vk = &device_vk->context_vk;
|
|
|
|
wined3d_cs_destroy_object(device->cs, adapter_vk_uninit_3d_cs, device_vk);
|
|
wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
|
|
|
|
device_context_remove(device, &context_vk->c);
|
|
wined3d_context_vk_cleanup(context_vk);
|
|
}
|
|
|
|
static void *wined3d_bo_vk_map(struct wined3d_bo_vk *bo, struct wined3d_context_vk *context_vk)
|
|
{
|
|
const struct wined3d_vk_info *vk_info;
|
|
struct wined3d_device_vk *device_vk;
|
|
void *map_ptr;
|
|
VkResult vr;
|
|
|
|
vk_info = context_vk->vk_info;
|
|
device_vk = wined3d_device_vk(context_vk->c.device);
|
|
|
|
if (bo->memory)
|
|
{
|
|
struct wined3d_allocator_chunk_vk *chunk_vk = wined3d_allocator_chunk_vk(bo->memory->chunk);
|
|
|
|
if (!(map_ptr = wined3d_allocator_chunk_vk_map(chunk_vk, context_vk)))
|
|
{
|
|
ERR("Failed to map chunk.\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
else if ((vr = VK_CALL(vkMapMemory(device_vk->vk_device, bo->vk_memory, 0, VK_WHOLE_SIZE, 0, &map_ptr))) < 0)
|
|
{
|
|
ERR("Failed to map memory, vr %s.\n", wined3d_debug_vkresult(vr));
|
|
return NULL;
|
|
}
|
|
|
|
return map_ptr;
|
|
}
|
|
|
|
static void wined3d_bo_vk_unmap(struct wined3d_bo_vk *bo, struct wined3d_context_vk *context_vk)
|
|
{
|
|
const struct wined3d_vk_info *vk_info;
|
|
struct wined3d_device_vk *device_vk;
|
|
|
|
vk_info = context_vk->vk_info;
|
|
device_vk = wined3d_device_vk(context_vk->c.device);
|
|
|
|
if (bo->memory)
|
|
wined3d_allocator_chunk_vk_unmap(wined3d_allocator_chunk_vk(bo->memory->chunk), context_vk);
|
|
else
|
|
VK_CALL(vkUnmapMemory(device_vk->vk_device, bo->vk_memory));
|
|
}
|
|
|
|
static void *adapter_vk_map_bo_address(struct wined3d_context *context,
|
|
const struct wined3d_bo_address *data, size_t size, uint32_t bind_flags, uint32_t map_flags)
|
|
{
|
|
struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
|
|
const struct wined3d_vk_info *vk_info;
|
|
struct wined3d_device_vk *device_vk;
|
|
VkCommandBuffer vk_command_buffer;
|
|
VkBufferMemoryBarrier vk_barrier;
|
|
VkMappedMemoryRange range;
|
|
struct wined3d_bo_vk *bo;
|
|
void *map_ptr;
|
|
|
|
if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
|
|
return data->addr;
|
|
|
|
vk_info = context_vk->vk_info;
|
|
device_vk = wined3d_device_vk(context->device);
|
|
|
|
if (map_flags & WINED3D_MAP_NOOVERWRITE)
|
|
goto map;
|
|
|
|
if (map_flags & WINED3D_MAP_READ)
|
|
{
|
|
if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
|
|
{
|
|
ERR("Failed to get command buffer.\n");
|
|
return NULL;
|
|
}
|
|
|
|
vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
|
vk_barrier.pNext = NULL;
|
|
vk_barrier.srcAccessMask = vk_access_mask_from_bind_flags(bind_flags);
|
|
vk_barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
|
|
vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
vk_barrier.buffer = bo->vk_buffer;
|
|
vk_barrier.offset = (uintptr_t)data->addr;
|
|
vk_barrier.size = size;
|
|
VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
|
|
|
|
if (!(bo->memory_type & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
|
|
{
|
|
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
|
range.pNext = NULL;
|
|
range.memory = bo->vk_memory;
|
|
range.offset = bo->memory_offset + (uintptr_t)data->addr;
|
|
range.size = size;
|
|
VK_CALL(vkInvalidateMappedMemoryRanges(device_vk->vk_device, 1, &range));
|
|
}
|
|
|
|
bo->command_buffer_id = context_vk->current_command_buffer.id;
|
|
}
|
|
|
|
if (bo->command_buffer_id == context_vk->current_command_buffer.id)
|
|
wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
|
|
wined3d_context_vk_wait_command_buffer(context_vk, bo->command_buffer_id);
|
|
|
|
map:
|
|
if (!(map_ptr = wined3d_bo_vk_map(bo, context_vk)))
|
|
{
|
|
ERR("Failed to map bo.\n");
|
|
return NULL;
|
|
}
|
|
|
|
return (uint8_t *)map_ptr + bo->memory_offset + (uintptr_t)data->addr;
|
|
}
|
|
|
|
static void adapter_vk_unmap_bo_address(struct wined3d_context *context, const struct wined3d_bo_address *data,
|
|
uint32_t bind_flags, unsigned int range_count, const struct wined3d_range *ranges)
|
|
{
|
|
struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
|
|
const struct wined3d_vk_info *vk_info;
|
|
struct wined3d_device_vk *device_vk;
|
|
VkMappedMemoryRange range;
|
|
struct wined3d_bo_vk *bo;
|
|
unsigned int i;
|
|
|
|
if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
|
|
return;
|
|
|
|
vk_info = context_vk->vk_info;
|
|
device_vk = wined3d_device_vk(context->device);
|
|
|
|
if (!(bo->memory_type & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
|
|
{
|
|
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
|
range.pNext = NULL;
|
|
range.memory = bo->vk_memory;
|
|
|
|
for (i = 0; i < range_count; ++i)
|
|
{
|
|
range.offset = bo->memory_offset + ranges[i].offset;
|
|
range.size = ranges[i].size;
|
|
VK_CALL(vkFlushMappedMemoryRanges(device_vk->vk_device, 1, &range));
|
|
}
|
|
}
|
|
|
|
wined3d_bo_vk_unmap(bo, context_vk);
|
|
}
|
|
|
|
static void adapter_vk_copy_bo_address(struct wined3d_context *context,
|
|
const struct wined3d_bo_address *dst, uint32_t dst_bind_flags,
|
|
const struct wined3d_bo_address *src, uint32_t src_bind_flags, size_t size)
|
|
{
|
|
struct wined3d_range range;
|
|
void *dst_ptr, *src_ptr;
|
|
|
|
src_ptr = adapter_vk_map_bo_address(context, src, size, src_bind_flags, WINED3D_MAP_READ);
|
|
dst_ptr = adapter_vk_map_bo_address(context, dst, size, dst_bind_flags, WINED3D_MAP_WRITE);
|
|
|
|
memcpy(dst_ptr, src_ptr, size);
|
|
|
|
range.offset = 0;
|
|
range.size = size;
|
|
adapter_vk_unmap_bo_address(context, dst, dst_bind_flags, 1, &range);
|
|
adapter_vk_unmap_bo_address(context, src, src_bind_flags, 0, NULL);
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_swapchain(struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
|
|
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain)
|
|
{
|
|
struct wined3d_swapchain *swapchain_vk;
|
|
HRESULT hr;
|
|
|
|
TRACE("device %p, desc %p, parent %p, parent_ops %p, swapchain %p.\n",
|
|
device, desc, parent, parent_ops, swapchain);
|
|
|
|
if (!(swapchain_vk = heap_alloc_zero(sizeof(*swapchain_vk))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = wined3d_swapchain_vk_init(swapchain_vk, device, desc, parent, parent_ops)))
|
|
{
|
|
WARN("Failed to initialise swapchain, hr %#x.\n", hr);
|
|
heap_free(swapchain_vk);
|
|
return hr;
|
|
}
|
|
|
|
TRACE("Created swapchain %p.\n", swapchain_vk);
|
|
*swapchain = swapchain_vk;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void adapter_vk_destroy_swapchain(struct wined3d_swapchain *swapchain)
|
|
{
|
|
wined3d_swapchain_cleanup(swapchain);
|
|
heap_free(swapchain);
|
|
}
|
|
|
|
unsigned int wined3d_adapter_vk_get_memory_type_index(const struct wined3d_adapter_vk *adapter_vk,
|
|
uint32_t memory_type_mask, VkMemoryPropertyFlags flags)
|
|
{
|
|
const VkPhysicalDeviceMemoryProperties *memory_info = &adapter_vk->memory_properties;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < memory_info->memoryTypeCount; ++i)
|
|
{
|
|
if (!(memory_type_mask & (1u << i)))
|
|
continue;
|
|
if ((memory_info->memoryTypes[i].propertyFlags & flags) == flags)
|
|
return i;
|
|
}
|
|
|
|
return ~0u;
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_buffer(struct wined3d_device *device,
|
|
const struct wined3d_buffer_desc *desc, const struct wined3d_sub_resource_data *data,
|
|
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
|
|
{
|
|
struct wined3d_buffer_vk *buffer_vk;
|
|
HRESULT hr;
|
|
|
|
TRACE("device %p, desc %p, data %p, parent %p, parent_ops %p, buffer %p.\n",
|
|
device, desc, data, parent, parent_ops, buffer);
|
|
|
|
if (!(buffer_vk = heap_alloc_zero(sizeof(*buffer_vk))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = wined3d_buffer_vk_init(buffer_vk, device, desc, data, parent, parent_ops)))
|
|
{
|
|
WARN("Failed to initialise buffer, hr %#x.\n", hr);
|
|
heap_free(buffer_vk);
|
|
return hr;
|
|
}
|
|
|
|
TRACE("Created buffer %p.\n", buffer_vk);
|
|
*buffer = &buffer_vk->b;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void adapter_vk_destroy_buffer(struct wined3d_buffer *buffer)
|
|
{
|
|
struct wined3d_buffer_vk *buffer_vk = wined3d_buffer_vk(buffer);
|
|
struct wined3d_device *device = buffer_vk->b.resource.device;
|
|
unsigned int swapchain_count = device->swapchain_count;
|
|
|
|
TRACE("buffer_vk %p.\n", buffer_vk);
|
|
|
|
/* Take a reference to the device, in case releasing the buffer would
|
|
* cause the device to be destroyed. However, swapchain resources don't
|
|
* take a reference to the device, and we wouldn't want to increment the
|
|
* refcount on a device that's in the process of being destroyed. */
|
|
if (swapchain_count)
|
|
wined3d_device_incref(device);
|
|
wined3d_buffer_cleanup(&buffer_vk->b);
|
|
wined3d_cs_destroy_object(device->cs, heap_free, buffer_vk);
|
|
if (swapchain_count)
|
|
wined3d_device_decref(device);
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_texture(struct wined3d_device *device,
|
|
const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
|
|
uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
|
|
{
|
|
struct wined3d_texture_vk *texture_vk;
|
|
HRESULT hr;
|
|
|
|
TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, parent %p, parent_ops %p, texture %p.\n",
|
|
device, desc, layer_count, level_count, flags, parent, parent_ops, texture);
|
|
|
|
if (!(texture_vk = wined3d_texture_allocate_object_memory(sizeof(*texture_vk), level_count, layer_count)))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = wined3d_texture_vk_init(texture_vk, device, desc,
|
|
layer_count, level_count, flags, parent, parent_ops)))
|
|
{
|
|
WARN("Failed to initialise texture, hr %#x.\n", hr);
|
|
heap_free(texture_vk);
|
|
return hr;
|
|
}
|
|
|
|
TRACE("Created texture %p.\n", texture_vk);
|
|
*texture = &texture_vk->t;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void adapter_vk_destroy_texture(struct wined3d_texture *texture)
|
|
{
|
|
struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(texture);
|
|
struct wined3d_device *device = texture_vk->t.resource.device;
|
|
unsigned int swapchain_count = device->swapchain_count;
|
|
|
|
TRACE("texture_vk %p.\n", texture_vk);
|
|
|
|
/* Take a reference to the device, in case releasing the texture would
|
|
* cause the device to be destroyed. However, swapchain resources don't
|
|
* take a reference to the device, and we wouldn't want to increment the
|
|
* refcount on a device that's in the process of being destroyed. */
|
|
if (swapchain_count)
|
|
wined3d_device_incref(device);
|
|
|
|
wined3d_texture_sub_resources_destroyed(texture);
|
|
texture->resource.parent_ops->wined3d_object_destroyed(texture->resource.parent);
|
|
|
|
wined3d_texture_cleanup(&texture_vk->t);
|
|
wined3d_cs_destroy_object(device->cs, heap_free, texture_vk);
|
|
|
|
if (swapchain_count)
|
|
wined3d_device_decref(device);
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_rendertarget_view(const struct wined3d_view_desc *desc,
|
|
struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
struct wined3d_rendertarget_view **view)
|
|
{
|
|
struct wined3d_rendertarget_view_vk *view_vk;
|
|
HRESULT hr;
|
|
|
|
TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n",
|
|
wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view);
|
|
|
|
if (!(view_vk = heap_alloc_zero(sizeof(*view_vk))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = wined3d_rendertarget_view_vk_init(view_vk, desc, resource, parent, parent_ops)))
|
|
{
|
|
WARN("Failed to initialise view, hr %#x.\n", hr);
|
|
heap_free(view_vk);
|
|
return hr;
|
|
}
|
|
|
|
TRACE("Created render target view %p.\n", view_vk);
|
|
*view = &view_vk->v;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void adapter_vk_destroy_rendertarget_view(struct wined3d_rendertarget_view *view)
|
|
{
|
|
struct wined3d_rendertarget_view_vk *view_vk = wined3d_rendertarget_view_vk(view);
|
|
struct wined3d_device *device = view_vk->v.resource->device;
|
|
unsigned int swapchain_count = device->swapchain_count;
|
|
|
|
TRACE("view_vk %p.\n", view_vk);
|
|
|
|
/* Take a reference to the device, in case releasing the view's resource
|
|
* would cause the device to be destroyed. However, swapchain resources
|
|
* don't take a reference to the device, and we wouldn't want to increment
|
|
* the refcount on a device that's in the process of being destroyed. */
|
|
if (swapchain_count)
|
|
wined3d_device_incref(device);
|
|
wined3d_rendertarget_view_cleanup(&view_vk->v);
|
|
wined3d_cs_destroy_object(device->cs, heap_free, view_vk);
|
|
if (swapchain_count)
|
|
wined3d_device_decref(device);
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_shader_resource_view(const struct wined3d_view_desc *desc,
|
|
struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
struct wined3d_shader_resource_view **view)
|
|
{
|
|
struct wined3d_shader_resource_view_vk *view_vk;
|
|
HRESULT hr;
|
|
|
|
TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n",
|
|
wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view);
|
|
|
|
if (!(view_vk = heap_alloc_zero(sizeof(*view_vk))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = wined3d_shader_resource_view_vk_init(view_vk, desc, resource, parent, parent_ops)))
|
|
{
|
|
WARN("Failed to initialise view, hr %#x.\n", hr);
|
|
heap_free(view_vk);
|
|
return hr;
|
|
}
|
|
|
|
TRACE("Created shader resource view %p.\n", view_vk);
|
|
*view = &view_vk->v;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void adapter_vk_destroy_shader_resource_view(struct wined3d_shader_resource_view *view)
|
|
{
|
|
struct wined3d_shader_resource_view_vk *view_vk = wined3d_shader_resource_view_vk(view);
|
|
struct wined3d_device *device = view_vk->v.resource->device;
|
|
unsigned int swapchain_count = device->swapchain_count;
|
|
|
|
TRACE("view_vk %p.\n", view_vk);
|
|
|
|
/* Take a reference to the device, in case releasing the view's resource
|
|
* would cause the device to be destroyed. However, swapchain resources
|
|
* don't take a reference to the device, and we wouldn't want to increment
|
|
* the refcount on a device that's in the process of being destroyed. */
|
|
if (swapchain_count)
|
|
wined3d_device_incref(device);
|
|
wined3d_shader_resource_view_cleanup(&view_vk->v);
|
|
wined3d_cs_destroy_object(device->cs, heap_free, view_vk);
|
|
if (swapchain_count)
|
|
wined3d_device_decref(device);
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_unordered_access_view(const struct wined3d_view_desc *desc,
|
|
struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
struct wined3d_unordered_access_view **view)
|
|
{
|
|
struct wined3d_unordered_access_view_vk *view_vk;
|
|
HRESULT hr;
|
|
|
|
TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n",
|
|
wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view);
|
|
|
|
if (!(view_vk = heap_alloc_zero(sizeof(*view_vk))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = wined3d_unordered_access_view_vk_init(view_vk, desc, resource, parent, parent_ops)))
|
|
{
|
|
WARN("Failed to initialise view, hr %#x.\n", hr);
|
|
heap_free(view_vk);
|
|
return hr;
|
|
}
|
|
|
|
TRACE("Created unordered access view %p.\n", view_vk);
|
|
*view = &view_vk->v;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void adapter_vk_destroy_unordered_access_view(struct wined3d_unordered_access_view *view)
|
|
{
|
|
struct wined3d_unordered_access_view_vk *view_vk = wined3d_unordered_access_view_vk(view);
|
|
struct wined3d_device *device = view_vk->v.resource->device;
|
|
unsigned int swapchain_count = device->swapchain_count;
|
|
|
|
TRACE("view_vk %p.\n", view_vk);
|
|
|
|
/* Take a reference to the device, in case releasing the view's resource
|
|
* would cause the device to be destroyed. However, swapchain resources
|
|
* don't take a reference to the device, and we wouldn't want to increment
|
|
* the refcount on a device that's in the process of being destroyed. */
|
|
if (swapchain_count)
|
|
wined3d_device_incref(device);
|
|
wined3d_unordered_access_view_cleanup(&view_vk->v);
|
|
wined3d_cs_destroy_object(device->cs, heap_free, view_vk);
|
|
if (swapchain_count)
|
|
wined3d_device_decref(device);
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_sampler(struct wined3d_device *device, const struct wined3d_sampler_desc *desc,
|
|
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_sampler **sampler)
|
|
{
|
|
struct wined3d_sampler *sampler_vk;
|
|
|
|
TRACE("device %p, desc %p, parent %p, parent_ops %p, sampler %p.\n",
|
|
device, desc, parent, parent_ops, sampler);
|
|
|
|
if (!(sampler_vk = heap_alloc_zero(sizeof(*sampler_vk))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
wined3d_sampler_vk_init(sampler_vk, device, desc, parent, parent_ops);
|
|
|
|
TRACE("Created sampler %p.\n", sampler_vk);
|
|
*sampler = sampler_vk;
|
|
|
|
return WINED3D_OK;
|
|
}
|
|
|
|
static void adapter_vk_destroy_sampler(struct wined3d_sampler *sampler)
|
|
{
|
|
TRACE("sampler %p.\n", sampler);
|
|
|
|
wined3d_cs_destroy_object(sampler->device->cs, heap_free, sampler);
|
|
}
|
|
|
|
static HRESULT adapter_vk_create_query(struct wined3d_device *device, enum wined3d_query_type type,
|
|
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
|
|
{
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
device, type, parent, parent_ops, query);
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
}
|
|
|
|
static void adapter_vk_destroy_query(struct wined3d_query *query)
|
|
{
|
|
TRACE("query %p.\n", query);
|
|
}
|
|
|
|
static void adapter_vk_flush_context(struct wined3d_context *context)
|
|
{
|
|
TRACE("context %p.\n", context);
|
|
}
|
|
|
|
void adapter_vk_clear_uav(struct wined3d_context *context,
|
|
struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value)
|
|
{
|
|
FIXME("context %p, view %p, clear_value %s.\n", context, view, debug_uvec4(clear_value));
|
|
}
|
|
|
|
static const struct wined3d_adapter_ops wined3d_adapter_vk_ops =
|
|
{
|
|
adapter_vk_destroy,
|
|
adapter_vk_create_device,
|
|
adapter_vk_destroy_device,
|
|
adapter_vk_acquire_context,
|
|
adapter_vk_release_context,
|
|
adapter_vk_get_wined3d_caps,
|
|
adapter_vk_check_format,
|
|
adapter_vk_init_3d,
|
|
adapter_vk_uninit_3d,
|
|
adapter_vk_map_bo_address,
|
|
adapter_vk_unmap_bo_address,
|
|
adapter_vk_copy_bo_address,
|
|
adapter_vk_create_swapchain,
|
|
adapter_vk_destroy_swapchain,
|
|
adapter_vk_create_buffer,
|
|
adapter_vk_destroy_buffer,
|
|
adapter_vk_create_texture,
|
|
adapter_vk_destroy_texture,
|
|
adapter_vk_create_rendertarget_view,
|
|
adapter_vk_destroy_rendertarget_view,
|
|
adapter_vk_create_shader_resource_view,
|
|
adapter_vk_destroy_shader_resource_view,
|
|
adapter_vk_create_unordered_access_view,
|
|
adapter_vk_destroy_unordered_access_view,
|
|
adapter_vk_create_sampler,
|
|
adapter_vk_destroy_sampler,
|
|
adapter_vk_create_query,
|
|
adapter_vk_destroy_query,
|
|
adapter_vk_flush_context,
|
|
adapter_vk_clear_uav,
|
|
};
|
|
|
|
static unsigned int wined3d_get_wine_vk_version(void)
|
|
{
|
|
const char *ptr = PACKAGE_VERSION;
|
|
int major, minor;
|
|
|
|
major = atoi(ptr);
|
|
|
|
while (isdigit(*ptr))
|
|
++ptr;
|
|
if (*ptr == '.')
|
|
++ptr;
|
|
|
|
minor = atoi(ptr);
|
|
|
|
return VK_MAKE_VERSION(major, minor, 0);
|
|
}
|
|
|
|
static const struct
|
|
{
|
|
const char *name;
|
|
unsigned int core_since_version;
|
|
BOOL required;
|
|
}
|
|
vulkan_instance_extensions[] =
|
|
{
|
|
{VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_API_VERSION_1_1, FALSE},
|
|
};
|
|
|
|
static BOOL enable_vulkan_instance_extensions(uint32_t *extension_count,
|
|
const char *enabled_extensions[], const struct wined3d_vk_info *vk_info)
|
|
{
|
|
PFN_vkEnumerateInstanceExtensionProperties pfn_vkEnumerateInstanceExtensionProperties;
|
|
VkExtensionProperties *extensions = NULL;
|
|
BOOL success = FALSE, found;
|
|
unsigned int i, j, count;
|
|
VkResult vr;
|
|
|
|
*extension_count = 0;
|
|
|
|
if (!(pfn_vkEnumerateInstanceExtensionProperties
|
|
= (void *)VK_CALL(vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"))))
|
|
{
|
|
WARN("Failed to get 'vkEnumerateInstanceExtensionProperties'.\n");
|
|
goto done;
|
|
}
|
|
|
|
if ((vr = pfn_vkEnumerateInstanceExtensionProperties(NULL, &count, NULL)) < 0)
|
|
{
|
|
WARN("Failed to count instance extensions, vr %s.\n", wined3d_debug_vkresult(vr));
|
|
goto done;
|
|
}
|
|
if (!(extensions = heap_calloc(count, sizeof(*extensions))))
|
|
{
|
|
WARN("Out of memory.\n");
|
|
goto done;
|
|
}
|
|
if ((vr = pfn_vkEnumerateInstanceExtensionProperties(NULL, &count, extensions)) < 0)
|
|
{
|
|
WARN("Failed to enumerate extensions, vr %s.\n", wined3d_debug_vkresult(vr));
|
|
goto done;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vulkan_instance_extensions); ++i)
|
|
{
|
|
if (vulkan_instance_extensions[i].core_since_version <= vk_info->api_version)
|
|
continue;
|
|
|
|
for (j = 0, found = FALSE; j < count; ++j)
|
|
{
|
|
if (!strcmp(extensions[j].extensionName, vulkan_instance_extensions[i].name))
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
TRACE("Enabling instance extension '%s'.\n", vulkan_instance_extensions[i].name);
|
|
enabled_extensions[(*extension_count)++] = vulkan_instance_extensions[i].name;
|
|
}
|
|
else if (!found && vulkan_instance_extensions[i].required)
|
|
{
|
|
WARN("Required extension '%s' is not available.\n", vulkan_instance_extensions[i].name);
|
|
goto done;
|
|
}
|
|
}
|
|
success = TRUE;
|
|
|
|
done:
|
|
heap_free(extensions);
|
|
return success;
|
|
}
|
|
|
|
static BOOL wined3d_init_vulkan(struct wined3d_vk_info *vk_info)
|
|
{
|
|
const char *enabled_instance_extensions[ARRAY_SIZE(vulkan_instance_extensions)];
|
|
PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion;
|
|
struct vulkan_ops *vk_ops = &vk_info->vk_ops;
|
|
VkInstance instance = VK_NULL_HANDLE;
|
|
VkInstanceCreateInfo instance_info;
|
|
VkApplicationInfo app_info;
|
|
uint32_t api_version = 0;
|
|
char app_name[MAX_PATH];
|
|
VkResult vr;
|
|
|
|
if (!wined3d_load_vulkan(vk_info))
|
|
return FALSE;
|
|
|
|
if (!(vk_ops->vkCreateInstance = (void *)VK_CALL(vkGetInstanceProcAddr(NULL, "vkCreateInstance"))))
|
|
{
|
|
ERR("Failed to get 'vkCreateInstance'.\n");
|
|
goto fail;
|
|
}
|
|
|
|
vk_info->api_version = VK_API_VERSION_1_0;
|
|
if ((pfn_vkEnumerateInstanceVersion = (void *)VK_CALL(vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion")))
|
|
&& pfn_vkEnumerateInstanceVersion(&api_version) == VK_SUCCESS)
|
|
{
|
|
TRACE("Vulkan instance API version %s.\n", debug_vk_version(api_version));
|
|
|
|
if (api_version >= VK_API_VERSION_1_1)
|
|
vk_info->api_version = VK_API_VERSION_1_1;
|
|
}
|
|
|
|
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_info->api_version;
|
|
|
|
memset(&instance_info, 0, sizeof(instance_info));
|
|
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
instance_info.pApplicationInfo = &app_info;
|
|
instance_info.ppEnabledExtensionNames = enabled_instance_extensions;
|
|
if (!enable_vulkan_instance_extensions(&instance_info.enabledExtensionCount, enabled_instance_extensions, vk_info))
|
|
goto fail;
|
|
|
|
if ((vr = VK_CALL(vkCreateInstance(&instance_info, NULL, &instance))) < 0)
|
|
{
|
|
WARN("Failed to create Vulkan instance, vr %s.\n", wined3d_debug_vkresult(vr));
|
|
goto fail;
|
|
}
|
|
|
|
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"); \
|
|
goto fail; \
|
|
}
|
|
#define LOAD_INSTANCE_OPT_PFN(name) \
|
|
vk_ops->name = (void *)VK_CALL(vkGetInstanceProcAddr(instance, #name));
|
|
#define VK_INSTANCE_PFN LOAD_INSTANCE_PFN
|
|
#define VK_INSTANCE_EXT_PFN LOAD_INSTANCE_OPT_PFN
|
|
#define VK_DEVICE_PFN LOAD_INSTANCE_PFN
|
|
VK_INSTANCE_FUNCS()
|
|
VK_DEVICE_FUNCS()
|
|
#undef VK_INSTANCE_PFN
|
|
#undef VK_INSTANCE_EXT_PFN
|
|
#undef VK_DEVICE_PFN
|
|
|
|
#define MAP_INSTANCE_FUNCTION(core_pfn, ext_pfn) \
|
|
if (!vk_ops->core_pfn) \
|
|
vk_ops->core_pfn = (void *)VK_CALL(vkGetInstanceProcAddr(instance, #ext_pfn));
|
|
MAP_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties2, vkGetPhysicalDeviceProperties2KHR)
|
|
#undef MAP_INSTANCE_FUNCTION
|
|
|
|
vk_info->instance = instance;
|
|
|
|
return TRUE;
|
|
|
|
fail:
|
|
if (vk_ops->vkDestroyInstance)
|
|
VK_CALL(vkDestroyInstance(instance, NULL));
|
|
wined3d_unload_vulkan(vk_info);
|
|
return FALSE;
|
|
}
|
|
|
|
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 %s.\n", wined3d_debug_vkresult(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 %s.\n", wined3d_debug_vkresult(vr));
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
return physical_devices[0];
|
|
}
|
|
|
|
static enum wined3d_display_driver guess_display_driver(enum wined3d_pci_vendor vendor)
|
|
{
|
|
switch (vendor)
|
|
{
|
|
case HW_VENDOR_AMD: return DRIVER_AMD_RX;
|
|
case HW_VENDOR_INTEL: return DRIVER_INTEL_HD4000;
|
|
case HW_VENDOR_NVIDIA: return DRIVER_NVIDIA_GEFORCE8;
|
|
default: return DRIVER_WINE;
|
|
}
|
|
}
|
|
|
|
static void adapter_vk_init_driver_info(struct wined3d_adapter_vk *adapter_vk,
|
|
const VkPhysicalDeviceProperties *properties)
|
|
{
|
|
const VkPhysicalDeviceMemoryProperties *memory_properties = &adapter_vk->memory_properties;
|
|
const struct wined3d_gpu_description *gpu_description;
|
|
struct wined3d_gpu_description description;
|
|
UINT64 vram_bytes, sysmem_bytes;
|
|
const VkMemoryHeap *heap;
|
|
unsigned int i;
|
|
|
|
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: %s.\n", debug_vk_version(properties->apiVersion));
|
|
|
|
for (i = 0, vram_bytes = 0, sysmem_bytes = 0; i < memory_properties->memoryHeapCount; ++i)
|
|
{
|
|
heap = &memory_properties->memoryHeaps[i];
|
|
TRACE("Memory heap [%u]: flags %#x, size 0x%s.\n",
|
|
i, heap->flags, wine_dbgstr_longlong(heap->size));
|
|
if (heap->flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
|
|
vram_bytes += heap->size;
|
|
else
|
|
sysmem_bytes += heap->size;
|
|
}
|
|
TRACE("Total device memory: 0x%s.\n", wine_dbgstr_longlong(vram_bytes));
|
|
TRACE("Total shared system memory: 0x%s.\n", wine_dbgstr_longlong(sysmem_bytes));
|
|
|
|
if (!(gpu_description = wined3d_get_user_override_gpu_description(properties->vendorID, properties->deviceID)))
|
|
gpu_description = wined3d_get_gpu_description(properties->vendorID, properties->deviceID);
|
|
|
|
if (!gpu_description)
|
|
{
|
|
FIXME("Failed to retrieve GPU description for device %s %04x:%04x.\n",
|
|
debugstr_a(properties->deviceName), properties->vendorID, properties->deviceID);
|
|
|
|
description.vendor = properties->vendorID;
|
|
description.device = properties->deviceID;
|
|
description.description = properties->deviceName;
|
|
description.driver = guess_display_driver(properties->vendorID);
|
|
description.vidmem = vram_bytes;
|
|
|
|
gpu_description = &description;
|
|
}
|
|
|
|
wined3d_driver_info_init(&adapter_vk->a.driver_info, gpu_description, vram_bytes, sysmem_bytes);
|
|
}
|
|
|
|
static void wined3d_adapter_vk_init_d3d_info(struct wined3d_adapter *adapter, uint32_t wined3d_creation_flags)
|
|
{
|
|
struct wined3d_d3d_info *d3d_info = &adapter->d3d_info;
|
|
|
|
d3d_info->wined3d_creation_flags = wined3d_creation_flags;
|
|
|
|
d3d_info->texture_swizzle = TRUE;
|
|
|
|
d3d_info->multisample_draw_location = WINED3D_LOCATION_TEXTURE_RGB;
|
|
}
|
|
|
|
static BOOL wined3d_adapter_vk_init(struct wined3d_adapter_vk *adapter_vk,
|
|
unsigned int ordinal, unsigned int wined3d_creation_flags)
|
|
{
|
|
struct wined3d_vk_info *vk_info = &adapter_vk->vk_info;
|
|
struct wined3d_adapter *adapter = &adapter_vk->a;
|
|
VkPhysicalDeviceIDProperties id_properties;
|
|
VkPhysicalDeviceProperties2 properties2;
|
|
|
|
TRACE("adapter_vk %p, ordinal %u, wined3d_creation_flags %#x.\n",
|
|
adapter_vk, ordinal, wined3d_creation_flags);
|
|
|
|
if (!wined3d_adapter_init(adapter, ordinal, &wined3d_adapter_vk_ops))
|
|
return FALSE;
|
|
|
|
if (!wined3d_init_vulkan(vk_info))
|
|
{
|
|
WARN("Failed to initialize Vulkan.\n");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(adapter_vk->physical_device = get_vulkan_physical_device(vk_info)))
|
|
goto fail_vulkan;
|
|
|
|
memset(&id_properties, 0, sizeof(id_properties));
|
|
id_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
|
|
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
|
properties2.pNext = &id_properties;
|
|
|
|
if (vk_info->vk_ops.vkGetPhysicalDeviceProperties2)
|
|
VK_CALL(vkGetPhysicalDeviceProperties2(adapter_vk->physical_device, &properties2));
|
|
else
|
|
VK_CALL(vkGetPhysicalDeviceProperties(adapter_vk->physical_device, &properties2.properties));
|
|
adapter_vk->device_limits = properties2.properties.limits;
|
|
|
|
VK_CALL(vkGetPhysicalDeviceMemoryProperties(adapter_vk->physical_device, &adapter_vk->memory_properties));
|
|
|
|
adapter_vk_init_driver_info(adapter_vk, &properties2.properties);
|
|
adapter->vram_bytes_used = 0;
|
|
TRACE("Emulating 0x%s bytes of video ram.\n", wine_dbgstr_longlong(adapter->driver_info.vram_bytes));
|
|
|
|
memcpy(&adapter->driver_uuid, id_properties.driverUUID, sizeof(adapter->driver_uuid));
|
|
memcpy(&adapter->device_uuid, id_properties.deviceUUID, sizeof(adapter->device_uuid));
|
|
|
|
if (!wined3d_adapter_vk_init_format_info(adapter_vk, vk_info))
|
|
goto fail_vulkan;
|
|
|
|
adapter->vertex_pipe = &none_vertex_pipe;
|
|
adapter->fragment_pipe = &none_fragment_pipe;
|
|
adapter->shader_backend = &none_shader_backend;
|
|
|
|
wined3d_adapter_vk_init_d3d_info(adapter, wined3d_creation_flags);
|
|
|
|
return TRUE;
|
|
|
|
fail_vulkan:
|
|
VK_CALL(vkDestroyInstance(vk_info->instance, NULL));
|
|
wined3d_unload_vulkan(vk_info);
|
|
fail:
|
|
wined3d_adapter_cleanup(adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
}
|