mirror of https://github.com/AxioDL/boo.git
Xlib integration of Vulkan
This commit is contained in:
parent
f9c681bef9
commit
ae487b70f3
|
@ -125,12 +125,13 @@ else(NOT GEKKO)
|
||||||
include_directories(${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR})
|
include_directories(${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR})
|
||||||
list(APPEND _BOO_SYS_LIBS X11 Xi GL ${DBUS_LIBRARY} pthread)
|
list(APPEND _BOO_SYS_LIBS X11 Xi GL ${DBUS_LIBRARY} pthread)
|
||||||
|
|
||||||
|
unset(VULKAN_LIBRARY CACHE)
|
||||||
find_library(VULKAN_LIBRARY vulkan)
|
find_library(VULKAN_LIBRARY vulkan)
|
||||||
if(NOT VULKAN_LIBRARY-NOTFOUND)
|
if(NOT (VULKAN_LIBRARY STREQUAL VULKAN_LIBRARY-NOTFOUND))
|
||||||
message(STATUS "Vulkan loader found; enabling Vulkan support")
|
message(STATUS "Vulkan loader found; enabling Vulkan support")
|
||||||
|
list(APPEND _BOO_SYS_DEFINES -DBOO_HAS_VULKAN=1)
|
||||||
list(APPEND _BOO_SYS_LIBS ${VULKAN_LIBRARY})
|
list(APPEND _BOO_SYS_LIBS ${VULKAN_LIBRARY})
|
||||||
list(APPEND PLAT_SRCS
|
list(APPEND PLAT_SRCS lib/graphicsdev/Vulkan.cpp)
|
||||||
lib/graphicsdev/Vulkan.cpp)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef GDEV_VULKAN_HPP
|
#ifndef GDEV_VULKAN_HPP
|
||||||
#define GDEV_VULKAN_HPP
|
#define GDEV_VULKAN_HPP
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
|
||||||
#include "IGraphicsDataFactory.hpp"
|
#include "IGraphicsDataFactory.hpp"
|
||||||
#include "IGraphicsCommandQueue.hpp"
|
#include "IGraphicsCommandQueue.hpp"
|
||||||
|
@ -15,11 +16,18 @@ namespace boo
|
||||||
|
|
||||||
struct VulkanContext
|
struct VulkanContext
|
||||||
{
|
{
|
||||||
VkInstance m_instance;
|
std::vector<const char*> m_instanceLayerNames;
|
||||||
VkPhysicalDevice m_adapter;
|
std::vector<const char*> m_instanceExtensionNames;
|
||||||
VkPhysicalDeviceProperties m_devProps;
|
VkInstance m_instance = VK_NULL_HANDLE;
|
||||||
|
std::vector<const char*> m_deviceLayerNames;
|
||||||
|
std::vector<const char*> m_deviceExtensionNames;
|
||||||
|
std::vector<VkPhysicalDevice> m_gpus;
|
||||||
|
VkPhysicalDeviceProperties m_gpuProps;
|
||||||
VkPhysicalDeviceMemoryProperties m_memoryProperties;
|
VkPhysicalDeviceMemoryProperties m_memoryProperties;
|
||||||
VkDevice m_dev;
|
VkDevice m_dev;
|
||||||
|
uint32_t m_queueCount;
|
||||||
|
uint32_t m_graphicsQueueFamilyIndex = UINT32_MAX;
|
||||||
|
std::vector<VkQueueFamilyProperties> m_queueProps;
|
||||||
VkQueue m_queue;
|
VkQueue m_queue;
|
||||||
VkDescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
VkPipelineLayout m_layout;
|
VkPipelineLayout m_layout;
|
||||||
|
@ -30,18 +38,28 @@ struct VulkanContext
|
||||||
VkSampler m_linearSampler;
|
VkSampler m_linearSampler;
|
||||||
struct Window
|
struct Window
|
||||||
{
|
{
|
||||||
VkSwapchainKHR m_swapChain;
|
VkSwapchainKHR m_swapChain = VK_NULL_HANDLE;
|
||||||
struct Buffer
|
struct Buffer
|
||||||
{
|
{
|
||||||
VkImage m_image;
|
VkImage m_image;
|
||||||
VkImageView m_view;
|
VkImageView m_view;
|
||||||
|
void destroy(VkDevice dev)
|
||||||
|
{
|
||||||
|
vkDestroyImageView(dev, m_view, nullptr);
|
||||||
|
vkDestroyImage(dev, m_image, nullptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
std::vector<Buffer> m_bufs;
|
std::vector<Buffer> m_bufs;
|
||||||
uint32_t m_backBuf = 0;
|
uint32_t m_backBuf = 0;
|
||||||
size_t width, height;
|
size_t width, height;
|
||||||
};
|
};
|
||||||
std::unordered_map<const boo::IWindow*, Window> m_windows;
|
std::unordered_map<const boo::IWindow*, std::unique_ptr<Window>> m_windows;
|
||||||
|
|
||||||
|
void initVulkan(const char* appName);
|
||||||
|
void initDevice();
|
||||||
|
void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format);
|
||||||
};
|
};
|
||||||
|
extern VulkanContext g_VulkanContext;
|
||||||
|
|
||||||
class VulkanDataFactory : public IGraphicsDataFactory
|
class VulkanDataFactory : public IGraphicsDataFactory
|
||||||
{
|
{
|
||||||
|
@ -106,4 +124,5 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif // GDEV_VULKAN_HPP
|
#endif // GDEV_VULKAN_HPP
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
#else
|
||||||
|
#define VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "boo/graphicsdev/Vulkan.hpp"
|
#include "boo/graphicsdev/Vulkan.hpp"
|
||||||
#include "boo/IGraphicsContext.hpp"
|
#include "boo/IGraphicsContext.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -8,6 +14,7 @@
|
||||||
|
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
#undef None
|
||||||
|
|
||||||
#define MAX_UNIFORM_COUNT 8
|
#define MAX_UNIFORM_COUNT 8
|
||||||
#define MAX_TEXTURE_COUNT 8
|
#define MAX_TEXTURE_COUNT 8
|
||||||
|
@ -114,6 +121,7 @@ static const TBuiltInResource DefaultBuiltInResource =
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
static LogVisor::LogModule Log("boo::Vulkan");
|
static LogVisor::LogModule Log("boo::Vulkan");
|
||||||
|
VulkanContext g_VulkanContext;
|
||||||
|
|
||||||
static inline void ThrowIfFailed(VkResult res)
|
static inline void ThrowIfFailed(VkResult res)
|
||||||
{
|
{
|
||||||
|
@ -127,6 +135,342 @@ static inline void ThrowIfFalse(bool res)
|
||||||
Log.report(LogVisor::FatalError, "operation failed\n", res);
|
Log.report(LogVisor::FatalError, "operation failed\n", res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool MemoryTypeFromProperties(VulkanContext* ctx, uint32_t typeBits,
|
||||||
|
VkFlags requirementsMask,
|
||||||
|
uint32_t *typeIndex)
|
||||||
|
{
|
||||||
|
/* Search memtypes to find first index with those properties */
|
||||||
|
for (uint32_t i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
if ((typeBits & 1) == 1)
|
||||||
|
{
|
||||||
|
/* Type is available, does it match user properties? */
|
||||||
|
if ((ctx->m_memoryProperties.memoryTypes[i].propertyFlags &
|
||||||
|
requirementsMask) == requirementsMask) {
|
||||||
|
*typeIndex = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typeBits >>= 1;
|
||||||
|
}
|
||||||
|
/* No memory types matched, return failure */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetImageLayout(VkCommandBuffer cmd, VkImage image,
|
||||||
|
VkImageAspectFlags aspectMask,
|
||||||
|
VkImageLayout old_image_layout,
|
||||||
|
VkImageLayout new_image_layout)
|
||||||
|
{
|
||||||
|
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||||
|
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
imageMemoryBarrier.pNext = NULL;
|
||||||
|
imageMemoryBarrier.srcAccessMask = 0;
|
||||||
|
imageMemoryBarrier.dstAccessMask = 0;
|
||||||
|
imageMemoryBarrier.oldLayout = old_image_layout;
|
||||||
|
imageMemoryBarrier.newLayout = new_image_layout;
|
||||||
|
imageMemoryBarrier.image = image;
|
||||||
|
imageMemoryBarrier.subresourceRange.aspectMask = aspectMask;
|
||||||
|
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||||
|
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
if (old_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||||
|
imageMemoryBarrier.srcAccessMask =
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||||
|
/* Make sure anything that was copying from this image has completed */
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||||
|
/* Make sure any Copy or CPU writes to image are flushed */
|
||||||
|
imageMemoryBarrier.srcAccessMask =
|
||||||
|
VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||||
|
imageMemoryBarrier.dstAccessMask =
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||||
|
imageMemoryBarrier.dstAccessMask =
|
||||||
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(cmd, src_stages, dest_stages, 0, 0, NULL, 0, NULL,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanContext::initVulkan(const char* appName)
|
||||||
|
{
|
||||||
|
/* need platform surface extensions */
|
||||||
|
m_instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
|
m_instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
|
#else
|
||||||
|
m_instanceExtensionNames.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* need swapchain device extension */
|
||||||
|
m_deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
|
||||||
|
/* create the instance */
|
||||||
|
VkApplicationInfo appInfo = {};
|
||||||
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
|
appInfo.pNext = nullptr;
|
||||||
|
appInfo.pApplicationName = appName;
|
||||||
|
appInfo.applicationVersion = 1;
|
||||||
|
appInfo.pEngineName = "libBoo";
|
||||||
|
appInfo.engineVersion = 1;
|
||||||
|
appInfo.apiVersion = VK_API_VERSION;
|
||||||
|
|
||||||
|
VkInstanceCreateInfo instInfo = {};
|
||||||
|
instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
|
instInfo.pNext = nullptr;
|
||||||
|
instInfo.flags = 0;
|
||||||
|
instInfo.pApplicationInfo = &appInfo;
|
||||||
|
instInfo.enabledLayerCount = m_instanceLayerNames.size();
|
||||||
|
instInfo.ppEnabledLayerNames = m_instanceLayerNames.size()
|
||||||
|
? m_instanceLayerNames.data()
|
||||||
|
: nullptr;
|
||||||
|
instInfo.enabledExtensionCount = m_instanceExtensionNames.size();
|
||||||
|
instInfo.ppEnabledExtensionNames = m_instanceExtensionNames.data();
|
||||||
|
|
||||||
|
ThrowIfFailed(vkCreateInstance(&instInfo, nullptr, &m_instance));
|
||||||
|
|
||||||
|
uint32_t gpuCount = 1;
|
||||||
|
ThrowIfFailed(vkEnumeratePhysicalDevices(m_instance, &gpuCount, nullptr));
|
||||||
|
assert(gpuCount);
|
||||||
|
m_gpus.resize(gpuCount);
|
||||||
|
|
||||||
|
ThrowIfFailed(vkEnumeratePhysicalDevices(m_instance, &gpuCount, m_gpus.data()));
|
||||||
|
assert(gpuCount >= 1);
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(m_gpus[0], &m_queueCount, nullptr);
|
||||||
|
assert(m_queueCount >= 1);
|
||||||
|
|
||||||
|
m_queueProps.resize(m_queueCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(m_gpus[0], &m_queueCount, m_queueProps.data());
|
||||||
|
assert(m_queueCount >= 1);
|
||||||
|
|
||||||
|
/* This is as good a place as any to do this */
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(m_gpus[0], &m_memoryProperties);
|
||||||
|
vkGetPhysicalDeviceProperties(m_gpus[0], &m_gpuProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanContext::initDevice()
|
||||||
|
{
|
||||||
|
if (m_graphicsQueueFamilyIndex == UINT32_MAX)
|
||||||
|
Log.report(LogVisor::FatalError,
|
||||||
|
"VulkanContext::m_graphicsQueueFamilyIndex hasn't been initialized");
|
||||||
|
|
||||||
|
/* create the device */
|
||||||
|
VkDeviceQueueCreateInfo queueInfo = {};
|
||||||
|
float queuePriorities[1] = {0.0};
|
||||||
|
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
queueInfo.pNext = nullptr;
|
||||||
|
queueInfo.queueCount = 1;
|
||||||
|
queueInfo.pQueuePriorities = queuePriorities;
|
||||||
|
queueInfo.queueFamilyIndex = m_graphicsQueueFamilyIndex;
|
||||||
|
|
||||||
|
VkDeviceCreateInfo deviceInfo = {};
|
||||||
|
deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
|
deviceInfo.pNext = nullptr;
|
||||||
|
deviceInfo.queueCreateInfoCount = 1;
|
||||||
|
deviceInfo.pQueueCreateInfos = &queueInfo;
|
||||||
|
deviceInfo.enabledLayerCount = m_deviceLayerNames.size();
|
||||||
|
deviceInfo.ppEnabledLayerNames =
|
||||||
|
deviceInfo.enabledLayerCount ? m_deviceLayerNames.data() : nullptr;
|
||||||
|
deviceInfo.enabledExtensionCount = m_deviceExtensionNames.size();
|
||||||
|
deviceInfo.ppEnabledExtensionNames =
|
||||||
|
deviceInfo.enabledExtensionCount ? m_deviceExtensionNames.data() : nullptr;
|
||||||
|
deviceInfo.pEnabledFeatures = nullptr;
|
||||||
|
|
||||||
|
ThrowIfFailed(vkCreateDevice(m_gpus[0], &deviceInfo, nullptr, &m_dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanContext::initSwapChain(VulkanContext::Window& windowCtx, VkSurfaceKHR surface, VkFormat format)
|
||||||
|
{
|
||||||
|
VkSurfaceCapabilitiesKHR surfCapabilities;
|
||||||
|
ThrowIfFailed(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpus[0], surface, &surfCapabilities));
|
||||||
|
|
||||||
|
uint32_t presentModeCount;
|
||||||
|
ThrowIfFailed(vkGetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, nullptr));
|
||||||
|
VkPresentModeKHR* presentModes = (VkPresentModeKHR*)malloc(presentModeCount * sizeof(VkPresentModeKHR));
|
||||||
|
|
||||||
|
ThrowIfFailed(vkGetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, presentModes));
|
||||||
|
|
||||||
|
VkExtent2D swapChainExtent;
|
||||||
|
// width and height are either both -1, or both not -1.
|
||||||
|
if (surfCapabilities.currentExtent.width == (uint32_t)-1)
|
||||||
|
{
|
||||||
|
// If the surface size is undefined, the size is set to
|
||||||
|
// the size of the images requested.
|
||||||
|
swapChainExtent.width = 50;
|
||||||
|
swapChainExtent.height = 50;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the surface size is defined, the swap chain size must match
|
||||||
|
swapChainExtent = surfCapabilities.currentExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If mailbox mode is available, use it, as is the lowest-latency non-
|
||||||
|
// tearing mode. If not, try IMMEDIATE which will usually be available,
|
||||||
|
// and is fastest (though it tears). If not, fall back to FIFO which is
|
||||||
|
// always available.
|
||||||
|
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
for (size_t i=0 ; i<presentModeCount ; ++i)
|
||||||
|
{
|
||||||
|
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||||
|
{
|
||||||
|
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) &&
|
||||||
|
(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR))
|
||||||
|
{
|
||||||
|
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the number of VkImage's to use in the swap chain (we desire to
|
||||||
|
// own only 1 image at a time, besides the images being displayed and
|
||||||
|
// queued for display):
|
||||||
|
uint32_t desiredNumberOfSwapChainImages = surfCapabilities.minImageCount + 1;
|
||||||
|
if ((surfCapabilities.maxImageCount > 0) &&
|
||||||
|
(desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount))
|
||||||
|
{
|
||||||
|
// Application must settle for fewer images than desired:
|
||||||
|
desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceTransformFlagBitsKHR preTransform;
|
||||||
|
if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
|
||||||
|
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||||
|
else
|
||||||
|
preTransform = surfCapabilities.currentTransform;
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR swapChainInfo = {};
|
||||||
|
swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
swapChainInfo.pNext = nullptr;
|
||||||
|
swapChainInfo.surface = surface;
|
||||||
|
swapChainInfo.minImageCount = desiredNumberOfSwapChainImages;
|
||||||
|
swapChainInfo.imageFormat = format;
|
||||||
|
swapChainInfo.imageExtent.width = swapChainExtent.width;
|
||||||
|
swapChainInfo.imageExtent.height = swapChainExtent.height;
|
||||||
|
swapChainInfo.preTransform = preTransform;
|
||||||
|
swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
swapChainInfo.imageArrayLayers = 1;
|
||||||
|
swapChainInfo.presentMode = swapchainPresentMode;
|
||||||
|
swapChainInfo.oldSwapchain = nullptr;
|
||||||
|
swapChainInfo.clipped = true;
|
||||||
|
swapChainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
|
||||||
|
swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
swapChainInfo.queueFamilyIndexCount = 0;
|
||||||
|
swapChainInfo.pQueueFamilyIndices = nullptr;
|
||||||
|
|
||||||
|
ThrowIfFailed(vkCreateSwapchainKHR(m_dev, &swapChainInfo, nullptr, &windowCtx.m_swapChain));
|
||||||
|
|
||||||
|
uint32_t swapchainImageCount;
|
||||||
|
ThrowIfFailed(vkGetSwapchainImagesKHR(m_dev, windowCtx.m_swapChain, &swapchainImageCount, nullptr));
|
||||||
|
|
||||||
|
VkImage* swapchainImages = (VkImage*)malloc(swapchainImageCount * sizeof(VkImage));
|
||||||
|
ThrowIfFailed(vkGetSwapchainImagesKHR(m_dev, windowCtx.m_swapChain, &swapchainImageCount, swapchainImages));
|
||||||
|
|
||||||
|
windowCtx.m_bufs.resize(swapchainImageCount);
|
||||||
|
|
||||||
|
// Going to need a command buffer to send the memory barriers in
|
||||||
|
// set_image_layout but we couldn't have created one before we knew
|
||||||
|
// what our graphics_queue_family_index is, but now that we have it,
|
||||||
|
// create the command buffer
|
||||||
|
|
||||||
|
VkCommandPoolCreateInfo cmdPoolInfo = {};
|
||||||
|
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
cmdPoolInfo.pNext = nullptr;
|
||||||
|
cmdPoolInfo.queueFamilyIndex = m_graphicsQueueFamilyIndex;
|
||||||
|
cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
ThrowIfFailed(vkCreateCommandPool(m_dev, &cmdPoolInfo, nullptr, &m_loadPool));
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo cmd = {};
|
||||||
|
cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
cmd.pNext = nullptr;
|
||||||
|
cmd.commandPool = m_loadPool;
|
||||||
|
cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
cmd.commandBufferCount = 1;
|
||||||
|
ThrowIfFailed(vkAllocateCommandBuffers(m_dev, &cmd, &m_loadCmdBuf));
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo cmdBufBeginInfo = {};
|
||||||
|
cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
ThrowIfFailed(vkBeginCommandBuffer(m_loadCmdBuf, &cmdBufBeginInfo));
|
||||||
|
|
||||||
|
vkGetDeviceQueue(m_dev, m_graphicsQueueFamilyIndex, 0, &m_queue);
|
||||||
|
|
||||||
|
for (uint32_t i=0 ; i<swapchainImageCount ; ++i)
|
||||||
|
{
|
||||||
|
VkImageViewCreateInfo colorImageView = {};
|
||||||
|
colorImageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
colorImageView.pNext = nullptr;
|
||||||
|
colorImageView.format = format;
|
||||||
|
colorImageView.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||||
|
colorImageView.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||||
|
colorImageView.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||||
|
colorImageView.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||||
|
colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
colorImageView.subresourceRange.baseMipLevel = 0;
|
||||||
|
colorImageView.subresourceRange.levelCount = 1;
|
||||||
|
colorImageView.subresourceRange.baseArrayLayer = 0;
|
||||||
|
colorImageView.subresourceRange.layerCount = 1;
|
||||||
|
colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
colorImageView.flags = 0;
|
||||||
|
|
||||||
|
windowCtx.m_bufs[i].m_image = swapchainImages[i];
|
||||||
|
|
||||||
|
SetImageLayout(m_loadCmdBuf, windowCtx.m_bufs[i].m_image, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
colorImageView.image = windowCtx.m_bufs[i].m_image;
|
||||||
|
|
||||||
|
ThrowIfFailed(vkCreateImageView(m_dev, &colorImageView, nullptr, &windowCtx.m_bufs[i].m_view));
|
||||||
|
}
|
||||||
|
ThrowIfFailed(vkEndCommandBuffer(m_loadCmdBuf));
|
||||||
|
|
||||||
|
VkFenceCreateInfo fenceInfo;
|
||||||
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
ThrowIfFailed(vkCreateFence(m_dev, &fenceInfo, nullptr, &m_loadFence));
|
||||||
|
|
||||||
|
VkPipelineStageFlags pipeStageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||||
|
VkSubmitInfo submitInfo[1] = {};
|
||||||
|
submitInfo[0].pNext = nullptr;
|
||||||
|
submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submitInfo[0].waitSemaphoreCount = 0;
|
||||||
|
submitInfo[0].pWaitSemaphores = nullptr;
|
||||||
|
submitInfo[0].pWaitDstStageMask = &pipeStageFlags;
|
||||||
|
submitInfo[0].commandBufferCount = 1;
|
||||||
|
submitInfo[0].pCommandBuffers = &m_loadCmdBuf;
|
||||||
|
submitInfo[0].signalSemaphoreCount = 0;
|
||||||
|
submitInfo[0].pSignalSemaphores = nullptr;
|
||||||
|
|
||||||
|
ThrowIfFailed(vkQueueSubmit(m_queue, 1, submitInfo, m_loadFence));
|
||||||
|
ThrowIfFailed(vkWaitForFences(m_dev, 1, &m_loadFence, VK_TRUE, -1));
|
||||||
|
|
||||||
|
/* Reset fence and command buffer */
|
||||||
|
ThrowIfFailed(vkResetFences(m_dev, 1, &m_loadFence));
|
||||||
|
ThrowIfFailed(vkResetCommandBuffer(m_loadCmdBuf, 0));
|
||||||
|
ThrowIfFailed(vkBeginCommandBuffer(m_loadCmdBuf, &cmdBufBeginInfo));
|
||||||
|
}
|
||||||
|
|
||||||
struct VulkanData : IGraphicsData
|
struct VulkanData : IGraphicsData
|
||||||
{
|
{
|
||||||
VulkanContext* m_ctx;
|
VulkanContext* m_ctx;
|
||||||
|
@ -157,80 +501,6 @@ static const VkBufferUsageFlagBits USE_TABLE[] =
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool MemoryTypeFromProperties(VulkanContext* ctx, uint32_t typeBits,
|
|
||||||
VkFlags requirementsMask,
|
|
||||||
uint32_t *typeIndex)
|
|
||||||
{
|
|
||||||
/* Search memtypes to find first index with those properties */
|
|
||||||
for (uint32_t i = 0; i < 32; i++)
|
|
||||||
{
|
|
||||||
if ((typeBits & 1) == 1)
|
|
||||||
{
|
|
||||||
/* Type is available, does it match user properties? */
|
|
||||||
if ((ctx->m_memoryProperties.memoryTypes[i].propertyFlags &
|
|
||||||
requirementsMask) == requirementsMask) {
|
|
||||||
*typeIndex = i;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typeBits >>= 1;
|
|
||||||
}
|
|
||||||
/* No memory types matched, return failure */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SetImageLayout(VkCommandBuffer cmd, VkImage image,
|
|
||||||
VkImageAspectFlags aspectMask,
|
|
||||||
VkImageLayout old_image_layout,
|
|
||||||
VkImageLayout new_image_layout)
|
|
||||||
{
|
|
||||||
VkImageMemoryBarrier image_memory_barrier = {};
|
|
||||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
image_memory_barrier.pNext = NULL;
|
|
||||||
image_memory_barrier.srcAccessMask = 0;
|
|
||||||
image_memory_barrier.dstAccessMask = 0;
|
|
||||||
image_memory_barrier.oldLayout = old_image_layout;
|
|
||||||
image_memory_barrier.newLayout = new_image_layout;
|
|
||||||
image_memory_barrier.image = image;
|
|
||||||
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
|
|
||||||
image_memory_barrier.subresourceRange.baseMipLevel = 0;
|
|
||||||
image_memory_barrier.subresourceRange.levelCount = 1;
|
|
||||||
image_memory_barrier.subresourceRange.layerCount = 1;
|
|
||||||
|
|
||||||
if (old_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
|
||||||
image_memory_barrier.srcAccessMask =
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
|
||||||
/* Make sure anything that was copying from this image has completed */
|
|
||||||
image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
|
||||||
/* Make sure any Copy or CPU writes to image are flushed */
|
|
||||||
image_memory_barrier.srcAccessMask =
|
|
||||||
VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
|
||||||
image_memory_barrier.dstAccessMask =
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
|
||||||
image_memory_barrier.dstAccessMask =
|
|
||||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
|
||||||
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
|
||||||
|
|
||||||
vkCmdPipelineBarrier(cmd, src_stages, dest_stages, 0, 0, NULL, 0, NULL,
|
|
||||||
1, &image_memory_barrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
class VulkanGraphicsBufferS : public IGraphicsBufferS
|
class VulkanGraphicsBufferS : public IGraphicsBufferS
|
||||||
{
|
{
|
||||||
friend class VulkanDataFactory;
|
friend class VulkanDataFactory;
|
||||||
|
@ -267,11 +537,11 @@ public:
|
||||||
|
|
||||||
VkDeviceSize sizeForGPU(VulkanContext* ctx, uint32_t& memTypeBits, VkDeviceSize offset)
|
VkDeviceSize sizeForGPU(VulkanContext* ctx, uint32_t& memTypeBits, VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
if (m_uniform && ctx->m_devProps.limits.minUniformBufferOffsetAlignment)
|
if (m_uniform && ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment)
|
||||||
{
|
{
|
||||||
offset = (offset +
|
offset = (offset +
|
||||||
ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1) &
|
ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1) &
|
||||||
~(ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1);
|
~(ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
|
@ -334,11 +604,11 @@ public:
|
||||||
{
|
{
|
||||||
for (int i=0 ; i<2 ; ++i)
|
for (int i=0 ; i<2 ; ++i)
|
||||||
{
|
{
|
||||||
if (m_uniform && ctx->m_devProps.limits.minUniformBufferOffsetAlignment)
|
if (m_uniform && ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment)
|
||||||
{
|
{
|
||||||
offset = (offset +
|
offset = (offset +
|
||||||
ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1) &
|
ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1) &
|
||||||
~(ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1);
|
~(ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
|
|
|
@ -110,8 +110,8 @@ static Window GetWindowOfEvent(XEvent* event, bool& windowEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
IWindow* _WindowXlibNew(const std::string& title,
|
IWindow* _WindowXlibNew(const std::string& title,
|
||||||
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
||||||
GLXContext lastCtx);
|
GLXContext lastCtx, bool useVulkan);
|
||||||
|
|
||||||
static XIMStyle ChooseBetterStyle(XIMStyle style1, XIMStyle style2)
|
static XIMStyle ChooseBetterStyle(XIMStyle style1, XIMStyle style2)
|
||||||
{
|
{
|
||||||
|
@ -170,6 +170,9 @@ class ApplicationXlib final : public IApplication
|
||||||
XIMStyle m_bestStyle = 0;
|
XIMStyle m_bestStyle = 0;
|
||||||
int m_xDefaultScreen = 0;
|
int m_xDefaultScreen = 0;
|
||||||
int m_xcbFd, m_dbusFd, m_maxFd;
|
int m_xcbFd, m_dbusFd, m_maxFd;
|
||||||
|
|
||||||
|
/* Vulkan enable */
|
||||||
|
bool m_useVulkan = true;
|
||||||
|
|
||||||
void _deletedWindow(IWindow* window)
|
void _deletedWindow(IWindow* window)
|
||||||
{
|
{
|
||||||
|
@ -455,7 +458,8 @@ public:
|
||||||
|
|
||||||
IWindow* newWindow(const std::string& title)
|
IWindow* newWindow(const std::string& title)
|
||||||
{
|
{
|
||||||
IWindow* newWindow = _WindowXlibNew(title, m_xDisp, m_xDefaultScreen, m_xIM, m_bestStyle, m_fontset, m_lastGlxCtx);
|
IWindow* newWindow = _WindowXlibNew(title, m_xDisp, m_xDefaultScreen, m_xIM,
|
||||||
|
m_bestStyle, m_fontset, m_lastGlxCtx, m_useVulkan);
|
||||||
m_windows[(Window)newWindow->getPlatformHandle()] = newWindow;
|
m_windows[(Window)newWindow->getPlatformHandle()] = newWindow;
|
||||||
return newWindow;
|
return newWindow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include "boo/IApplication.hpp"
|
#include "boo/IApplication.hpp"
|
||||||
#include "boo/graphicsdev/GL.hpp"
|
#include "boo/graphicsdev/GL.hpp"
|
||||||
|
|
||||||
|
#define VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
#include "boo/graphicsdev/Vulkan.hpp"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -103,8 +106,13 @@ const size_t MAINICON_NETWM_SZ __attribute__ ((weak)) = 0;
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
static LogVisor::LogModule Log("boo::WindowXCB");
|
static LogVisor::LogModule Log("boo::WindowXlib");
|
||||||
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
|
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
IGraphicsCommandQueue* _NewVulkanCommandQueue(VulkanContext* ctx,
|
||||||
|
VulkanContext::Window* windowCtx,
|
||||||
|
IGraphicsContext* parent);
|
||||||
|
#endif
|
||||||
void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx);
|
void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx);
|
||||||
void GLXExtensionCheck();
|
void GLXExtensionCheck();
|
||||||
void GLXEnableVSync(Display* disp, GLXWindow drawable);
|
void GLXEnableVSync(Display* disp, GLXWindow drawable);
|
||||||
|
@ -264,13 +272,27 @@ static void genFrameDefault(Screen* screen, int& xOut, int& yOut, int& wOut, int
|
||||||
wOut = width;
|
wOut = width;
|
||||||
hOut = height;
|
hOut = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GraphicsContextGLX : IGraphicsContext
|
struct GraphicsContextXlib : IGraphicsContext
|
||||||
{
|
{
|
||||||
EGraphicsAPI m_api;
|
EGraphicsAPI m_api;
|
||||||
EPixelFormat m_pf;
|
EPixelFormat m_pf;
|
||||||
IWindow* m_parentWindow;
|
IWindow* m_parentWindow;
|
||||||
Display* m_xDisp = nullptr;
|
Display* m_xDisp;
|
||||||
|
|
||||||
|
std::mutex m_vsyncmt;
|
||||||
|
std::condition_variable m_vsynccv;
|
||||||
|
|
||||||
|
GraphicsContextXlib(EGraphicsAPI api, EPixelFormat pf, IWindow* parentWindow, Display* disp)
|
||||||
|
: m_api(api),
|
||||||
|
m_pf(pf),
|
||||||
|
m_parentWindow(parentWindow),
|
||||||
|
m_xDisp(disp) {}
|
||||||
|
virtual void destroy()=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GraphicsContextXlibGLX : GraphicsContextXlib
|
||||||
|
{
|
||||||
GLXContext m_lastCtx = 0;
|
GLXContext m_lastCtx = 0;
|
||||||
|
|
||||||
GLXFBConfig m_fbconfig = 0;
|
GLXFBConfig m_fbconfig = 0;
|
||||||
|
@ -289,13 +311,10 @@ struct GraphicsContextGLX : IGraphicsContext
|
||||||
public:
|
public:
|
||||||
IWindowCallback* m_callback;
|
IWindowCallback* m_callback;
|
||||||
|
|
||||||
GraphicsContextGLX(EGraphicsAPI api, IWindow* parentWindow,
|
GraphicsContextXlibGLX(EGraphicsAPI api, IWindow* parentWindow,
|
||||||
Display* display, int defaultScreen,
|
Display* display, int defaultScreen,
|
||||||
GLXContext lastCtx, uint32_t& visualIdOut)
|
GLXContext lastCtx, uint32_t& visualIdOut)
|
||||||
: m_api(api),
|
: GraphicsContextXlib(api, EPixelFormat::RGBA8, parentWindow, display),
|
||||||
m_pf(EPixelFormat::RGBA8_Z24),
|
|
||||||
m_parentWindow(parentWindow),
|
|
||||||
m_xDisp(display),
|
|
||||||
m_lastCtx(lastCtx)
|
m_lastCtx(lastCtx)
|
||||||
{
|
{
|
||||||
m_dataFactory = new class GLDataFactory(this);
|
m_dataFactory = new class GLDataFactory(this);
|
||||||
|
@ -383,7 +402,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~GraphicsContextGLX() {destroy();}
|
~GraphicsContextXlibGLX() {destroy();}
|
||||||
|
|
||||||
void _setCallback(IWindowCallback* cb)
|
void _setCallback(IWindowCallback* cb)
|
||||||
{
|
{
|
||||||
|
@ -407,9 +426,6 @@ public:
|
||||||
m_pf = pf;
|
m_pf = pf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::mutex m_vsyncmt;
|
|
||||||
std::condition_variable m_vsynccv;
|
|
||||||
|
|
||||||
void initializeContext()
|
void initializeContext()
|
||||||
{
|
{
|
||||||
if (!glXCreateContextAttribsARB)
|
if (!glXCreateContextAttribsARB)
|
||||||
|
@ -570,6 +586,302 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
struct GraphicsContextXlibVulkan : GraphicsContextXlib
|
||||||
|
{
|
||||||
|
VulkanContext* m_ctx;
|
||||||
|
VkSurfaceKHR m_surface;
|
||||||
|
VkFormat m_format;
|
||||||
|
|
||||||
|
GLXFBConfig m_fbconfig = 0;
|
||||||
|
int m_visualid = 0;
|
||||||
|
|
||||||
|
IGraphicsCommandQueue* m_commandQueue = nullptr;
|
||||||
|
IGraphicsDataFactory* m_dataFactory = nullptr;
|
||||||
|
|
||||||
|
std::thread m_vsyncThread;
|
||||||
|
bool m_vsyncRunning;
|
||||||
|
|
||||||
|
static void ThrowIfFailed(VkResult res)
|
||||||
|
{
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
Log.report(LogVisor::FatalError, "%d\n", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
IWindowCallback* m_callback;
|
||||||
|
|
||||||
|
GraphicsContextXlibVulkan(IWindow* parentWindow,
|
||||||
|
Display* display, int defaultScreen,
|
||||||
|
VulkanContext* ctx, uint32_t& visualIdOut)
|
||||||
|
: GraphicsContextXlib(EGraphicsAPI::Vulkan, EPixelFormat::RGBA8, parentWindow, display),
|
||||||
|
m_ctx(ctx)
|
||||||
|
{
|
||||||
|
if (ctx->m_instance == VK_NULL_HANDLE)
|
||||||
|
ctx->initVulkan(APP->getProcessName().c_str());
|
||||||
|
|
||||||
|
VulkanContext::Window& m_windowCtx =
|
||||||
|
*ctx->m_windows.emplace(std::make_pair(parentWindow,
|
||||||
|
std::make_unique<VulkanContext::Window>())).first->second;
|
||||||
|
m_dataFactory = new class VulkanDataFactory(this, ctx);
|
||||||
|
|
||||||
|
VkXlibSurfaceCreateInfoKHR surfaceInfo = {};
|
||||||
|
surfaceInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
|
||||||
|
surfaceInfo.dpy = display;
|
||||||
|
surfaceInfo.window = parentWindow->getPlatformHandle();
|
||||||
|
ThrowIfFailed(vkCreateXlibSurfaceKHR(ctx->m_instance, &surfaceInfo, nullptr, &m_surface));
|
||||||
|
|
||||||
|
/* Iterate over each queue to learn whether it supports presenting */
|
||||||
|
VkBool32 *supportsPresent = (VkBool32*)malloc(ctx->m_queueCount * sizeof(VkBool32));
|
||||||
|
for (uint32_t i=0 ; i<ctx->m_queueCount ; ++i)
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(ctx->m_gpus[0], i, m_surface, &supportsPresent[i]);
|
||||||
|
|
||||||
|
/* Search for a graphics queue and a present queue in the array of queue
|
||||||
|
* families, try to find one that supports both */
|
||||||
|
if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX)
|
||||||
|
{
|
||||||
|
/* First window, init device */
|
||||||
|
for (uint32_t i=0 ; i<ctx->m_queueCount; ++i)
|
||||||
|
{
|
||||||
|
if ((ctx->m_queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
|
||||||
|
{
|
||||||
|
if (supportsPresent[i] == VK_TRUE)
|
||||||
|
{
|
||||||
|
m_ctx->m_graphicsQueueFamilyIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate error if could not find a queue that supports both a graphics
|
||||||
|
* and present */
|
||||||
|
if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX)
|
||||||
|
Log.report(LogVisor::FatalError,
|
||||||
|
"Could not find a queue that supports both graphics and present");
|
||||||
|
|
||||||
|
m_ctx->initDevice();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Subsequent window, verify present */
|
||||||
|
if (supportsPresent[m_ctx->m_graphicsQueueFamilyIndex] == VK_FALSE)
|
||||||
|
Log.report(LogVisor::FatalError, "subsequent surface doesn't support present");
|
||||||
|
}
|
||||||
|
free(supportsPresent);
|
||||||
|
|
||||||
|
|
||||||
|
/* Get the list of VkFormats that are supported */
|
||||||
|
uint32_t formatCount;
|
||||||
|
ThrowIfFailed(vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->m_gpus[0], m_surface, &formatCount, nullptr));
|
||||||
|
VkSurfaceFormatKHR* surfFormats = (VkSurfaceFormatKHR*)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
|
||||||
|
ThrowIfFailed(vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->m_gpus[0], m_surface, &formatCount, surfFormats));
|
||||||
|
|
||||||
|
/* If the format list includes just one entry of VK_FORMAT_UNDEFINED,
|
||||||
|
* the surface has no preferred format. Otherwise, at least one
|
||||||
|
* supported format will be returned. */
|
||||||
|
if (formatCount >= 1)
|
||||||
|
{
|
||||||
|
if (surfFormats[0].format == VK_FORMAT_UNDEFINED)
|
||||||
|
m_format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
else
|
||||||
|
m_format = surfFormats[0].format;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log.report(LogVisor::FatalError, "no surface formats available for Vulkan swapchain");
|
||||||
|
|
||||||
|
|
||||||
|
/* Query framebuffer configurations */
|
||||||
|
GLXFBConfig* fbConfigs = nullptr;
|
||||||
|
int numFBConfigs = 0;
|
||||||
|
fbConfigs = glXGetFBConfigs(display, defaultScreen, &numFBConfigs);
|
||||||
|
if (!fbConfigs || numFBConfigs == 0)
|
||||||
|
{
|
||||||
|
Log.report(LogVisor::FatalError, "glXGetFBConfigs failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0 ; i<numFBConfigs ; ++i)
|
||||||
|
{
|
||||||
|
GLXFBConfig config = fbConfigs[i];
|
||||||
|
int visualId, depthSize, colorSize, doubleBuffer;
|
||||||
|
glXGetFBConfigAttrib(display, config, GLX_VISUAL_ID, &visualId);
|
||||||
|
glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize);
|
||||||
|
glXGetFBConfigAttrib(display, config, GLX_BUFFER_SIZE, &colorSize);
|
||||||
|
glXGetFBConfigAttrib(display, config, GLX_DOUBLEBUFFER, &doubleBuffer);
|
||||||
|
|
||||||
|
/* Double-buffer only */
|
||||||
|
if (!doubleBuffer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m_pf == EPixelFormat::RGBA8 && colorSize >= 32)
|
||||||
|
{
|
||||||
|
m_fbconfig = config;
|
||||||
|
m_visualid = visualId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (m_pf == EPixelFormat::RGBA8_Z24 && colorSize >= 32 && depthSize >= 24)
|
||||||
|
{
|
||||||
|
m_fbconfig = config;
|
||||||
|
m_visualid = visualId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (m_pf == EPixelFormat::RGBAF32 && colorSize >= 128)
|
||||||
|
{
|
||||||
|
m_fbconfig = config;
|
||||||
|
m_visualid = visualId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (m_pf == EPixelFormat::RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24)
|
||||||
|
{
|
||||||
|
m_fbconfig = config;
|
||||||
|
m_visualid = visualId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XFree(fbConfigs);
|
||||||
|
|
||||||
|
if (!m_fbconfig)
|
||||||
|
{
|
||||||
|
Log.report(LogVisor::FatalError, "unable to find suitable pixel format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vkGetPhysicalDeviceXlibPresentationSupportKHR(ctx->m_gpus[0], ctx->m_graphicsQueueFamilyIndex, display, m_visualid))
|
||||||
|
{
|
||||||
|
Log.report(LogVisor::FatalError, "unable to find vulkan-compatible pixel format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visualIdOut = m_visualid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy()
|
||||||
|
{
|
||||||
|
VulkanContext::Window& m_windowCtx = *m_ctx->m_windows[m_parentWindow];
|
||||||
|
vkDestroySwapchainKHR(m_ctx->m_dev, m_windowCtx.m_swapChain, nullptr);
|
||||||
|
vkDestroySurfaceKHR(m_ctx->m_instance, m_surface, nullptr);
|
||||||
|
for (VulkanContext::Window::Buffer& buf : m_windowCtx.m_bufs)
|
||||||
|
buf.destroy(m_ctx->m_dev);
|
||||||
|
m_windowCtx.m_bufs.clear();
|
||||||
|
|
||||||
|
if (m_vsyncRunning)
|
||||||
|
{
|
||||||
|
m_vsyncRunning = false;
|
||||||
|
m_vsyncThread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~GraphicsContextXlibVulkan() {destroy();}
|
||||||
|
|
||||||
|
void _setCallback(IWindowCallback* cb)
|
||||||
|
{
|
||||||
|
m_callback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGraphicsAPI getAPI() const
|
||||||
|
{
|
||||||
|
return m_api;
|
||||||
|
}
|
||||||
|
|
||||||
|
EPixelFormat getPixelFormat() const
|
||||||
|
{
|
||||||
|
return m_pf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPixelFormat(EPixelFormat pf)
|
||||||
|
{
|
||||||
|
if (pf > EPixelFormat::RGBAF32_Z24)
|
||||||
|
return;
|
||||||
|
m_pf = pf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initializeContext()
|
||||||
|
{
|
||||||
|
if (!glXWaitVideoSyncSGI)
|
||||||
|
{
|
||||||
|
glXWaitVideoSyncSGI = (glXWaitVideoSyncSGIProc)
|
||||||
|
glXGetProcAddressARB((const GLubyte*)"glXWaitVideoSyncSGI");
|
||||||
|
if (!glXWaitVideoSyncSGI)
|
||||||
|
Log.report(LogVisor::FatalError, "unable to resolve glXWaitVideoSyncSGI");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spawn vsync thread */
|
||||||
|
m_vsyncRunning = true;
|
||||||
|
std::mutex initmt;
|
||||||
|
std::condition_variable initcv;
|
||||||
|
std::unique_lock<std::mutex> outerLk(initmt);
|
||||||
|
m_vsyncThread = std::thread([&]()
|
||||||
|
{
|
||||||
|
Display* vsyncDisp;
|
||||||
|
GLXContext vsyncCtx;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> innerLk(initmt);
|
||||||
|
|
||||||
|
vsyncDisp = XOpenDisplay(0);
|
||||||
|
if (!vsyncDisp)
|
||||||
|
Log.report(LogVisor::FatalError, "unable to open new vsync display");
|
||||||
|
XLockDisplay(vsyncDisp);
|
||||||
|
|
||||||
|
static int attributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, 0 };
|
||||||
|
XVisualInfo *vi = glXChooseVisual(vsyncDisp, DefaultScreen(vsyncDisp), attributeList);
|
||||||
|
|
||||||
|
vsyncCtx = glXCreateContext(vsyncDisp, vi, nullptr, True);
|
||||||
|
if (!vsyncCtx)
|
||||||
|
Log.report(LogVisor::FatalError, "unable to make new vsync GLX context");
|
||||||
|
|
||||||
|
if (!glXMakeCurrent(vsyncDisp, DefaultRootWindow(vsyncDisp), vsyncCtx))
|
||||||
|
Log.report(LogVisor::FatalError, "unable to make vsync context current");
|
||||||
|
}
|
||||||
|
initcv.notify_one();
|
||||||
|
|
||||||
|
while (m_vsyncRunning)
|
||||||
|
{
|
||||||
|
unsigned int sync;
|
||||||
|
int err = glXWaitVideoSyncSGI(1, 0, &sync);
|
||||||
|
if (err)
|
||||||
|
Log.report(LogVisor::FatalError, "wait err");
|
||||||
|
m_vsynccv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
glXMakeCurrent(vsyncDisp, 0, nullptr);
|
||||||
|
glXDestroyContext(vsyncDisp, vsyncCtx);
|
||||||
|
XUnlockDisplay(vsyncDisp);
|
||||||
|
XCloseDisplay(vsyncDisp);
|
||||||
|
});
|
||||||
|
initcv.wait(outerLk);
|
||||||
|
|
||||||
|
m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeCurrent() {}
|
||||||
|
|
||||||
|
void postInit() {}
|
||||||
|
|
||||||
|
IGraphicsCommandQueue* getCommandQueue()
|
||||||
|
{
|
||||||
|
return m_commandQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IGraphicsDataFactory* getDataFactory()
|
||||||
|
{
|
||||||
|
return m_dataFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
IGraphicsDataFactory* getMainContextDataFactory()
|
||||||
|
{
|
||||||
|
return getDataFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
IGraphicsDataFactory* getLoadContextDataFactory()
|
||||||
|
{
|
||||||
|
return getDataFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
void present() {}
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
class WindowXlib : public IWindow
|
class WindowXlib : public IWindow
|
||||||
{
|
{
|
||||||
Display* m_xDisp;
|
Display* m_xDisp;
|
||||||
|
@ -578,7 +890,7 @@ class WindowXlib : public IWindow
|
||||||
Window m_windowId;
|
Window m_windowId;
|
||||||
XIMStyle m_bestStyle;
|
XIMStyle m_bestStyle;
|
||||||
XIC m_xIC = nullptr;
|
XIC m_xIC = nullptr;
|
||||||
GraphicsContextGLX m_gfxCtx;
|
std::unique_ptr<GraphicsContextXlib> m_gfxCtx;
|
||||||
uint32_t m_visualId;
|
uint32_t m_visualId;
|
||||||
|
|
||||||
/* Last known input device id (0xffff if not yet set) */
|
/* Last known input device id (0xffff if not yet set) */
|
||||||
|
@ -624,16 +936,22 @@ class WindowXlib : public IWindow
|
||||||
public:
|
public:
|
||||||
WindowXlib(const std::string& title,
|
WindowXlib(const std::string& title,
|
||||||
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
||||||
GLXContext lastCtx)
|
GLXContext lastCtx, bool useVulkan)
|
||||||
: m_xDisp(display), m_callback(nullptr),
|
: m_xDisp(display), m_callback(nullptr),
|
||||||
m_gfxCtx(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
|
|
||||||
this, display, defaultScreen,
|
|
||||||
lastCtx, m_visualId),
|
|
||||||
m_bestStyle(bestInputStyle)
|
m_bestStyle(bestInputStyle)
|
||||||
{
|
{
|
||||||
if (!S_ATOMS)
|
if (!S_ATOMS)
|
||||||
S_ATOMS = new XlibAtoms(display);
|
S_ATOMS = new XlibAtoms(display);
|
||||||
|
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
if (useVulkan)
|
||||||
|
m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, defaultScreen,
|
||||||
|
&g_VulkanContext, m_visualId));
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
m_gfxCtx.reset(new GraphicsContextXlibGLX(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
|
||||||
|
this, display, defaultScreen, lastCtx, m_visualId));
|
||||||
|
|
||||||
/* Default screen */
|
/* Default screen */
|
||||||
Screen* screen = ScreenOfDisplay(display, defaultScreen);
|
Screen* screen = ScreenOfDisplay(display, defaultScreen);
|
||||||
m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM;
|
m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM;
|
||||||
|
@ -726,13 +1044,13 @@ public:
|
||||||
setCursor(EMouseCursor::Pointer);
|
setCursor(EMouseCursor::Pointer);
|
||||||
XFlush(m_xDisp);
|
XFlush(m_xDisp);
|
||||||
|
|
||||||
m_gfxCtx.initializeContext();
|
m_gfxCtx->initializeContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
~WindowXlib()
|
~WindowXlib()
|
||||||
{
|
{
|
||||||
XLockDisplay(m_xDisp);
|
XLockDisplay(m_xDisp);
|
||||||
m_gfxCtx.destroy();
|
m_gfxCtx->destroy();
|
||||||
XUnmapWindow(m_xDisp, m_windowId);
|
XUnmapWindow(m_xDisp, m_windowId);
|
||||||
XDestroyWindow(m_xDisp, m_windowId);
|
XDestroyWindow(m_xDisp, m_windowId);
|
||||||
XFreeColormap(m_xDisp, m_colormapId);
|
XFreeColormap(m_xDisp, m_colormapId);
|
||||||
|
@ -1109,8 +1427,8 @@ public:
|
||||||
|
|
||||||
void waitForRetrace()
|
void waitForRetrace()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lk(m_gfxCtx.m_vsyncmt);
|
std::unique_lock<std::mutex> lk(m_gfxCtx->m_vsyncmt);
|
||||||
m_gfxCtx.m_vsynccv.wait(lk);
|
m_gfxCtx->m_vsynccv.wait(lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t getPlatformHandle() const
|
uintptr_t getPlatformHandle() const
|
||||||
|
@ -1594,22 +1912,22 @@ public:
|
||||||
|
|
||||||
IGraphicsCommandQueue* getCommandQueue()
|
IGraphicsCommandQueue* getCommandQueue()
|
||||||
{
|
{
|
||||||
return m_gfxCtx.getCommandQueue();
|
return m_gfxCtx->getCommandQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
IGraphicsDataFactory* getDataFactory()
|
IGraphicsDataFactory* getDataFactory()
|
||||||
{
|
{
|
||||||
return m_gfxCtx.getDataFactory();
|
return m_gfxCtx->getDataFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
IGraphicsDataFactory* getMainContextDataFactory()
|
IGraphicsDataFactory* getMainContextDataFactory()
|
||||||
{
|
{
|
||||||
return m_gfxCtx.getMainContextDataFactory();
|
return m_gfxCtx->getMainContextDataFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
IGraphicsDataFactory* getLoadContextDataFactory()
|
IGraphicsDataFactory* getLoadContextDataFactory()
|
||||||
{
|
{
|
||||||
return m_gfxCtx.getLoadContextDataFactory();
|
return m_gfxCtx->getLoadContextDataFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isWindowMapped()
|
bool _isWindowMapped()
|
||||||
|
@ -1624,10 +1942,10 @@ public:
|
||||||
|
|
||||||
IWindow* _WindowXlibNew(const std::string& title,
|
IWindow* _WindowXlibNew(const std::string& title,
|
||||||
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
||||||
GLXContext lastCtx)
|
GLXContext lastCtx, bool useVulkan)
|
||||||
{
|
{
|
||||||
XLockDisplay(display);
|
XLockDisplay(display);
|
||||||
IWindow* ret = new WindowXlib(title, display, defaultScreen, xIM, bestInputStyle, fontset, lastCtx);
|
IWindow* ret = new WindowXlib(title, display, defaultScreen, xIM, bestInputStyle, fontset, lastCtx, useVulkan);
|
||||||
XUnlockDisplay(display);
|
XUnlockDisplay(display);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue