mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-18 06:46:23 -04:00
vulkan: Device initialization
This initialized a Vulkan logical device according to compositor preference, but does not yet do anything with it.
This commit is contained in:
parent
9cf99ea4bf
commit
42caf8b387
5 changed files with 352 additions and 1 deletions
|
|
@ -136,6 +136,8 @@ wayland_cursor = dependency('wayland-cursor')
|
|||
xkb = dependency('xkbcommon', version: '>=1.0.0')
|
||||
fontconfig = dependency('fontconfig')
|
||||
utf8proc = dependency('libutf8proc', required: get_option('grapheme-clustering'))
|
||||
vulkan = dependency('vulkan')
|
||||
drm = dependency('libdrm').partial_dependency(compile_args: true, includes: true)
|
||||
|
||||
if utf8proc.found()
|
||||
add_project_arguments('-DFOOT_GRAPHEME_CLUSTERING=1', language: 'c')
|
||||
|
|
@ -165,6 +167,7 @@ wl_proto_xml = [
|
|||
wayland_protocols_datadir / 'unstable/tablet/tablet-unstable-v2.xml', # required by cursor-shape-v1
|
||||
wayland_protocols_datadir / 'staging/cursor-shape/cursor-shape-v1.xml',
|
||||
wayland_protocols_datadir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
|
||||
wayland_protocols_datadir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml',
|
||||
]
|
||||
|
||||
foreach prot : wl_proto_xml
|
||||
|
|
@ -288,6 +291,7 @@ executable(
|
|||
'search.c', 'search.h',
|
||||
'server.c', 'server.h', 'client-protocol.h',
|
||||
'shm.c', 'shm.h',
|
||||
'vulkan.c', 'vulkan.h',
|
||||
'slave.c', 'slave.h',
|
||||
'spawn.c', 'spawn.h',
|
||||
'tokenize.c', 'tokenize.h',
|
||||
|
|
@ -297,7 +301,7 @@ executable(
|
|||
'wayland.c', 'wayland.h', 'shm-formats.h',
|
||||
wl_proto_src + wl_proto_headers, version,
|
||||
dependencies: [math, threads, libepoll, pixman, wayland_client, wayland_cursor, xkb, fontconfig, utf8proc,
|
||||
tllist, fcft],
|
||||
tllist, fcft, vulkan, drm],
|
||||
link_with: pgolib,
|
||||
install: true)
|
||||
|
||||
|
|
|
|||
234
vulkan.c
Normal file
234
vulkan.c
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <pixman.h>
|
||||
#include <tllist.h>
|
||||
#include "linux-dmabuf-v1.h"
|
||||
#include "vulkan.h"
|
||||
|
||||
#define LOG_MODULE "vulkan"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "log.h"
|
||||
#include "debug.h"
|
||||
#include "macros.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
static void
|
||||
log_phdev(const VkPhysicalDeviceProperties *props)
|
||||
{
|
||||
#if LOG_ENABLE_DBG == 1
|
||||
uint32_t vv_major = VK_VERSION_MAJOR(props->apiVersion);
|
||||
uint32_t vv_minor = VK_VERSION_MINOR(props->apiVersion);
|
||||
uint32_t vv_patch = VK_VERSION_PATCH(props->apiVersion);
|
||||
|
||||
uint32_t dv_major = VK_VERSION_MAJOR(props->driverVersion);
|
||||
uint32_t dv_minor = VK_VERSION_MINOR(props->driverVersion);
|
||||
uint32_t dv_patch = VK_VERSION_PATCH(props->driverVersion);
|
||||
|
||||
const char *dev_type = "unknown";
|
||||
switch (props->deviceType) {
|
||||
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
||||
dev_type = "integrated";
|
||||
break;
|
||||
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
||||
dev_type = "discrete";
|
||||
break;
|
||||
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
||||
dev_type = "cpu";
|
||||
break;
|
||||
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
||||
dev_type = "vgpu";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_DBG("Vulkan device: %s, type: %s, supported API version: %u.%u.%u, driver version: %u.%u.%u",
|
||||
props->deviceName, dev_type, vv_major, vv_minor, vv_patch, dv_major, dv_minor, dv_patch);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
vulkan_select_queue_family(struct vulkan *vk, VkPhysicalDevice phdev)
|
||||
{
|
||||
uint32_t qfam_count;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(vk->physical_device, &qfam_count, NULL);
|
||||
assert(qfam_count > 0);
|
||||
VkQueueFamilyProperties queue_props[qfam_count];
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(vk->physical_device, &qfam_count, queue_props);
|
||||
|
||||
for (unsigned i = 0u; i < qfam_count; ++i) {
|
||||
if (queue_props[i].queueFlags & VK_QUEUE_TRANSFER_BIT) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0u; i < qfam_count; ++i) {
|
||||
if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
static bool
|
||||
check_extension(const VkExtensionProperties *avail, uint32_t avail_len, const char *name)
|
||||
{
|
||||
for (size_t i = 0; i < avail_len; i++)
|
||||
if (strcmp(avail[i].extensionName, name) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
vulkan_destroy(struct vulkan *vk)
|
||||
{
|
||||
if (vk->device)
|
||||
vkDestroyDevice(vk->device, NULL);
|
||||
if (vk->instance)
|
||||
vkDestroyInstance(vk->instance, NULL);
|
||||
free(vk);
|
||||
}
|
||||
|
||||
struct vulkan *
|
||||
vulkan_create(dev_t preferred_device)
|
||||
{
|
||||
LOG_DBG("Creating vulkan backend");
|
||||
struct vulkan *vk = calloc(1, sizeof(*vk));
|
||||
if (!vk) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VkApplicationInfo appInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pEngineName = "foot",
|
||||
.engineVersion = VK_MAKE_VERSION(1, 0, 0),
|
||||
.apiVersion = VK_API_VERSION_1_1,
|
||||
};
|
||||
|
||||
VkInstanceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pApplicationInfo = &appInfo,
|
||||
};
|
||||
|
||||
vk->instance = VK_NULL_HANDLE;
|
||||
if (vkCreateInstance(&createInfo, NULL, &vk->instance) != VK_SUCCESS) {
|
||||
LOG_ERR("Could not create Vulkan instance");
|
||||
goto error;
|
||||
}
|
||||
LOG_DBG("Created instance");
|
||||
|
||||
//
|
||||
// Enumerate and pick a physical device. The enumeration can take
|
||||
// a little while at least on my machines
|
||||
//
|
||||
vkEnumeratePhysicalDevices(vk->instance, &vk->device_len, NULL);
|
||||
if (vk->device_len == 0) {
|
||||
LOG_ERR("No physical Vulkan devices");
|
||||
goto error;
|
||||
}
|
||||
|
||||
vk->devices = calloc(vk->device_len+1, sizeof(*vk->devices));
|
||||
|
||||
vkEnumeratePhysicalDevices(vk->instance, &vk->device_len, vk->devices);
|
||||
LOG_DBG("Enumerated physical Vulkan devices");
|
||||
|
||||
int chosen = 0;
|
||||
for (uint32_t idx = 0; idx < vk->device_len; idx++) {
|
||||
VkPhysicalDevice phdev = vk->devices[idx];
|
||||
|
||||
uint32_t avail_extc = 0;
|
||||
if (vkEnumerateDeviceExtensionProperties(phdev, NULL, &avail_extc, NULL) != VK_SUCCESS || avail_extc == 0) {
|
||||
LOG_ERR("Could not enumerate device extensions");
|
||||
continue;
|
||||
}
|
||||
|
||||
VkExtensionProperties avail_ext_props[avail_extc + 1];
|
||||
if (vkEnumerateDeviceExtensionProperties(phdev, NULL, &avail_extc, avail_ext_props) != VK_SUCCESS) {
|
||||
LOG_ERR("Could not enumerate device extensions");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool has_drm_props = check_extension(avail_ext_props, avail_extc,
|
||||
VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME);
|
||||
if (!has_drm_props) {
|
||||
LOG_ERR("Device does not support DRM extension");
|
||||
continue;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceDrmPropertiesEXT drm_props = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT,
|
||||
};
|
||||
VkPhysicalDeviceProperties2 props = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
.pNext = &drm_props,
|
||||
};
|
||||
vkGetPhysicalDeviceProperties2(phdev, &props);
|
||||
|
||||
log_phdev(&props.properties);
|
||||
|
||||
if (preferred_device == 0) {
|
||||
// Integrated GPUs are usually better for memory mapping
|
||||
if (props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
||||
LOG_DBG("Selected integrated GPU");
|
||||
chosen = idx;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_t primary_devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor);
|
||||
dev_t render_devid = makedev(drm_props.renderMajor, drm_props.renderMinor);
|
||||
if (primary_devid == preferred_device || render_devid == preferred_device) {
|
||||
LOG_DBG("Selected preferred physical Vulkan device");
|
||||
chosen = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vk->physical_device = vk->devices[chosen];
|
||||
LOG_DBG("Selected physical Vulkan device");
|
||||
|
||||
const char *extensions[4] = { 0 };
|
||||
size_t extensions_len = 0;
|
||||
extensions[extensions_len++] = VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME;
|
||||
extensions[extensions_len++] = VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME;
|
||||
extensions[extensions_len++] = VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME;
|
||||
|
||||
const float prio = 1.f;
|
||||
VkDeviceQueueCreateInfo qinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.queueFamilyIndex = vulkan_select_queue_family(vk, vk->physical_device),
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &prio,
|
||||
};
|
||||
|
||||
VkDeviceCreateInfo dev_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.queueCreateInfoCount = 1u,
|
||||
.pQueueCreateInfos = &qinfo,
|
||||
.enabledExtensionCount = extensions_len,
|
||||
.ppEnabledExtensionNames = extensions,
|
||||
};
|
||||
|
||||
if (vkCreateDevice(vk->physical_device, &dev_info, NULL, &vk->device) != VK_SUCCESS) {
|
||||
LOG_ERR("Could not create device");
|
||||
goto error;
|
||||
}
|
||||
LOG_DBG("Created logical Vulkan device");
|
||||
|
||||
vk->api.vkGetMemoryFdKHR =
|
||||
(PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(vk->device, "vkGetMemoryFdKHR");
|
||||
|
||||
return vk;
|
||||
|
||||
error:
|
||||
vulkan_destroy(vk);
|
||||
return NULL;
|
||||
}
|
||||
20
vulkan.h
Normal file
20
vulkan.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
struct vulkan {
|
||||
VkInstance instance;
|
||||
VkPhysicalDevice *devices;
|
||||
uint32_t device_len;
|
||||
VkPhysicalDevice physical_device;
|
||||
|
||||
VkDevice device;
|
||||
|
||||
struct {
|
||||
PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR;
|
||||
} api;
|
||||
};
|
||||
|
||||
void vulkan_destroy(struct vulkan *vk);
|
||||
struct vulkan *vulkan_create(dev_t preferred_device);
|
||||
87
wayland.c
87
wayland.c
|
|
@ -34,6 +34,7 @@
|
|||
#include "shm-formats.h"
|
||||
#include "util.h"
|
||||
#include "xmalloc.h"
|
||||
#include "vulkan.h"
|
||||
|
||||
static void
|
||||
csd_reload_font(struct wl_window *win, float old_scale)
|
||||
|
|
@ -1085,6 +1086,76 @@ fdm_repeat(struct fdm *fdm, int fd, int events, void *data)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dmabuf_feedback_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback)
|
||||
{
|
||||
LOG_DBG("linux dmabuf feedback done");
|
||||
struct wayland *wayl = data;
|
||||
if (wayl->vk == NULL)
|
||||
wayl->vk = vulkan_create(wayl->preferred_device);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dmabuf_feedback_format_table(void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, int fd, uint32_t size)
|
||||
{
|
||||
LOG_DBG("linux dmabuf feedback format table");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dmabuf_feedback_main_device(void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, struct wl_array *device)
|
||||
{
|
||||
|
||||
dev_t dev_id;
|
||||
assert(device->size == sizeof(dev_id));
|
||||
memcpy(&dev_id, device->data, sizeof(dev_id));
|
||||
|
||||
struct wayland *wayl = data;
|
||||
wayl->preferred_device = dev_id;
|
||||
|
||||
LOG_DBG("linux dmabuf feedback main device: %ld", dev_id);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dmabuf_feedback_tranche_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback)
|
||||
{
|
||||
LOG_DBG("linux dmabuf feedback tranche done");
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dmabuf_feedback_tranche_target_device(void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, struct wl_array *device)
|
||||
{
|
||||
|
||||
dev_t dev_id;
|
||||
assert(device->size == sizeof(dev_id));
|
||||
memcpy(&dev_id, device->data, sizeof(dev_id));
|
||||
|
||||
LOG_DBG("linux dmabuf feedback tranche target device: %ld", dev_id);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dmabuf_feedback_tranche_formats(void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, struct wl_array *indices)
|
||||
{
|
||||
LOG_DBG("linux dmabuf feedback tranche formats");
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dmabuf_feedback_tranche_flags(void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, uint32_t flags)
|
||||
{
|
||||
LOG_DBG("linux dmabuf feedback tranche flags: %d", flags);
|
||||
}
|
||||
|
||||
static const struct zwp_linux_dmabuf_feedback_v1_listener
|
||||
linux_dmabuf_feedback_v1_listener = {
|
||||
.done = handle_dmabuf_feedback_done,
|
||||
.format_table = handle_dmabuf_feedback_format_table,
|
||||
.main_device = handle_dmabuf_feedback_main_device,
|
||||
.tranche_done = handle_dmabuf_feedback_tranche_done,
|
||||
.tranche_target_device = handle_dmabuf_feedback_tranche_target_device,
|
||||
.tranche_formats = handle_dmabuf_feedback_tranche_formats,
|
||||
.tranche_flags = handle_dmabuf_feedback_tranche_flags,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_global(void *data, struct wl_registry *registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
|
|
@ -1115,6 +1186,18 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
wayl->registry, name, &wl_subcompositor_interface, required);
|
||||
}
|
||||
|
||||
else if (streq(interface, zwp_linux_dmabuf_v1_interface.name)) {
|
||||
const uint32_t required = 4;
|
||||
if (!verify_iface_version(interface, version, required))
|
||||
return;
|
||||
|
||||
wayl->linux_dmabuf = wl_registry_bind(
|
||||
wayl->registry, name, &zwp_linux_dmabuf_v1_interface, required);
|
||||
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback = zwp_linux_dmabuf_v1_get_default_feedback(wayl->linux_dmabuf);
|
||||
zwp_linux_dmabuf_feedback_v1_add_listener(feedback, &linux_dmabuf_feedback_v1_listener, wayl);
|
||||
}
|
||||
|
||||
else if (streq(interface, wl_shm_interface.name)) {
|
||||
const uint32_t required = 1;
|
||||
if (!verify_iface_version(interface, version, required))
|
||||
|
|
@ -1679,6 +1762,10 @@ wayl_destroy(struct wayland *wayl)
|
|||
zwp_text_input_manager_v3_destroy(wayl->text_input_manager);
|
||||
#endif
|
||||
|
||||
if (wayl->vk != NULL)
|
||||
vulkan_destroy(wayl->vk);
|
||||
if (wayl->linux_dmabuf != NULL)
|
||||
zwp_linux_dmabuf_v1_destroy(wayl->linux_dmabuf);
|
||||
if (wayl->single_pixel_manager != NULL)
|
||||
wp_single_pixel_buffer_manager_v1_destroy(wayl->single_pixel_manager);
|
||||
if (wayl->fractional_scale_manager != NULL)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <uchar.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
#include <xdg-decoration-unstable-v1.h>
|
||||
#include <xdg-output-unstable-v1.h>
|
||||
#include <xdg-shell.h>
|
||||
#include <linux-dmabuf-v1.h>
|
||||
|
||||
#include <fcft/fcft.h>
|
||||
#include <tllist.h>
|
||||
|
|
@ -425,6 +427,7 @@ struct wayland {
|
|||
struct wl_compositor *compositor;
|
||||
struct wl_subcompositor *sub_compositor;
|
||||
struct wl_shm *shm;
|
||||
struct zwp_linux_dmabuf_v1 *linux_dmabuf;
|
||||
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||
|
||||
|
|
@ -458,6 +461,9 @@ struct wayland {
|
|||
|
||||
/* WL_SHM >= 2 */
|
||||
bool use_shm_release;
|
||||
|
||||
struct vulkan *vk;
|
||||
dev_t preferred_device;
|
||||
};
|
||||
|
||||
struct wayland *wayl_init(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue