nvk: add vulkan skeleton

This is enough to run vulkaninfo without crashing.

Jason:
* Drop a redundant nvk_device_entrypoints
* Add some VKAPI_ATTR and VKAPI_CALL
* nvk: Move EnumerateInstanceExtensionProperties to the top
  This way things are more-or-less in initialization order.  First the
  version then extensions then create the instance.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>
This commit is contained in:
Karol Herbst 2022-05-16 22:39:44 +02:00 committed by Marge Bot
parent cfbd1fd413
commit 83786bf1c9
13 changed files with 617 additions and 3 deletions

View File

@ -242,6 +242,7 @@ with_broadcom_vk = _vulkan_drivers.contains('broadcom')
with_imagination_vk = _vulkan_drivers.contains('imagination-experimental')
with_imagination_srv = get_option('imagination-srv')
with_microsoft_vk = _vulkan_drivers.contains('microsoft-experimental')
with_nouveau_vk = _vulkan_drivers.contains('nouveau-experimental')
with_any_vk = _vulkan_drivers.length() != 0
with_any_broadcom = [
@ -258,6 +259,7 @@ with_any_intel = [
with_intel_tools,
with_intel_vk,
].contains(true)
with_any_nouveau = with_gallium_nouveau or with_nouveau_vk
if with_swrast_vk and not with_gallium_softpipe
error('swrast vulkan requires gallium swrast')
@ -1575,7 +1577,7 @@ _libdrm_checks = [
['intel', with_gallium_i915],
['amdgpu', (with_amd_vk and not with_platform_windows) or with_gallium_radeonsi],
['radeon', (with_gallium_radeonsi or with_gallium_r300 or with_gallium_r600)],
['nouveau', with_gallium_nouveau],
['nouveau', with_any_nouveau],
]
# Loop over the enables versions and get the highest libdrm requirement for all

View File

@ -211,7 +211,7 @@ option(
value : ['auto'],
choices : ['auto', 'amd', 'broadcom', 'freedreno', 'intel', 'intel_hasvk',
'panfrost', 'swrast', 'virtio', 'imagination-experimental',
'microsoft-experimental'],
'microsoft-experimental', 'nouveau-experimental'],
description : 'List of vulkan drivers to build. If this is set to auto ' +
'all drivers applicable to the target OS/architecture ' +
'will be built'

View File

@ -106,7 +106,7 @@ endif
if with_microsoft_clc or with_gallium_d3d12 or with_spirv_to_dxil or with_microsoft_vk
subdir('microsoft')
endif
if with_gallium_nouveau
if with_any_nouveau
subdir('nouveau')
endif
if with_gallium_asahi or with_tools.contains('asahi')

View File

View File

@ -18,6 +18,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
subdir('compiler')
if with_nouveau_vk
subdir('vulkan')
endif
if with_tools.contains('drm-shim')
subdir('drm-shim')
endif

View File

@ -0,0 +1,60 @@
nvk_files = files(
'nvk_device.c',
'nvk_device.h',
'nvk_instance.c',
'nvk_instance.h',
'nvk_physical_device.c',
'nvk_physical_device.h',
'nvk_private.h',
)
nouveau_icd = custom_target(
'nouveau_icd',
input : [vk_icd_gen, vk_api_xml],
output : 'nouveau_icd.@0@.json'.format(host_machine.cpu()),
command : [
prog_python, '@INPUT0@',
'--api-version', '1.3', '--xml', '@INPUT1@',
'--lib-path', join_paths(get_option('prefix'), get_option('libdir'),
'libvulkan_nouveau.so'),
'--out', '@OUTPUT@',
],
build_by_default : true,
install_dir : with_vulkan_icd_dir,
install : true,
)
nvk_entrypoints = custom_target(
'nvk_entrypoints',
input : [vk_entrypoints_gen, vk_api_xml],
output : ['nvk_entrypoints.h', 'nvk_entrypoints.c'],
command : [
prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--proto', '--weak',
'--out-h', '@OUTPUT0@', '--out-c', '@OUTPUT1@', '--prefix', 'nvk',
'--beta', with_vulkan_beta.to_string(),
],
depend_files : vk_entrypoints_gen_depend_files,
)
nvk_deps = [
dep_libdrm,
idep_vulkan_runtime,
idep_vulkan_util,
idep_vulkan_wsi,
idep_vulkan_wsi_headers,
]
libvulkan_nouveau = shared_library(
'vulkan_nouveau',
[
nvk_entrypoints,
nvk_files,
],
include_directories : [
inc_include,
inc_src,
],
dependencies : nvk_deps,
gnu_symbol_visibility : 'hidden',
install : true,
)

View File

@ -0,0 +1,53 @@
#include "nvk_device.h"
#include "nvk_instance.h"
#include "nvk_physical_device.h"
#include "vulkan/wsi/wsi_common.h"
VKAPI_ATTR VkResult VKAPI_CALL
nvk_CreateDevice(VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDevice *pDevice)
{
VK_FROM_HANDLE(nvk_physical_device, physical_device, physicalDevice);
VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
struct nvk_device *device;
device = vk_zalloc2(&physical_device->instance->vk.alloc,
pAllocator,
sizeof(*device),
8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (!device)
return vk_error(physical_device, VK_ERROR_OUT_OF_HOST_MEMORY);
struct vk_device_dispatch_table dispatch_table;
vk_device_dispatch_table_from_entrypoints(&dispatch_table, &nvk_device_entrypoints, true);
vk_device_dispatch_table_from_entrypoints(&dispatch_table, &wsi_device_entrypoints, false);
result =
vk_device_init(&device->vk, &physical_device->vk, &dispatch_table, pCreateInfo, pAllocator);
if (result != VK_SUCCESS)
goto fail_alloc;
*pDevice = nvk_device_to_handle(device);
return VK_SUCCESS;
fail_alloc:
vk_free(&device->vk.alloc, device);
return result;
}
VKAPI_ATTR void VKAPI_CALL
nvk_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator)
{
VK_FROM_HANDLE(nvk_device, device, _device);
if (!device)
return;
vk_free(&device->vk.alloc, device);
}

View File

@ -0,0 +1,13 @@
#ifndef NVK_DEVICE
#define NVK_DEVICE 1
#include "nvk_private.h"
#include "vulkan/runtime/vk_device.h"
struct nvk_device {
struct vk_device vk;
};
VK_DEFINE_HANDLE_CASTS(nvk_device, vk.base, VkDevice, VK_OBJECT_TYPE_DEVICE)
#endif

View File

@ -0,0 +1,82 @@
#include "nvk_instance.h"
#include "nvk_physical_device.h"
static const struct vk_instance_extension_table instance_extensions = {
.KHR_get_physical_device_properties2 = true,
.EXT_debug_report = true,
.EXT_debug_utils = true,
};
VKAPI_ATTR VkResult VKAPI_CALL
nvk_EnumerateInstanceExtensionProperties(const char *pLayerName,
uint32_t *pPropertyCount,
VkExtensionProperties *pProperties)
{
if (pLayerName)
return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
return vk_enumerate_instance_extension_properties(
&instance_extensions, pPropertyCount, pProperties);
}
VKAPI_ATTR VkResult VKAPI_CALL
nvk_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkInstance *pInstance)
{
struct nvk_instance *instance;
VkResult result;
if (pAllocator == NULL)
pAllocator = vk_default_allocator();
instance = vk_alloc(pAllocator, sizeof(*instance), 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!instance)
return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
struct vk_instance_dispatch_table dispatch_table;
vk_instance_dispatch_table_from_entrypoints(&dispatch_table, &nvk_instance_entrypoints, true);
result = vk_instance_init(
&instance->vk, &instance_extensions, &dispatch_table, pCreateInfo, pAllocator);
if (result != VK_SUCCESS) {
vk_free(pAllocator, instance);
return result;
}
instance->physical_devices_enumerated = false;
list_inithead(&instance->physical_devices);
*pInstance = nvk_instance_to_handle(instance);
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL
nvk_DestroyInstance(VkInstance _instance, const VkAllocationCallbacks *pAllocator)
{
VK_FROM_HANDLE(nvk_instance, instance, _instance);
if (!instance)
return;
list_for_each_entry_safe(struct nvk_physical_device, pdevice, &instance->physical_devices, link)
nvk_physical_device_destroy(pdevice);
vk_instance_finish(&instance->vk);
vk_free(&instance->vk.alloc, instance);
}
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
nvk_GetInstanceProcAddr(VkInstance _instance, const char *pName)
{
VK_FROM_HANDLE(nvk_instance, instance, _instance);
return vk_instance_get_proc_addr(&instance->vk, &nvk_instance_entrypoints, pName);
}
PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance, const char *pName)
{
return nvk_GetInstanceProcAddr(instance, pName);
}

