bfd02982ab
Working nested Vulkan path now using surface from SDL2 window. For some definition of working, tile corruption there too.
1005 lines
25 KiB
C++
1005 lines
25 KiB
C++
// Initialize Vulkan and composite stuff with a compute queue
|
|
|
|
#include "rendervulkan.hpp"
|
|
#include "main.hpp"
|
|
|
|
#include "composite.h"
|
|
|
|
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,
|
|
};
|
|
|
|
std::vector< const char * > g_vecSDLInstanceExts;
|
|
|
|
VkInstance instance;
|
|
|
|
VkSurfaceKHR surface;
|
|
VkSurfaceCapabilitiesKHR surfaceCaps;
|
|
std::vector< VkSurfaceFormatKHR > surfaceFormats;
|
|
std::vector< VkPresentModeKHR > presentModes;
|
|
uint32_t g_nSwapChainImageIndex;
|
|
|
|
VkSwapchainKHR swapChain;
|
|
std::vector< VkImage > swapChainImages;
|
|
std::vector< VkImageView > swapChainImageViews;
|
|
|
|
VkPhysicalDevice physicalDevice;
|
|
uint32_t queueFamilyIndex;
|
|
VkQueue queue;
|
|
VkShaderModule shaderModule;
|
|
VkDevice device;
|
|
VkCommandPool commandPool;
|
|
VkDescriptorPool descriptorPool;
|
|
|
|
struct VkPhysicalDeviceMemoryProperties memoryProperties;
|
|
|
|
int g_nOutImage; // ping/pong between two RTs
|
|
CVulkanTexture outputImage[2];
|
|
|
|
std::unordered_map<VulkanTexture_t, CVulkanTexture *> g_mapVulkanTextures;
|
|
std::atomic<VulkanTexture_t> g_nMaxVulkanTexHandle;
|
|
|
|
#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;
|
|
};
|
|
|
|
struct {
|
|
uint32_t DRMFormat;
|
|
VkFormat vkFormat;
|
|
} s_DRMVKFormatTable[] = {
|
|
{ DRM_FORMAT_XRGB8888, VK_FORMAT_A8B8G8R8_UNORM_PACK32 },
|
|
{ DRM_FORMAT_ARGB8888, VK_FORMAT_A8B8G8R8_UNORM_PACK32 },
|
|
{ DRM_FORMAT_RGBA8888, VK_FORMAT_R8G8B8A8_UNORM },
|
|
{ DRM_FORMAT_INVALID, VK_FORMAT_UNDEFINED },
|
|
};
|
|
|
|
static inline uint32_t VulkanFormatToDRM( VkFormat vkFormat )
|
|
{
|
|
for ( int i = 0; s_DRMVKFormatTable[i].vkFormat != VK_FORMAT_UNDEFINED; i++ )
|
|
{
|
|
if ( s_DRMVKFormatTable[i].vkFormat == vkFormat )
|
|
{
|
|
return s_DRMVKFormatTable[i].DRMFormat;
|
|
}
|
|
}
|
|
|
|
return DRM_FORMAT_INVALID;
|
|
}
|
|
|
|
static inline VkFormat DRMFormatToVulkan( uint32_t nDRMFormat )
|
|
{
|
|
for ( int i = 0; s_DRMVKFormatTable[i].vkFormat != VK_FORMAT_UNDEFINED; i++ )
|
|
{
|
|
if ( s_DRMVKFormatTable[i].DRMFormat == nDRMFormat )
|
|
{
|
|
return s_DRMVKFormatTable[i].vkFormat;
|
|
}
|
|
}
|
|
|
|
return VK_FORMAT_UNDEFINED;
|
|
}
|
|
|
|
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 CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, bool bFlippable, bool bTextureable, wlr_dmabuf_attributes *pDMA /* = nullptr */ )
|
|
{
|
|
VkResult res = VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
VkImageUsageFlags usage = bTextureable ? VK_IMAGE_USAGE_SAMPLED_BIT : VK_IMAGE_USAGE_STORAGE_BIT;
|
|
|
|
VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
|
|
// Possible extensions for below
|
|
wsi_image_create_info wsiImageCreateInfo = {};
|
|
VkExternalMemoryImageCreateInfo externalImageCreateInfo = {};
|
|
|
|
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 ( pDMA != nullptr )
|
|
{
|
|
assert( format == DRMFormatToVulkan( pDMA->format ) );
|
|
}
|
|
|
|
if ( bFlippable == true )
|
|
{
|
|
wsiImageCreateInfo.sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA;
|
|
wsiImageCreateInfo.scanout = VK_TRUE;
|
|
wsiImageCreateInfo.pNext = imageInfo.pNext;
|
|
|
|
imageInfo.pNext = &wsiImageCreateInfo;
|
|
}
|
|
|
|
if ( pDMA != nullptr )
|
|
{
|
|
externalImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
|
|
externalImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
|
|
externalImageCreateInfo.pNext = imageInfo.pNext;
|
|
|
|
imageInfo.pNext = &externalImageCreateInfo;
|
|
}
|
|
|
|
if (vkCreateImage(device, &imageInfo, nullptr, &m_vkImage) != VK_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
VkMemoryRequirements memRequirements;
|
|
vkGetImageMemoryRequirements(device, m_vkImage, &memRequirements);
|
|
|
|
// Possible pNexts
|
|
wsi_memory_allocate_info wsiAllocInfo = {};
|
|
VkImportMemoryFdInfoKHR importMemoryInfo = {};
|
|
VkExportMemoryAllocateInfo memory_export_info = {};
|
|
VkMemoryDedicatedAllocateInfo memory_dedicated_info = {};
|
|
|
|
VkMemoryAllocateInfo allocInfo = {};
|
|
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
allocInfo.allocationSize = memRequirements.size;
|
|
allocInfo.memoryTypeIndex = findMemoryType(properties, memRequirements.memoryTypeBits );
|
|
|
|
if ( bFlippable == true || pDMA != nullptr )
|
|
{
|
|
memory_dedicated_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
|
|
memory_dedicated_info.image = m_vkImage;
|
|
memory_dedicated_info.buffer = VK_NULL_HANDLE;
|
|
memory_dedicated_info.pNext = allocInfo.pNext;
|
|
|
|
allocInfo.pNext = &memory_dedicated_info;
|
|
}
|
|
|
|
if ( bFlippable == true )
|
|
{
|
|
wsiAllocInfo.sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA;
|
|
wsiAllocInfo.implicit_sync = true;
|
|
wsiAllocInfo.pNext = allocInfo.pNext;
|
|
|
|
allocInfo.pNext = &wsiAllocInfo;
|
|
|
|
memory_export_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
|
|
memory_export_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
|
|
memory_export_info.pNext = allocInfo.pNext;
|
|
|
|
allocInfo.pNext = &memory_export_info;
|
|
}
|
|
|
|
if ( pDMA != nullptr )
|
|
{
|
|
// Memory already provided by pDMA
|
|
importMemoryInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
|
|
importMemoryInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
|
|
importMemoryInfo.fd = pDMA->fd[0];
|
|
importMemoryInfo.pNext = allocInfo.pNext;
|
|
|
|
allocInfo.pNext = &importMemoryInfo;
|
|
}
|
|
|
|
if (vkAllocateMemory(device, &allocInfo, nullptr, &m_vkImageMemory) != VK_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
res = vkBindImageMemory(device, m_vkImage, m_vkImageMemory, 0);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
return false;
|
|
|
|
if ( bFlippable == true )
|
|
{
|
|
// We assume we own the memory when doing this right now.
|
|
// We could support the import scenario as well if needed
|
|
assert( bTextureable == false );
|
|
|
|
m_DMA.modifier = DRM_FORMAT_MOD_INVALID;
|
|
m_DMA.n_planes = 1;
|
|
m_DMA.width = width;
|
|
m_DMA.height = height;
|
|
m_DMA.format = VulkanFormatToDRM( 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;
|
|
}
|
|
|
|
VkImageViewCreateInfo createInfo = {};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
createInfo.image = m_vkImage;
|
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
createInfo.format = format;
|
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
createInfo.subresourceRange.baseMipLevel = 0;
|
|
createInfo.subresourceRange.levelCount = 1;
|
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
|
createInfo.subresourceRange.layerCount = 1;
|
|
|
|
res = vkCreateImageView(device, &createInfo, nullptr, &m_vkImageView);
|
|
if ( res != VK_SUCCESS )
|
|
return false;
|
|
|
|
m_bInitialized = true;
|
|
m_bFlippable = bFlippable;
|
|
|
|
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;
|
|
|
|
if ( BIsNested() == true )
|
|
{
|
|
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;
|
|
|
|
VkShaderModuleCreateInfo shaderModuleCreateInfo = {};
|
|
shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
shaderModuleCreateInfo.codeSize = composite_spv_len;
|
|
shaderModuleCreateInfo.pCode = (const uint32_t*)composite_spv;
|
|
|
|
VkResult res = vkCreateShaderModule( device, &shaderModuleCreateInfo, nullptr, &shaderModule );
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VkCommandPoolCreateInfo commandPoolCreateInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
.pNext = nullptr,
|
|
.flags = 0,
|
|
.queueFamilyIndex = queueFamilyIndex,
|
|
};
|
|
|
|
res = vkCreateCommandPool(device, &commandPoolCreateInfo, 0, &commandPool);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// probably hard to hit that even with 3 overlays, and a bunch of tracked windows
|
|
// famous last words
|
|
//#define k_nMaxSets 20
|
|
#define k_nMaxSets 2000 // don't have time to cache or free stuff
|
|
|
|
VkDescriptorPoolSize descriptorPoolSize[] = {
|
|
{
|
|
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
k_nMaxSets * 1,
|
|
},
|
|
{
|
|
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
|
k_nMaxSets * k_nMaxLayers,
|
|
},
|
|
{
|
|
VK_DESCRIPTOR_TYPE_SAMPLER,
|
|
k_nMaxSets * k_nMaxLayers,
|
|
},
|
|
};
|
|
|
|
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
nullptr,
|
|
.flags = 0,
|
|
.maxSets = k_nMaxSets,
|
|
.poolSizeCount = 3,
|
|
descriptorPoolSize
|
|
};
|
|
|
|
res = vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, 0, &descriptorPool);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
void fini_device()
|
|
{
|
|
vkDestroyDevice(device, 0);
|
|
}
|
|
|
|
void acquire_next_image( void )
|
|
{
|
|
vkAcquireNextImageKHR( device, swapChain, UINT64_MAX, VK_NULL_HANDLE, VK_NULL_HANDLE, &g_nSwapChainImageIndex );
|
|
}
|
|
|
|
void vulkan_present_to_window( void )
|
|
{
|
|
VkPresentInfoKHR presentInfo = {};
|
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
|
|
// presentInfo.waitSemaphoreCount = 1;
|
|
// presentInfo.pWaitSemaphores = signalSemaphores;
|
|
|
|
presentInfo.swapchainCount = 1;
|
|
presentInfo.pSwapchains = &swapChain;
|
|
|
|
presentInfo.pImageIndices = &g_nSwapChainImageIndex;
|
|
|
|
vkQueuePresentKHR( queue, &presentInfo );
|
|
|
|
acquire_next_image();
|
|
}
|
|
|
|
int vulkan_init(void)
|
|
{
|
|
VkResult result = VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
std::vector< const char * > vecEnabledInstanceExtensions;
|
|
vecEnabledInstanceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME );
|
|
|
|
vecEnabledInstanceExtensions.insert( vecEnabledInstanceExtensions.end(), g_vecSDLInstanceExts.begin(), g_vecSDLInstanceExts.end() );
|
|
|
|
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;
|
|
}
|
|
|
|
if ( BIsNested() == true )
|
|
{
|
|
SDL_Vulkan_CreateSurface( window, instance, &surface );
|
|
|
|
if ( surface == VK_NULL_HANDLE )
|
|
return 0;
|
|
|
|
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( physicalDevice, surface, &surfaceCaps );
|
|
|
|
if ( result != VK_SUCCESS )
|
|
return 0;
|
|
|
|
uint32_t formatCount = 0;
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, surface, &formatCount, nullptr );
|
|
|
|
if ( result != VK_SUCCESS )
|
|
return 0;
|
|
|
|
if ( formatCount != 0 ) {
|
|
surfaceFormats.resize( formatCount );
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, surface, &formatCount, surfaceFormats.data() );
|
|
|
|
if ( result != VK_SUCCESS )
|
|
return 0;
|
|
}
|
|
|
|
uint32_t presentModeCount = 0;
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr );
|
|
|
|
if ( result != VK_SUCCESS )
|
|
return 0;
|
|
|
|
if ( presentModeCount != 0 ) {
|
|
presentModes.resize(presentModeCount);
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR( physicalDevice, surface, &presentModeCount, presentModes.data() );
|
|
|
|
if ( result != VK_SUCCESS )
|
|
return 0;
|
|
}
|
|
|
|
uint32_t imageCount = surfaceCaps.minImageCount + 1;
|
|
|
|
VkSwapchainCreateInfoKHR createInfo = {};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
createInfo.surface = surface;
|
|
|
|
createInfo.minImageCount = imageCount;
|
|
createInfo.imageFormat = surfaceFormats[0].format;
|
|
createInfo.imageColorSpace = surfaceFormats[0].colorSpace;
|
|
createInfo.imageExtent = { g_nOutputWidth, g_nOutputHeight };
|
|
createInfo.imageArrayLayers = 1;
|
|
createInfo.imageUsage = VK_IMAGE_USAGE_STORAGE_BIT;
|
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
createInfo.preTransform = surfaceCaps.currentTransform;
|
|
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
createInfo.presentMode = presentModes[0];
|
|
createInfo.clipped = VK_TRUE;
|
|
|
|
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
|
|
|
if (vkCreateSwapchainKHR( device, &createInfo, nullptr, &swapChain) != VK_SUCCESS ) {
|
|
return 0;
|
|
}
|
|
|
|
vkGetSwapchainImagesKHR( device, swapChain, &imageCount, nullptr );
|
|
swapChainImages.resize( imageCount );
|
|
swapChainImageViews.resize( imageCount );
|
|
vkGetSwapchainImagesKHR( device, swapChain, &imageCount, swapChainImages.data() );
|
|
|
|
for ( uint32_t i = 0; i < swapChainImages.size(); i++ )
|
|
{
|
|
VkImageViewCreateInfo createInfo = {};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
createInfo.image = swapChainImages[ i ];
|
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
createInfo.format = surfaceFormats[ 0 ].format;
|
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
createInfo.subresourceRange.baseMipLevel = 0;
|
|
createInfo.subresourceRange.levelCount = 1;
|
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
|
createInfo.subresourceRange.layerCount = 1;
|
|
|
|
result = vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[ i ]);
|
|
|
|
if ( result != VK_SUCCESS )
|
|
return false;
|
|
}
|
|
|
|
acquire_next_image();
|
|
}
|
|
|
|
dyn_vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr( device, "vkGetMemoryFdKHR" );
|
|
if ( dyn_vkGetMemoryFdKHR == nullptr )
|
|
return 0;
|
|
|
|
|
|
if ( BIsNested() == false )
|
|
{
|
|
VkFormat imageFormat = DRMFormatToVulkan( g_nDRMFormat );
|
|
|
|
if ( imageFormat == VK_FORMAT_UNDEFINED )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bool bSuccess = outputImage[0].BInit( g_nOutputWidth, g_nOutputHeight, imageFormat, true, false );
|
|
|
|
if ( bSuccess != true )
|
|
return 0;
|
|
|
|
bSuccess = outputImage[1].BInit( g_nOutputWidth, g_nOutputHeight, imageFormat, true, false );
|
|
|
|
if ( bSuccess != true )
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
VulkanTexture_t vulkan_create_texture_from_dmabuf( struct wlr_dmabuf_attributes *pDMA )
|
|
{
|
|
VulkanTexture_t ret = 0;
|
|
|
|
CVulkanTexture *pTex = new CVulkanTexture();
|
|
|
|
if ( pTex->BInit( pDMA->width, pDMA->height, DRMFormatToVulkan( pDMA->format ), false, true, pDMA ) == false )
|
|
{
|
|
delete pTex;
|
|
return ret;
|
|
}
|
|
|
|
ret = ++g_nMaxVulkanTexHandle;
|
|
g_mapVulkanTextures[ ret ] = pTex;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void vulkan_free_texture( VulkanTexture_t vulkanTex )
|
|
{
|
|
if ( vulkanTex == 0 )
|
|
return;
|
|
|
|
assert( g_mapVulkanTextures[ vulkanTex ] != nullptr );
|
|
|
|
// actually free something at some point
|
|
}
|
|
|
|
bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
|
|
{
|
|
CVulkanTexture *pTex[ k_nMaxLayers ] = {};
|
|
uint32_t nTexCount = 0;
|
|
|
|
for ( uint32_t i = 0; i < k_nMaxLayers; i ++ )
|
|
{
|
|
if ( pPipeline->layerBindings[ i ].tex != 0 )
|
|
{
|
|
pTex[ i ] = g_mapVulkanTextures[ pPipeline->layerBindings[ i ].tex ];
|
|
assert( pTex[ i ] );
|
|
|
|
nTexCount++;
|
|
}
|
|
}
|
|
|
|
std::vector< VkDescriptorSetLayoutBinding > vecLayoutBindings;
|
|
VkDescriptorSetLayoutBinding descriptorSetLayoutBindings =
|
|
{
|
|
.binding = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
.descriptorCount = 1,
|
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
};
|
|
|
|
vecLayoutBindings.push_back( descriptorSetLayoutBindings ); // first binding is target storage image
|
|
|
|
for ( uint32_t i = 0; i < nTexCount; i++ )
|
|
{
|
|
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
|
descriptorSetLayoutBindings.binding = 1 + ( i * 2 );
|
|
vecLayoutBindings.push_back( descriptorSetLayoutBindings );
|
|
|
|
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
|
descriptorSetLayoutBindings.binding = 1 + ( i * 2 ) + 1;
|
|
vecLayoutBindings.push_back( descriptorSetLayoutBindings );
|
|
}
|
|
|
|
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
.pNext = nullptr,
|
|
.flags = 0,
|
|
.bindingCount = 1 + ( nTexCount * 2 ),
|
|
vecLayoutBindings.data()
|
|
};
|
|
|
|
VkDescriptorSetLayout descriptorSetLayout;
|
|
VkResult res = vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, 0, &descriptorSetLayout);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
0,
|
|
0,
|
|
1,
|
|
&descriptorSetLayout,
|
|
0,
|
|
0
|
|
};
|
|
|
|
VkPipelineLayout pipelineLayout;
|
|
res = vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, 0, &pipelineLayout);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VkComputePipelineCreateInfo computePipelineCreateInfo = {
|
|
VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
|
0,
|
|
0,
|
|
{
|
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
0,
|
|
0,
|
|
VK_SHADER_STAGE_COMPUTE_BIT,
|
|
shaderModule,
|
|
"main",
|
|
0
|
|
},
|
|
pipelineLayout,
|
|
0,
|
|
0
|
|
};
|
|
|
|
VkPipeline pipeline;
|
|
res = vkCreateComputePipelines(device, 0, 1, &computePipelineCreateInfo, 0, &pipeline);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
nullptr,
|
|
descriptorPool,
|
|
1,
|
|
&descriptorSetLayout
|
|
};
|
|
|
|
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
|
res = vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet);
|
|
|
|
if ( res != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
{
|
|
VkDescriptorImageInfo imageInfo = {
|
|
.imageView = BIsNested() ? swapChainImageViews[ g_nSwapChainImageIndex ] : outputImage[ g_nOutImage ].m_vkImageView,
|
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL
|
|
};
|
|
|
|
VkWriteDescriptorSet writeDescriptorSet = {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.pNext = nullptr,
|
|
.dstSet = descriptorSet,
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
.pImageInfo = &imageInfo,
|
|
.pBufferInfo = nullptr,
|
|
.pTexelBufferView = nullptr,
|
|
};
|
|
|
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
|
}
|
|
|
|
for ( uint32_t i = 0; i < nTexCount; i++ )
|
|
{
|
|
VkSampler sampler = VK_NULL_HANDLE;
|
|
|
|
VkSamplerCreateInfo samplerCreateInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
.pNext = nullptr,
|
|
.magFilter = pPipeline->layerBindings[ i ].bFilter ? VK_FILTER_LINEAR : VK_FILTER_NEAREST,
|
|
.minFilter = pPipeline->layerBindings[ i ].bFilter ? VK_FILTER_LINEAR : VK_FILTER_NEAREST,
|
|
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
|
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
|
.unnormalizedCoordinates = VK_TRUE,
|
|
};
|
|
|
|
res = vkCreateSampler( device, &samplerCreateInfo, nullptr, &sampler );
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
{
|
|
VkDescriptorImageInfo imageInfo = {
|
|
.imageView = pTex[ i ]->m_vkImageView,
|
|
// TODO figure out what it is exactly for the wayland surfaces
|
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
};
|
|
|
|
VkWriteDescriptorSet writeDescriptorSet = {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.pNext = nullptr,
|
|
.dstSet = descriptorSet,
|
|
.dstBinding = 1 + (i * 2),
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
|
.pImageInfo = &imageInfo,
|
|
.pBufferInfo = nullptr,
|
|
.pTexelBufferView = nullptr,
|
|
};
|
|
|
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
|
}
|
|
|
|
{
|
|
VkDescriptorImageInfo imageInfo = {
|
|
.sampler = sampler,
|
|
};
|
|
|
|
VkWriteDescriptorSet writeDescriptorSet = {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.pNext = nullptr,
|
|
.dstSet = descriptorSet,
|
|
.dstBinding = 1 + (i * 2) + 1,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
|
|
.pImageInfo = &imageInfo,
|
|
.pBufferInfo = nullptr,
|
|
.pTexelBufferView = nullptr,
|
|
};
|
|
|
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
|
}
|
|
}
|
|
|
|
VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
|
|
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
0,
|
|
commandPool,
|
|
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
1
|
|
};
|
|
|
|
VkCommandBuffer commandBuffer;
|
|
res = vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, &commandBuffer);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VkCommandBufferBeginInfo commandBufferBeginInfo = {
|
|
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
0,
|
|
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
0
|
|
};
|
|
|
|
res = vkBeginCommandBuffer(commandBuffer, &commandBufferBeginInfo);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
|
|
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
|
|
pipelineLayout, 0, 1, &descriptorSet, 0, 0);
|
|
|
|
vkCmdDispatch(commandBuffer, g_nOutputWidth / 16, g_nOutputHeight / 16, 1);
|
|
|
|
res = vkEndCommandBuffer(commandBuffer);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VkSubmitInfo submitInfo = {
|
|
VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
&commandBuffer,
|
|
0,
|
|
0
|
|
};
|
|
|
|
res = vkQueueSubmit(queue, 1, &submitInfo, 0);
|
|
|
|
if ( res != VK_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
vkQueueWaitIdle( queue );
|
|
|
|
g_nOutImage = !g_nOutImage;
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t vulkan_get_last_composite_fbid( void )
|
|
{
|
|
return outputImage[ !g_nOutImage ].m_FBID;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|