From 2be0bdbcbbd175347d6404d1ecc7cf0e9a0fa6f3 Mon Sep 17 00:00:00 2001 From: "Pierre-Loup A. Griffais" Date: Sat, 7 Dec 2019 01:11:33 -0800 Subject: [PATCH] Start of Vulkan compute rendering code. Getting FBIDs (glxgears still OK). --- meson.build | 4 +- src/drm.cpp | 6 +- src/{drm.h => drm.hpp} | 0 src/main.cpp | 9 +- src/main.hpp | 3 + src/rendervulkan.cpp | 312 +++++++++++++++++++++++++++++++++++++++++ src/rendervulkan.hpp | 34 +++++ src/steamcompmgr.c | 8 +- 8 files changed, 370 insertions(+), 6 deletions(-) rename src/{drm.h => drm.hpp} (100%) create mode 100644 src/rendervulkan.cpp create mode 100644 src/rendervulkan.hpp diff --git a/meson.build b/meson.build index 32ad3c4..bddd7d3 100644 --- a/meson.build +++ b/meson.build @@ -15,6 +15,7 @@ dep_xxf86vm = dependency('xxf86vm') pixman_dep = dependency('pixman-1') drm_dep = dependency('libdrm') wlroots_dep = dependency('wlroots') +vulkan_dep = dependency('vulkan') cc = meson.get_compiler('c') @@ -56,10 +57,11 @@ executable( 'src/main.c', 'src/wlserver.c', 'src/drm.cpp', + 'src/rendervulkan.cpp', dependencies : [ dep_x11, dep_xdamage, dep_xcomposite, dep_xrender, dep_xext, dep_gl, dep_xxf86vm, pixman_dep, drm_dep, wlroots_dep, wayland_server, wayland_protos, libinput, xkbcommon, math, thread_dep, waffle_dep, - wlroots_static_dep + wlroots_static_dep, vulkan_dep ], ) diff --git a/src/drm.cpp b/src/drm.cpp index 3d693c7..f8729b7 100644 --- a/src/drm.cpp +++ b/src/drm.cpp @@ -13,7 +13,8 @@ #include #include -#include "drm.h" +#include "drm.hpp" +#include "main.hpp" #include @@ -407,6 +408,9 @@ int init_drm(struct drm_t *drm, const char *device, const char *mode_str, unsign std::thread flip_handler_thread( flip_handler_thread_run ); flip_handler_thread.detach(); + g_nOutputWidth = drm->mode->hdisplay; + g_nOutputHeight = drm->mode->vdisplay; + return 0; } diff --git a/src/drm.h b/src/drm.hpp similarity index 100% rename from src/drm.h rename to src/drm.hpp diff --git a/src/main.cpp b/src/main.cpp index 2531134..ecfc82e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,7 +11,7 @@ #include "main.hpp" #include "main.h" -#include "drm.h" +#include "drm.hpp" #include @@ -26,6 +26,9 @@ int g_nNestedWidth = 1280; int g_nNestedHeight = 720; int g_nNestedRefresh = 60; +int g_nOutputWidth = 1280; +int g_nOutputHeight = 720; + bool g_bIsNested = false; int BIsNested() @@ -121,8 +124,8 @@ void initOutput(void) 0, }; - const int32_t window_width = 1280; - const int32_t window_height = 720; + const int32_t window_width = g_nOutputWidth; + const int32_t window_height = g_nOutputHeight; waffle_init(init_attrs); dpy = waffle_display_connect(NULL); diff --git a/src/main.hpp b/src/main.hpp index 73a357d..f48d914 100644 --- a/src/main.hpp +++ b/src/main.hpp @@ -24,6 +24,9 @@ extern int g_nNestedWidth; extern int g_nNestedHeight; extern int g_nNestedRefresh; +extern int g_nOutputWidth; +extern int g_nOutputHeight; + int BIsNested( void ); #ifndef C_SIDE diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp new file mode 100644 index 0000000..8b5c620 --- /dev/null +++ b/src/rendervulkan.cpp @@ -0,0 +1,312 @@ +// Initialize Vulkan and composite stuff with a compute queue + +#include "rendervulkan.hpp" +#include "main.hpp" + +PFN_vkGetMemoryFdKHR dyn_vkGetMemoryFdKHR; + +const VkApplicationInfo appInfo = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "steamcompmgr", + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "just some code", + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_0, +}; + +VkInstance instance = VK_NULL_HANDLE; + +VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; +uint32_t queueFamilyIndex; +VkQueue queue; +VkDevice device = VK_NULL_HANDLE; + +struct VkPhysicalDeviceMemoryProperties memoryProperties; + +CVulkanOutputImage outputImage[2]; + +#define MAX_DEVICE_COUNT 8 +#define MAX_QUEUE_COUNT 8 + +#define VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA (VkStructureType)1000001002 +#define VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA (VkStructureType)1000001003 + +struct wsi_image_create_info { + VkStructureType sType; + const void *pNext; + bool scanout; + + uint32_t modifier_count; + const uint64_t *modifiers; +}; + +struct wsi_memory_allocate_info { + VkStructureType sType; + const void *pNext; + bool implicit_sync; +}; + +static inline uint32_t DRMFormatToVulkanFormat( VkFormat vkFormat ) +{ + switch ( vkFormat ) + { + case VK_FORMAT_R8G8B8A8_UNORM: + return DRM_FORMAT_RGBA8888; + default: + return DRM_FORMAT_INVALID; + } +} + +int32_t findMemoryType( VkMemoryPropertyFlags properties, uint32_t requiredTypeBits ) +{ + for ( uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++ ) + { + if ( ( ( 1 << i ) & requiredTypeBits ) == 0 ) + continue; + + if ( ( properties & memoryProperties.memoryTypes[ i ].propertyFlags ) != properties ) + continue; + + return i; + } + + return -1; +} + +bool CVulkanOutputImage::BInit(uint32_t width, uint32_t height, VkFormat format) +{ + VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL; + // We'll only access it with compute probably + VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT; + VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + VkImageCreateInfo imageInfo = {}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = format; + imageInfo.tiling = tiling; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = usage; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + // If not nested, these images will be flipped directly to the screen + if ( BIsNested() == false ) + { + wsi_image_create_info wsiImageCreateInfo = {}; + wsiImageCreateInfo.sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA; + wsiImageCreateInfo.scanout = VK_TRUE; + + imageInfo.pNext = &wsiImageCreateInfo; + } + + if (vkCreateImage(device, &imageInfo, nullptr, &m_vkImage) != VK_SUCCESS) { + return false; + } + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, m_vkImage, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(properties, memRequirements.memoryTypeBits ); + + if ( BIsNested() == false ) + { + wsi_memory_allocate_info wsiAllocInfo = {}; + wsiAllocInfo.sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA; + wsiAllocInfo.implicit_sync = true; + + allocInfo.pNext = &wsiAllocInfo; + + const VkExportMemoryAllocateInfo memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = &memory_export_info, + .image = m_vkImage, + .buffer = VK_NULL_HANDLE, + }; + + wsiAllocInfo.pNext = &memory_dedicated_info; + } + + if (vkAllocateMemory(device, &allocInfo, nullptr, &m_vkImageMemory) != VK_SUCCESS) { + return false; + } + + VkResult res = vkBindImageMemory(device, m_vkImage, m_vkImageMemory, 0); + + if ( res != VK_SUCCESS ) + return false; + + m_DMA = {}; + + if ( BIsNested() == false ) + { + m_DMA.modifier = DRM_FORMAT_MOD_INVALID; + m_DMA.n_planes = 1; + m_DMA.width = width; + m_DMA.height = height; + m_DMA.format = DRMFormatToVulkanFormat( format ); + + const VkMemoryGetFdInfoKHR memory_get_fd_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + .pNext = NULL, + .memory = m_vkImageMemory, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + res = dyn_vkGetMemoryFdKHR(device, &memory_get_fd_info, &m_DMA.fd[0]); + + if ( res != VK_SUCCESS ) + return false; + + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + vkGetImageSubresourceLayout(device, m_vkImage, &image_subresource, &image_layout); + + + m_DMA.stride[0] = image_layout.rowPitch; + + m_FBID = drm_fbid_from_dmabuf( &g_DRM, &m_DMA ); + + if ( m_FBID == 0 ) + return false; + } + + return true; +} + + +int init_device() +{ + uint32_t physicalDeviceCount; + VkPhysicalDevice deviceHandles[MAX_DEVICE_COUNT]; + VkQueueFamilyProperties queueFamilyProperties[MAX_QUEUE_COUNT]; + + vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, 0); + physicalDeviceCount = physicalDeviceCount > MAX_DEVICE_COUNT ? MAX_DEVICE_COUNT : physicalDeviceCount; + vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, deviceHandles); + + for (uint32_t i = 0; i < physicalDeviceCount; ++i) + { + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(deviceHandles[i], &queueFamilyCount, NULL); + queueFamilyCount = queueFamilyCount > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : queueFamilyCount; + vkGetPhysicalDeviceQueueFamilyProperties(deviceHandles[i], &queueFamilyCount, queueFamilyProperties); + + for (uint32_t j = 0; j < queueFamilyCount; ++j) { + if ( queueFamilyProperties[j].queueFlags & VK_QUEUE_COMPUTE_BIT && + !(queueFamilyProperties[j].queueFlags & VK_QUEUE_GRAPHICS_BIT ) ) + { + queueFamilyIndex = j; + physicalDevice = deviceHandles[i]; + } + } + + if (physicalDevice) + { + break; + } + } + + vkGetPhysicalDeviceMemoryProperties( physicalDevice, &memoryProperties ); + + float queuePriorities = 1.0f; + + VkDeviceQueueCreateInfo queueCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = queueFamilyIndex, + .queueCount = 1, + .pQueuePriorities = &queuePriorities + }; + + std::vector< const char * > vecEnabledDeviceExtensions; + vecEnabledDeviceExtensions.push_back( VK_KHR_SWAPCHAIN_EXTENSION_NAME ); + vecEnabledDeviceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME ); + vecEnabledDeviceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME ); + + VkDeviceCreateInfo deviceCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = 1, + .pQueueCreateInfos = &queueCreateInfo, + .enabledLayerCount = 0, + .ppEnabledLayerNames = 0, + .enabledExtensionCount = (uint32_t)vecEnabledDeviceExtensions.size(), + .ppEnabledExtensionNames = vecEnabledDeviceExtensions.data(), + .pEnabledFeatures = 0, + }; + + VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, NULL, &device); + + if ( result != VK_SUCCESS ) + { + return false; + } + + vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); + + if ( queue == VK_NULL_HANDLE ) + return false; + + return true; +} + +void fini_device() +{ + vkDestroyDevice(device, 0); +} + +int init_vulkan(void) +{ + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + + std::vector< const char * > vecEnabledInstanceExtensions; + vecEnabledInstanceExtensions.push_back( VK_KHR_SURFACE_EXTENSION_NAME ); + vecEnabledInstanceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME ); + + const VkInstanceCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &appInfo, + .enabledExtensionCount = (uint32_t)vecEnabledInstanceExtensions.size(), + .ppEnabledExtensionNames = vecEnabledInstanceExtensions.data(), + }; + + result = vkCreateInstance(&createInfo, 0, &instance); + + if ( result != VK_SUCCESS ) + return 0; + + if ( init_device() != 1 ) + { + return 0; + } + + dyn_vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr( device, "vkGetMemoryFdKHR" ); + if ( dyn_vkGetMemoryFdKHR == nullptr ) + return 0; + + bool bSuccess = outputImage[0].BInit( g_nOutputWidth, g_nOutputHeight, VK_FORMAT_R8G8B8A8_UNORM ); + + if ( bSuccess != true ) + return 0; + + bSuccess = outputImage[1].BInit( g_nOutputWidth, g_nOutputHeight, VK_FORMAT_R8G8B8A8_UNORM ); + + if ( bSuccess != true ) + return 0; + + return 1; +} diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp new file mode 100644 index 0000000..ed73440 --- /dev/null +++ b/src/rendervulkan.hpp @@ -0,0 +1,34 @@ +// Initialize Vulkan and composite stuff with a compute queue + +#pragma once + +#include "drm.hpp" + +#ifndef C_SIDE +extern "C" { +#endif + +#include +#include +#include + +#ifndef C_SIDE +class CVulkanOutputImage +{ +public: + bool BInit(uint32_t width, uint32_t height, VkFormat format); + +private: + VkImage m_vkImage; + VkDeviceMemory m_vkImageMemory; + + wlr_dmabuf_attributes m_DMA; + uint32_t m_FBID; +}; +#endif + +int init_vulkan(void); + +#ifndef C_SIDE +} +#endif diff --git a/src/steamcompmgr.c b/src/steamcompmgr.c index c0707d9..713e410 100644 --- a/src/steamcompmgr.c +++ b/src/steamcompmgr.c @@ -61,7 +61,8 @@ #include "main.hpp" #include "wlserver.h" -#include "drm.h" +#include "drm.hpp" +#include "rendervulkan.hpp" #define WAFFLE_API_VERSION 0x0106 #include @@ -1802,6 +1803,11 @@ steamcompmgr_main (int argc, char **argv) eglSwapInterval( eglGetCurrentDisplay(), 1 ); } + if ( init_vulkan() != True ) + { + fprintf (stderr, "alarm!!!\n"); + } + glEnable (GL_DEBUG_OUTPUT); glDebugMessageCallback(MessageCallback, 0);