View File

@ -0,0 +1,17 @@
#ifndef NVK_INSTANCE
#define NVK_INSTANCE 1
#include "nvk_private.h"
#include "vulkan/runtime/vk_instance.h"
struct nvk_instance {
struct vk_instance vk;
bool physical_devices_enumerated;
struct list_head physical_devices;
};
VK_DEFINE_HANDLE_CASTS(nvk_instance, vk.base, VkInstance, VK_OBJECT_TYPE_INSTANCE)
#endif

View File

@ -0,0 +1,325 @@
#include "nvk_physical_device.h"
#include "nvk_entrypoints.h"
#include "nvk_instance.h"
#include "vulkan/runtime/vk_device.h"
#include "vulkan/wsi/wsi_common.h"
VKAPI_ATTR void VKAPI_CALL
nvk_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures2 *pFeatures)
{
// VK_FROM_HANDLE(nvk_physical_device, pdevice, physicalDevice);
pFeatures->features = (VkPhysicalDeviceFeatures) {
.robustBufferAccess = true,
/* More features */
};
VkPhysicalDeviceVulkan11Features core_1_1 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
/* Vulkan 1.1 features */
};
VkPhysicalDeviceVulkan12Features core_1_2 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
/* Vulkan 1.2 features */
};
VkPhysicalDeviceVulkan13Features core_1_3 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
/* Vulkan 1.3 features */
};
vk_foreach_struct(ext, pFeatures->pNext)
{
if (vk_get_physical_device_core_1_1_feature_ext(ext, &core_1_1))
continue;
if (vk_get_physical_device_core_1_2_feature_ext(ext, &core_1_2))
continue;
if (vk_get_physical_device_core_1_3_feature_ext(ext, &core_1_3))
continue;
switch (ext->sType) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: {
VkPhysicalDevice4444FormatsFeaturesEXT *features = (void *)ext;
features->formatA4R4G4B4 = true;
features->formatA4B4G4R4 = true;
break;
}
/* More feature structs */
default:
break;
}
}
}
VKAPI_ATTR void VKAPI_CALL
nvk_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
VkPhysicalDeviceProperties2 *pProperties)
{
// VK_FROM_HANDLE(nvk_physical_device, pdevice, physicalDevice);
pProperties->properties = (VkPhysicalDeviceProperties) {
.apiVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION),
.driverVersion = vk_get_driver_version(),
/* More properties */
};
VkPhysicalDeviceVulkan11Properties core_1_1 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES,
/* Vulkan 1.1 properties */
};
VkPhysicalDeviceVulkan12Properties core_1_2 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES,
/* Vulkan 1.2 properties */
};
VkPhysicalDeviceVulkan13Properties core_1_3 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES,
/* Vulkan 1.3 properties */
};
vk_foreach_struct(ext, pProperties->pNext)
{
if (vk_get_physical_device_core_1_1_property_ext(ext, &core_1_1))
continue;
if (vk_get_physical_device_core_1_2_property_ext(ext, &core_1_2))
continue;
if (vk_get_physical_device_core_1_3_property_ext(ext, &core_1_3))
continue;
switch (ext->sType) {
/* More property structs */
default:
break;
}
}
}
PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, const char *pName)
{
VK_FROM_HANDLE(nvk_instance, instance, _instance);
return vk_instance_get_physical_device_proc_addr(&instance->vk, pName);
}
static void
nvk_get_device_extensions(const struct nvk_physical_device *device,
struct vk_device_extension_table *ext)
{
*ext = (struct vk_device_extension_table) {
.KHR_variable_pointers = true,
};
}
static VkResult
nvk_physical_device_try_create(struct nvk_instance *instance,
drmDevicePtr drm_device,
struct nvk_physical_device **device_out)
{
// const char *primary_path = drm_device->nodes[DRM_NODE_PRIMARY];
const char *path = drm_device->nodes[DRM_NODE_RENDER];
VkResult result;
int fd;
fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
if (errno == ENOMEM) {
return vk_errorf(
instance, VK_ERROR_OUT_OF_HOST_MEMORY, "Unable to open device %s: out of memory", path);
}
return vk_errorf(
instance, VK_ERROR_INCOMPATIBLE_DRIVER, "Unable to open device %s: %m", path);
}
vk_warn_non_conformant_implementation("nvk");
struct nvk_physical_device *device =
vk_zalloc(&instance->vk.alloc, sizeof(*device), 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (device == NULL) {
result = vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail_fd;
}
struct vk_physical_device_dispatch_table dispatch_table;
vk_physical_device_dispatch_table_from_entrypoints(
&dispatch_table, &nvk_physical_device_entrypoints, true);
vk_physical_device_dispatch_table_from_entrypoints(
&dispatch_table, &wsi_physical_device_entrypoints, false);
struct vk_device_extension_table supported_extensions;
nvk_get_device_extensions(device, &supported_extensions);
result = vk_physical_device_init(&device->vk, &instance->vk,
&supported_extensions, NULL,
&dispatch_table);
if (result != VK_SUCCESS) {
vk_error(instance, result);
goto fail_alloc;
}
device->instance = instance;
*device_out = device;
return VK_SUCCESS;
fail_alloc:
vk_free(&instance->vk.alloc, device);
fail_fd:
close(fd);
return result;
}
void
nvk_physical_device_destroy(struct nvk_physical_device *device)
{
vk_free(&device->instance->vk.alloc, device);
}
static VkResult
nvk_enumerate_physical_devices(struct nvk_instance *instance)
{
if (instance->physical_devices_enumerated)
return VK_SUCCESS;
instance->physical_devices_enumerated = true;
int max_devices = drmGetDevices2(0, NULL, 0);
if (max_devices < 1)
return VK_SUCCESS;
drmDevicePtr *devices = MALLOC(max_devices * sizeof(drmDevicePtr));
drmGetDevices2(0, devices, max_devices);
VkResult result = VK_SUCCESS;
for (unsigned i = 0; i < (unsigned)max_devices; i++) {
if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
devices[i]->bustype == DRM_BUS_PCI && devices[i]->deviceinfo.pci->vendor_id == 0x10de) {
struct nvk_physical_device *pdevice;
result = nvk_physical_device_try_create(instance, devices[i], &pdevice);
/* Incompatible DRM device, skip. */
if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
result = VK_SUCCESS;
continue;
}
/* Error creating the physical device, report the error. */
if (result != VK_SUCCESS)
break;
list_addtail(&pdevice->link, &instance->physical_devices);
}
}
drmFreeDevices(devices, max_devices);
FREE(devices);
/* If we successfully enumerated any devices, call it success */
return result;
}
VKAPI_ATTR VkResult VKAPI_CALL
nvk_EnumeratePhysicalDevices(VkInstance _instance,
uint32_t *pPhysicalDeviceCount,
VkPhysicalDevice *pPhysicalDevices)
{
VK_FROM_HANDLE(nvk_instance, instance, _instance);
VK_OUTARRAY_MAKE_TYPED(VkPhysicalDevice, out, pPhysicalDevices, pPhysicalDeviceCount);
VkResult result = nvk_enumerate_physical_devices(instance);
if (result != VK_SUCCESS)
return result;
list_for_each_entry(struct nvk_physical_device, pdevice, &instance->physical_devices, link)
{
vk_outarray_append_typed(VkPhysicalDevice, &out, i)
{
*i = nvk_physical_device_to_handle(pdevice);
}
}
return vk_outarray_status(&out);
}
VKAPI_ATTR VkResult VKAPI_CALL
nvk_EnumeratePhysicalDeviceGroups(VkInstance _instance,
uint32_t *pPhysicalDeviceGroupCount,
VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)
{
VK_FROM_HANDLE(nvk_instance, instance, _instance);
VK_OUTARRAY_MAKE_TYPED(VkPhysicalDeviceGroupProperties,
out,
pPhysicalDeviceGroupProperties,
pPhysicalDeviceGroupCount);
VkResult result = nvk_enumerate_physical_devices(instance);
if (result != VK_SUCCESS)
return result;
list_for_each_entry(struct nvk_physical_device, pdevice, &instance->physical_devices, link)
{
vk_outarray_append_typed(VkPhysicalDeviceGroupProperties, &out, p)
{
p->physicalDeviceCount = 1;
memset(p->physicalDevices, 0, sizeof(p->physicalDevices));
p->physicalDevices[0] = nvk_physical_device_to_handle(pdevice);
p->subsetAllocation = false;
}
}
return vk_outarray_status(&out);
}
VKAPI_ATTR void VKAPI_CALL
nvk_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
{
vk_foreach_struct(ext, pMemoryProperties->pNext)
{
switch (ext->sType) {
default:
nvk_debug_ignored_stype(ext->sType);
break;
}
}
}
VKAPI_ATTR void VKAPI_CALL
nvk_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
uint32_t *pQueueFamilyPropertyCount,
VkQueueFamilyProperties2 *pQueueFamilyProperties)
{
// VK_FROM_HANDLE(nvk_physical_device, pdevice, physicalDevice);
VK_OUTARRAY_MAKE_TYPED(
VkQueueFamilyProperties2, out, pQueueFamilyProperties, pQueueFamilyPropertyCount);
}
VKAPI_ATTR void VKAPI_CALL
nvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
VkFormat vk_format,
VkFormatProperties2 *pFormatProperties)
{
vk_foreach_struct(ext, pFormatProperties->pNext)
{
/* Use unsigned since some cases are not in the VkStructureType enum. */
switch ((unsigned)ext->sType) {
default:
nvk_debug_ignored_stype(ext->sType);
break;
}
}
}
VKAPI_ATTR VkResult VKAPI_CALL
nvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceImageFormatInfo2 *base_info,
VkImageFormatProperties2 *base_props)
{
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}

View File

@ -0,0 +1,25 @@
#ifndef NVK_PHYSICAL_DEVICE
#define NVK_PHYSICAL_DEVICE 1
#include "nvk_private.h"
#include "vulkan/runtime/vk_physical_device.h"
struct nvk_instance;
struct nvk_physical_device {
struct vk_physical_device vk;
struct nvk_instance *instance;
/* Link in nvk_instance::physical_devices */
struct list_head link;
};
VK_DEFINE_HANDLE_CASTS(nvk_physical_device,
vk.base,
VkPhysicalDevice,
VK_OBJECT_TYPE_PHYSICAL_DEVICE)
void nvk_physical_device_destroy(struct nvk_physical_device *);
#endif

View File

@ -0,0 +1,33 @@
#ifndef NVK_PRIVATE
#define NVK_PRIVATE 1
#include "nvk_entrypoints.h"
#include "util/log.h"
#include "util/u_memory.h"
#include "vulkan/runtime/vk_log.h"
#include "vulkan/util/vk_alloc.h"
#include "vulkan/util/vk_util.h"
#include <fcntl.h>
#include <xf86drm.h>
/**
* Warn on ignored extension structs.
*
* The Vulkan spec requires us to ignore unsupported or unknown structs in
* a pNext chain. In debug mode, emitting warnings for ignored structs may
* help us discover structs that we should not have ignored.
*
*
* From the Vulkan 1.0.38 spec:
*
* Any component of the implementation (the loader, any enabled layers,
* and drivers) must skip over, without processing (other than reading the
* sType and pNext members) any chained structures with sType values not
* defined by extensions supported by that component.
*/
#define nvk_debug_ignored_stype(sType) \
mesa_logd("%s: ignored VkStructureType %u\n", __func__, (sType))
#endif