vulkan-wsi-layer/layer/layer.cpp
Matteo Franchin 9b698b4a2f Initial sources for the vulkan-wsi-layer project
This commit adds the initial sources for the vulkan-wsi-layer project:
a Vulkan layer which implements some of the Vulkan window system
integration extensions such as VK_KHR_swapchain.
The layer is designed to be GPU vendor agnostic when used as part of the
Vulkan ICD/loader architecture.

The project currently implements support for VK_EXT_headless_surface and
its dependencies. We hope to extend support for further platforms such
as Wayland and direct-to-display rendering in the future.

This initial commit collects contributions from different individuals
employed by Arm.

More information on the project (building instructions, how to
contribute, etc.) can be found on the README.md file at the top of the
project tree.

Signed-off-by: Matteo Franchin <matteo.franchin@arm.com>
2019-05-31 15:48:05 +01:00

304 lines
12 KiB
C++

/*
* Copyright (c) 2016-2019 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <cassert>
#include <cstdio>
#include <cstring>
#include <vulkan/vk_layer.h>
#include <wsi/surface_properties.hpp>
#include "private_data.hpp"
#include "surface_api.hpp"
#include "swapchain_api.hpp"
#define VK_LAYER_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)
namespace layer
{
static const VkLayerProperties global_layer = {
"VK_LAYER_window_system_integration",
VK_LAYER_API_VERSION,
1,
"Window system integration layer",
};
static const VkExtensionProperties device_extension[] = { { VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_SWAPCHAIN_SPEC_VERSION } };
static const VkExtensionProperties instance_extension[] = { { VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_SURFACE_SPEC_VERSION } };
VKAPI_ATTR VkResult extension_properties(const uint32_t count, const VkExtensionProperties *layer_ext, uint32_t *pCount,
VkExtensionProperties *pProp)
{
uint32_t size;
if (pProp == NULL || layer_ext == NULL)
{
*pCount = count;
return VK_SUCCESS;
}
size = *pCount < count ? *pCount : count;
memcpy(pProp, layer_ext, size * sizeof(VkLayerProperties));
*pCount = size;
if (size < count)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
VKAPI_ATTR VkResult layer_properties(const uint32_t count, const VkLayerProperties *layer_prop, uint32_t *pCount,
VkLayerProperties *pProp)
{
uint32_t size;
if (pProp == NULL || layer_prop == NULL)
{
*pCount = count;
return VK_SUCCESS;
}
size = *pCount < count ? *pCount : count;
memcpy(pProp, layer_prop, size * sizeof(VkLayerProperties));
*pCount = size;
if (size < count)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
VKAPI_ATTR VkLayerInstanceCreateInfo *get_chain_info(const VkInstanceCreateInfo *pCreateInfo, VkLayerFunction func)
{
VkLayerInstanceCreateInfo *chain_info = (VkLayerInstanceCreateInfo *)pCreateInfo->pNext;
while (chain_info &&
!(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && chain_info->function == func))
{
chain_info = (VkLayerInstanceCreateInfo *)chain_info->pNext;
}
return chain_info;
}
VKAPI_ATTR VkLayerDeviceCreateInfo *get_chain_info(const VkDeviceCreateInfo *pCreateInfo, VkLayerFunction func)
{
VkLayerDeviceCreateInfo *chain_info = (VkLayerDeviceCreateInfo *)pCreateInfo->pNext;
while (chain_info &&
!(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO && chain_info->function == func))
{
chain_info = (VkLayerDeviceCreateInfo *)chain_info->pNext;
}
return chain_info;
}
/*
* This is where we get our initialisation and construct our dispatch table. All layers must implement the function.
* If you wish to intercept any device functions at all you need to implement vkCreateDevice.
*/
VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
VkInstance *pInstance)
{
VkLayerInstanceCreateInfo *layerCreateInfo = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
PFN_vkSetInstanceLoaderData loader_callback =
get_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK)->u.pfnSetInstanceLoaderData;
if (nullptr == layerCreateInfo || nullptr == layerCreateInfo->u.pLayerInfo)
{
return VK_ERROR_INITIALIZATION_FAILED;
}
/* Retrieve the vkGetInstanceProcAddr and the vkCreateInstance function pointers for the next layer in the chain. */
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = layerCreateInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(nullptr, "vkCreateInstance");
if (nullptr == fpCreateInstance)
{
return VK_ERROR_INITIALIZATION_FAILED;
}
/* Advance the link info for the next element on the chain. */
layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext;
/* Now call create instance on the chain further down the list. */
VkResult ret = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
instance_private_data::create(*pInstance, fpGetInstanceProcAddr, loader_callback);
return ret;
}
VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
{
VkLayerDeviceCreateInfo *layerCreateInfo = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
PFN_vkSetDeviceLoaderData loader_callback =
get_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK)->u.pfnSetDeviceLoaderData;
if (nullptr == layerCreateInfo || nullptr == layerCreateInfo->u.pLayerInfo)
{
return VK_ERROR_INITIALIZATION_FAILED;
}
/* Retrieve the vkGetDeviceProcAddr and the vkCreateDevice function pointers for the next layer in the chain. */
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = layerCreateInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = layerCreateInfo->u.pLayerInfo->pfnNextGetDeviceProcAddr;
PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
if (nullptr == fpCreateDevice)
{
return VK_ERROR_INITIALIZATION_FAILED;
}
/* Advance the link info for the next element on the chain. */
layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext;
/* Now call create device on the chain further down the list. */
VkResult ret = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
device_private_data::create(*pDevice, fpGetDeviceProcAddr, physicalDevice, loader_callback);
return ret;
}
} /* namespace layer */
extern "C"
{
VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL
wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName);
VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName);
/* Clean up the dispatch table for this instance. */
VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
wsi_layer_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator)
{
layer::instance_private_data::destroy(instance);
}
VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
wsi_layer_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator)
{
layer::device_private_data::destroy(device);
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
wsi_layer_vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance)
{
return layer::create_instance(pCreateInfo, pAllocator, pInstance);
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
wsi_layer_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
{
return layer::create_device(physicalDevice, pCreateInfo, pAllocator, pDevice);
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct)
{
assert(pVersionStruct);
assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
/* 2 is the minimum interface version which would utilize this function. */
assert(pVersionStruct->loaderLayerInterfaceVersion >= 2);
/* Set our requested interface version. Set to 2 for now to separate us from newer versions. */
pVersionStruct->loaderLayerInterfaceVersion = 2;
/* Fill in struct values. */
pVersionStruct->pfnGetInstanceProcAddr = &wsi_layer_vkGetInstanceProcAddr;
pVersionStruct->pfnGetDeviceProcAddr = &wsi_layer_vkGetDeviceProcAddr;
pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
return VK_SUCCESS;
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
wsi_layer_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
uint32_t *pCount, VkExtensionProperties *pProperties)
{
if (pLayerName && !strcmp(pLayerName, layer::global_layer.layerName))
return layer::extension_properties(1, layer::device_extension, pCount, pProperties);
assert(physicalDevice);
return layer::instance_private_data::get(layer::get_key(physicalDevice))
.disp.EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pCount, pProperties);
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
wsi_layer_vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
{
if (pLayerName && !strcmp(pLayerName, layer::global_layer.layerName))
return layer::extension_properties(1, layer::instance_extension, pCount, pProperties);
return VK_ERROR_LAYER_NOT_PRESENT;
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
wsi_layer_vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties)
{
return layer::layer_properties(1, &layer::global_layer, pCount, pProperties);
}
#define GET_PROC_ADDR(func) \
if (!strcmp(funcName, #func)) \
return (PFN_vkVoidFunction)&wsi_layer_##func;
VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL
wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName)
{
GET_PROC_ADDR(vkCreateSwapchainKHR);
GET_PROC_ADDR(vkDestroySwapchainKHR);
GET_PROC_ADDR(vkGetSwapchainImagesKHR);
GET_PROC_ADDR(vkAcquireNextImageKHR);
GET_PROC_ADDR(vkQueuePresentKHR);
return layer::device_private_data::get(layer::get_key(device)).disp.GetDeviceProcAddr(device, funcName);
}
VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName)
{
GET_PROC_ADDR(vkGetDeviceProcAddr);
GET_PROC_ADDR(vkGetInstanceProcAddr);
GET_PROC_ADDR(vkCreateInstance);
GET_PROC_ADDR(vkDestroyInstance);
GET_PROC_ADDR(vkCreateDevice);
GET_PROC_ADDR(vkDestroyDevice);
GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceSupportKHR);
GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
GET_PROC_ADDR(vkGetPhysicalDeviceSurfaceFormatsKHR);
GET_PROC_ADDR(vkGetPhysicalDeviceSurfacePresentModesKHR);
GET_PROC_ADDR(vkEnumerateDeviceExtensionProperties);
GET_PROC_ADDR(vkEnumerateInstanceExtensionProperties);
GET_PROC_ADDR(vkEnumerateInstanceLayerProperties);
return layer::instance_private_data::get(layer::get_key(instance)).disp.GetInstanceProcAddr(instance, funcName);
}
} /* extern "C" */