summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLionel Landwerlin <lionel.g.landwerlin@intel.com>2019-11-11 23:45:17 +0200
committerMarge Bot <eric+marge@anholt.net>2021-03-25 19:10:03 +0000
commit8b586d9ed6d78af1f689194271703b37c4367644 (patch)
tree9f2fa78047d2e5ee269e7785f4a28ca7d1929c91
parent54fe5b0482df0f066384b274796d4081c2a1968c (diff)
intel: Add null hw layer
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Acked-by: Jason Ekstrand <jason@jlekstrand.net> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/2832>
-rw-r--r--meson_options.txt2
-rw-r--r--src/intel/meson.build3
-rw-r--r--src/intel/nullhw-layer/README5
-rw-r--r--src/intel/nullhw-layer/VkLayer_INTEL_nullhw.json11
-rw-r--r--src/intel/nullhw-layer/intel_nullhw.c375
-rw-r--r--src/intel/nullhw-layer/meson.build38
6 files changed, 433 insertions, 1 deletions
diff --git a/meson_options.txt b/meson_options.txt
index e0ce124140c..a3967c50d59 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -221,7 +221,7 @@ option(
'vulkan-layers',
type : 'array',
value : [],
- choices : ['device-select', 'overlay'],
+ choices : ['device-select', 'intel-nullhw', 'overlay'],
description : 'List of vulkan layers to build'
)
option(
diff --git a/src/intel/meson.build b/src/intel/meson.build
index 528146f3bb7..3d5cf817c35 100644
--- a/src/intel/meson.build
+++ b/src/intel/meson.build
@@ -31,6 +31,9 @@ subdir('perf')
if with_intel_tools
subdir('tools')
endif
+if get_option('vulkan-layers').contains('intel-nullhw')
+ subdir('nullhw-layer')
+endif
if with_intel_vk
subdir('vulkan')
endif
diff --git a/src/intel/nullhw-layer/README b/src/intel/nullhw-layer/README
new file mode 100644
index 00000000000..8ecbd5cdf7d
--- /dev/null
+++ b/src/intel/nullhw-layer/README
@@ -0,0 +1,5 @@
+A Vulkan layer to disable all rendering/compute commands.
+
+To turn on the layer run :
+
+VK_INSTANCE_LAYERS=VK_LAYER_INTEL_nullhw /path/to/my_vulkan_app
diff --git a/src/intel/nullhw-layer/VkLayer_INTEL_nullhw.json b/src/intel/nullhw-layer/VkLayer_INTEL_nullhw.json
new file mode 100644
index 00000000000..49f67a449cd
--- /dev/null
+++ b/src/intel/nullhw-layer/VkLayer_INTEL_nullhw.json
@@ -0,0 +1,11 @@
+{
+ "file_format_version" : "1.0.0",
+ "layer" : {
+ "name": "VK_LAYER_INTEL_nullhw",
+ "type": "GLOBAL",
+ "library_path": "libVkLayer_INTEL_nullhw.so",
+ "api_version": "1.1.73",
+ "implementation_version": "1",
+ "description": "INTEL NULL HW"
+ }
+}
diff --git a/src/intel/nullhw-layer/intel_nullhw.c b/src/intel/nullhw-layer/intel_nullhw.c
new file mode 100644
index 00000000000..2546f0d492e
--- /dev/null
+++ b/src/intel/nullhw-layer/intel_nullhw.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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 <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <vulkan/vulkan.h>
+#include <vulkan/vk_layer.h>
+
+#include "util/debug.h"
+#include "util/hash_table.h"
+#include "util/macros.h"
+#include "util/simple_mtx.h"
+
+#include "vk_enum_to_str.h"
+#include "vk_util.h"
+
+struct instance_data {
+ struct vk_instance_dispatch_table vtable;
+ VkInstance instance;
+};
+
+struct device_data {
+ struct instance_data *instance;
+
+ PFN_vkSetDeviceLoaderData set_device_loader_data;
+
+ struct vk_device_dispatch_table vtable;
+ VkPhysicalDevice physical_device;
+ VkDevice device;
+};
+
+static struct hash_table_u64 *vk_object_to_data = NULL;
+static simple_mtx_t vk_object_to_data_mutex = _SIMPLE_MTX_INITIALIZER_NP;
+
+static inline void ensure_vk_object_map(void)
+{
+ if (!vk_object_to_data)
+ vk_object_to_data = _mesa_hash_table_u64_create(NULL);
+}
+
+#define HKEY(obj) ((uint64_t)(obj))
+#define FIND(type, obj) ((type *)find_object_data(HKEY(obj)))
+
+static void *find_object_data(uint64_t obj)
+{
+ simple_mtx_lock(&vk_object_to_data_mutex);
+ ensure_vk_object_map();
+ void *data = _mesa_hash_table_u64_search(vk_object_to_data, obj);
+ simple_mtx_unlock(&vk_object_to_data_mutex);
+ return data;
+}
+
+static void map_object(uint64_t obj, void *data)
+{
+ simple_mtx_lock(&vk_object_to_data_mutex);
+ ensure_vk_object_map();
+ _mesa_hash_table_u64_insert(vk_object_to_data, obj, data);
+ simple_mtx_unlock(&vk_object_to_data_mutex);
+}
+
+static void unmap_object(uint64_t obj)
+{
+ simple_mtx_lock(&vk_object_to_data_mutex);
+ _mesa_hash_table_u64_remove(vk_object_to_data, obj);
+ simple_mtx_unlock(&vk_object_to_data_mutex);
+}
+
+/**/
+
+#define VK_CHECK(expr) \
+ do { \
+ VkResult __result = (expr); \
+ if (__result != VK_SUCCESS) { \
+ fprintf(stderr, "'%s' line %i failed with %s\n", \
+ #expr, __LINE__, vk_Result_to_str(__result)); \
+ } \
+ } while (0)
+
+/**/
+
+static void override_queue(struct device_data *device_data,
+ VkDevice device,
+ uint32_t queue_family_index,
+ VkQueue queue)
+{
+ VkCommandPoolCreateInfo cmd_buffer_pool_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .queueFamilyIndex = queue_family_index,
+ };
+ VkCommandPool cmd_pool;
+ VK_CHECK(device_data->vtable.CreateCommandPool(device,
+ &cmd_buffer_pool_info,
+ NULL, &cmd_pool));
+
+
+ VkCommandBufferAllocateInfo cmd_buffer_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .commandPool = cmd_pool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandBufferCount = 1,
+ };
+ VkCommandBuffer cmd_buffer;
+ VK_CHECK(device_data->vtable.AllocateCommandBuffers(device,
+ &cmd_buffer_info,
+ &cmd_buffer));
+ VK_CHECK(device_data->set_device_loader_data(device, cmd_buffer));
+
+ VkCommandBufferBeginInfo buffer_begin_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ };
+ device_data->vtable.BeginCommandBuffer(cmd_buffer, &buffer_begin_info);
+
+ VkPerformanceOverrideInfoINTEL override_info = {
+ .sType = VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL,
+ .type = VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL,
+ .enable = VK_TRUE,
+ };
+ device_data->vtable.CmdSetPerformanceOverrideINTEL(cmd_buffer, &override_info);
+
+ device_data->vtable.EndCommandBuffer(cmd_buffer);
+
+ VkSubmitInfo submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .commandBufferCount = 1,
+ .pCommandBuffers = &cmd_buffer,
+ };
+ VK_CHECK(device_data->vtable.QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE));
+
+ VK_CHECK(device_data->vtable.QueueWaitIdle(queue));
+
+ device_data->vtable.DestroyCommandPool(device, cmd_pool, NULL);
+}
+
+static void device_override_queues(struct device_data *device_data,
+ const VkDeviceCreateInfo *pCreateInfo)
+{
+ for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
+ for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) {
+ VkQueue queue;
+ device_data->vtable.GetDeviceQueue(device_data->device,
+ pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,
+ j, &queue);
+
+ VK_CHECK(device_data->set_device_loader_data(device_data->device, queue));
+
+ override_queue(device_data, device_data->device,
+ pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, queue);
+ }
+ }
+}
+
+static VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,
+ VkLayerFunction func)
+{
+ vk_foreach_struct(item, pCreateInfo->pNext) {
+ if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
+ ((VkLayerDeviceCreateInfo *) item)->function == func)
+ return (VkLayerDeviceCreateInfo *)item;
+ }
+ unreachable("device chain info not found");
+ return NULL;
+}
+
+static struct device_data *new_device_data(VkDevice device, struct instance_data *instance)
+{
+ struct device_data *data = calloc(1, sizeof(*data));
+ data->instance = instance;
+ data->device = device;
+ map_object(HKEY(data->device), data);
+ return data;
+}
+
+static void destroy_device_data(struct device_data *data)
+{
+ unmap_object(HKEY(data->device));
+ free(data);
+}
+
+static VkResult nullhw_CreateDevice(
+ VkPhysicalDevice physicalDevice,
+ const VkDeviceCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkDevice* pDevice)
+{
+ VkLayerDeviceCreateInfo *chain_info =
+ get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
+
+ assert(chain_info->u.pLayerInfo);
+ PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+ PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
+ PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");
+ if (fpCreateDevice == NULL) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ // Advance the link info for the next element on the chain
+ chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
+
+ VkDeviceCreateInfo device_info = *pCreateInfo;
+ const char **extensions = calloc(device_info.enabledExtensionCount + 1, sizeof(*extensions));
+ bool found = false;
+ for (uint32_t i = 0; i < device_info.enabledExtensionCount; i++) {
+ if (!strcmp(device_info.ppEnabledExtensionNames[i], "VK_INTEL_performance_query")) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ memcpy(extensions, device_info.ppEnabledExtensionNames,
+ sizeof(*extensions) * device_info.enabledExtensionCount);
+ extensions[device_info.enabledExtensionCount++] = "VK_INTEL_performance_query";
+ device_info.ppEnabledExtensionNames = extensions;
+ }
+
+ VkResult result = fpCreateDevice(physicalDevice, &device_info, pAllocator, pDevice);
+ free(extensions);
+ if (result != VK_SUCCESS) return result;
+
+ struct instance_data *instance_data = FIND(struct instance_data, physicalDevice);
+ struct device_data *device_data = new_device_data(*pDevice, instance_data);
+ device_data->physical_device = physicalDevice;
+ vk_load_device_commands(*pDevice, fpGetDeviceProcAddr, &device_data->vtable);
+
+ VkLayerDeviceCreateInfo *load_data_info =
+ get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);
+ device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;
+
+ device_override_queues(device_data, pCreateInfo);
+
+ return result;
+}
+
+static void nullhw_DestroyDevice(
+ VkDevice device,
+ const VkAllocationCallbacks* pAllocator)
+{
+ struct device_data *device_data = FIND(struct device_data, device);
+ device_data->vtable.DestroyDevice(device, pAllocator);
+ destroy_device_data(device_data);
+}
+
+static struct instance_data *new_instance_data(VkInstance instance)
+{
+ struct instance_data *data = calloc(1, sizeof(*data));
+ data->instance = instance;
+ map_object(HKEY(data->instance), data);
+ return data;
+}
+
+static void destroy_instance_data(struct instance_data *data)
+{
+ unmap_object(HKEY(data->instance));
+ free(data);
+}
+
+static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
+ VkLayerFunction func)
+{
+ vk_foreach_struct(item, pCreateInfo->pNext) {
+ if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
+ ((VkLayerInstanceCreateInfo *) item)->function == func)
+ return (VkLayerInstanceCreateInfo *) item;
+ }
+ unreachable("instance chain info not found");
+ return NULL;
+}
+
+static VkResult nullhw_CreateInstance(
+ const VkInstanceCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkInstance* pInstance)
+{
+ VkLayerInstanceCreateInfo *chain_info =
+ get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
+
+ assert(chain_info->u.pLayerInfo);
+ PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
+ chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+ PFN_vkCreateInstance fpCreateInstance =
+ (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
+ if (fpCreateInstance == NULL) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ // Advance the link info for the next element on the chain
+ chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
+
+ VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
+ if (result != VK_SUCCESS) return result;
+
+ struct instance_data *instance_data = new_instance_data(*pInstance);
+ vk_load_instance_commands(instance_data->instance,
+ fpGetInstanceProcAddr,
+ &instance_data->vtable);
+
+ return result;
+}
+
+static void nullhw_DestroyInstance(
+ VkInstance instance,
+ const VkAllocationCallbacks* pAllocator)
+{
+ struct instance_data *instance_data = FIND(struct instance_data, instance);
+ instance_data->vtable.DestroyInstance(instance, pAllocator);
+ destroy_instance_data(instance_data);
+}
+
+static const struct {
+ const char *name;
+ void *ptr;
+} name_to_funcptr_map[] = {
+ { "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr },
+#define ADD_HOOK(fn) { "vk" # fn, (void *) nullhw_ ## fn }
+ ADD_HOOK(CreateInstance),
+ ADD_HOOK(DestroyInstance),
+ ADD_HOOK(CreateDevice),
+ ADD_HOOK(DestroyDevice),
+};
+
+static void *find_ptr(const char *name)
+{
+ for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {
+ if (strcmp(name, name_to_funcptr_map[i].name) == 0)
+ return name_to_funcptr_map[i].ptr;
+ }
+
+ return NULL;
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev,
+ const char *funcName)
+{
+ void *ptr = find_ptr(funcName);
+ if (ptr) return (PFN_vkVoidFunction)(ptr);
+
+ if (dev == NULL) return NULL;
+
+ struct device_data *device_data = FIND(struct device_data, dev);
+ if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;
+ return device_data->vtable.GetDeviceProcAddr(dev, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,
+ const char *funcName)
+{
+ void *ptr = find_ptr(funcName);
+ if (ptr) return (PFN_vkVoidFunction) ptr;
+
+ struct instance_data *instance_data = FIND(struct instance_data, instance);
+ if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;
+ return instance_data->vtable.GetInstanceProcAddr(instance, funcName);
+}
diff --git a/src/intel/nullhw-layer/meson.build b/src/intel/nullhw-layer/meson.build
new file mode 100644
index 00000000000..618b7788776
--- /dev/null
+++ b/src/intel/nullhw-layer/meson.build
@@ -0,0 +1,38 @@
+# Copyright © 2019 Intel Corporation
+
+# 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.
+
+vklayer_intel_nullhw_files = files(
+ 'intel_nullhw.c',
+)
+
+vklayer_intel_nullhw = shared_library(
+ 'VkLayer_INTEL_nullhw',
+ vklayer_intel_nullhw_files,
+ c_args : [no_override_init_args, vulkan_wsi_args],
+ dependencies : [idep_vulkan_util, idep_mesautil, vulkan_wsi_deps, dep_dl],
+ include_directories : [inc_include, inc_src],
+ link_args : cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro']),
+ install : true
+)
+
+install_data(
+ files('VkLayer_INTEL_nullhw.json'),
+ install_dir : join_paths(get_option('datadir'), 'vulkan', 'explicit_layer.d'),
+)