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})
|
||||
list(APPEND _BOO_SYS_LIBS X11 Xi GL ${DBUS_LIBRARY} pthread)
|
||||
|
||||
unset(VULKAN_LIBRARY CACHE)
|
||||
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")
|
||||
list(APPEND _BOO_SYS_DEFINES -DBOO_HAS_VULKAN=1)
|
||||
list(APPEND _BOO_SYS_LIBS ${VULKAN_LIBRARY})
|
||||
list(APPEND PLAT_SRCS
|
||||
lib/graphicsdev/Vulkan.cpp)
|
||||
list(APPEND PLAT_SRCS lib/graphicsdev/Vulkan.cpp)
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef GDEV_VULKAN_HPP
|
||||
#define GDEV_VULKAN_HPP
|
||||
#if BOO_HAS_VULKAN
|
||||
|
||||
#include "IGraphicsDataFactory.hpp"
|
||||
#include "IGraphicsCommandQueue.hpp"
|
||||
|
@ -15,11 +16,18 @@ namespace boo
|
|||
|
||||
struct VulkanContext
|
||||
{
|
||||
VkInstance m_instance;
|
||||
VkPhysicalDevice m_adapter;
|
||||
VkPhysicalDeviceProperties m_devProps;
|
||||
std::vector<const char*> m_instanceLayerNames;
|
||||
std::vector<const char*> m_instanceExtensionNames;
|
||||
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;
|
||||
VkDevice m_dev;
|
||||
uint32_t m_queueCount;
|
||||
uint32_t m_graphicsQueueFamilyIndex = UINT32_MAX;
|
||||
std::vector<VkQueueFamilyProperties> m_queueProps;
|
||||
VkQueue m_queue;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkPipelineLayout m_layout;
|
||||
|
@ -30,18 +38,28 @@ struct VulkanContext
|
|||
VkSampler m_linearSampler;
|
||||
struct Window
|
||||
{
|
||||
VkSwapchainKHR m_swapChain;
|
||||
VkSwapchainKHR m_swapChain = VK_NULL_HANDLE;
|
||||
struct Buffer
|
||||
{
|
||||
VkImage m_image;
|
||||
VkImageView m_view;
|
||||
void destroy(VkDevice dev)
|
||||
{
|
||||
vkDestroyImageView(dev, m_view, nullptr);
|
||||
vkDestroyImage(dev, m_image, nullptr);
|
||||
}
|
||||
};
|
||||
std::vector<Buffer> m_bufs;
|
||||
uint32_t m_backBuf = 0;
|
||||
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
|
||||
{
|
||||
|
@ -106,4 +124,5 @@ public:
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
#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/IGraphicsContext.hpp"
|
||||
#include <vector>
|
||||
|
@ -8,6 +14,7 @@
|
|||
|
||||
#undef min
|
||||
#undef max
|
||||
#undef None
|
||||
|
||||
#define MAX_UNIFORM_COUNT 8
|
||||
#define MAX_TEXTURE_COUNT 8
|
||||
|
@ -114,6 +121,7 @@ static const TBuiltInResource DefaultBuiltInResource =
|
|||
namespace boo
|
||||
{
|
||||
static LogVisor::LogModule Log("boo::Vulkan");
|
||||
VulkanContext g_VulkanContext;
|
||||
|
||||
static inline void ThrowIfFailed(VkResult res)
|
||||
{
|
||||
|
@ -127,6 +135,342 @@ static inline void ThrowIfFalse(bool 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
|
||||
{
|
||||
VulkanContext* m_ctx;
|
||||
|
@ -157,80 +501,6 @@ static const VkBufferUsageFlagBits USE_TABLE[] =
|
|||
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
|
||||
{
|
||||
friend class VulkanDataFactory;
|
||||
|
@ -267,11 +537,11 @@ public:
|
|||
|
||||
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 +
|
||||
ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1) &
|
||||
~(ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1);
|
||||
ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1) &
|
||||
~(ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1);
|
||||
}
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
|
@ -334,11 +604,11 @@ public:
|
|||
{
|
||||
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 +
|
||||
ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1) &
|
||||
~(ctx->m_devProps.limits.minUniformBufferOffsetAlignment - 1);
|
||||
ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1) &
|
||||
~(ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1);
|
||||
}
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
|
|
|
@ -110,8 +110,8 @@ static Window GetWindowOfEvent(XEvent* event, bool& windowEvent)
|
|||
}
|
||||
|
||||
IWindow* _WindowXlibNew(const std::string& title,
|
||||
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
||||
GLXContext lastCtx);
|
||||
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
||||
GLXContext lastCtx, bool useVulkan);
|
||||
|
||||
static XIMStyle ChooseBetterStyle(XIMStyle style1, XIMStyle style2)
|
||||
{
|
||||
|
@ -171,6 +171,9 @@ class ApplicationXlib final : public IApplication
|
|||
int m_xDefaultScreen = 0;
|
||||
int m_xcbFd, m_dbusFd, m_maxFd;
|
||||
|
||||
/* Vulkan enable */
|
||||
bool m_useVulkan = true;
|
||||
|
||||
void _deletedWindow(IWindow* window)
|
||||
{
|
||||
m_windows.erase((Window)window->getPlatformHandle());
|
||||
|
@ -455,7 +458,8 @@ public:
|
|||
|
||||
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;
|
||||
return newWindow;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#include "boo/IApplication.hpp"
|
||||
#include "boo/graphicsdev/GL.hpp"
|
||||
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#include "boo/graphicsdev/Vulkan.hpp"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -103,8 +106,13 @@ const size_t MAINICON_NETWM_SZ __attribute__ ((weak)) = 0;
|
|||
|
||||
namespace boo
|
||||
{
|
||||
static LogVisor::LogModule Log("boo::WindowXCB");
|
||||
static LogVisor::LogModule Log("boo::WindowXlib");
|
||||
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
|
||||
#if BOO_HAS_VULKAN
|
||||
IGraphicsCommandQueue* _NewVulkanCommandQueue(VulkanContext* ctx,
|
||||
VulkanContext::Window* windowCtx,
|
||||
IGraphicsContext* parent);
|
||||
#endif
|
||||
void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx);
|
||||
void GLXExtensionCheck();
|
||||
void GLXEnableVSync(Display* disp, GLXWindow drawable);
|
||||
|
@ -265,12 +273,26 @@ static void genFrameDefault(Screen* screen, int& xOut, int& yOut, int& wOut, int
|
|||
hOut = height;
|
||||
}
|
||||
|
||||
struct GraphicsContextGLX : IGraphicsContext
|
||||
struct GraphicsContextXlib : IGraphicsContext
|
||||
{
|
||||
EGraphicsAPI m_api;
|
||||
EPixelFormat m_pf;
|
||||
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;
|
||||
|
||||
GLXFBConfig m_fbconfig = 0;
|
||||
|
@ -289,13 +311,10 @@ struct GraphicsContextGLX : IGraphicsContext
|
|||
public:
|
||||
IWindowCallback* m_callback;
|
||||
|
||||
GraphicsContextGLX(EGraphicsAPI api, IWindow* parentWindow,
|
||||
Display* display, int defaultScreen,
|
||||
GLXContext lastCtx, uint32_t& visualIdOut)
|
||||
: m_api(api),
|
||||
m_pf(EPixelFormat::RGBA8_Z24),
|
||||
m_parentWindow(parentWindow),
|
||||
m_xDisp(display),
|
||||
GraphicsContextXlibGLX(EGraphicsAPI api, IWindow* parentWindow,
|
||||
Display* display, int defaultScreen,
|
||||
GLXContext lastCtx, uint32_t& visualIdOut)
|
||||
: GraphicsContextXlib(api, EPixelFormat::RGBA8, parentWindow, display),
|
||||
m_lastCtx(lastCtx)
|
||||
{
|
||||
m_dataFactory = new class GLDataFactory(this);
|
||||
|
@ -383,7 +402,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
~GraphicsContextGLX() {destroy();}
|
||||
~GraphicsContextXlibGLX() {destroy();}
|
||||
|
||||
void _setCallback(IWindowCallback* cb)
|
||||
{
|
||||
|
@ -407,9 +426,6 @@ public:
|
|||
m_pf = pf;
|
||||
}
|
||||
|
||||
std::mutex m_vsyncmt;
|
||||
std::condition_variable m_vsynccv;
|
||||
|
||||
void initializeContext()
|
||||
{
|
||||
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
|
||||
{
|
||||
Display* m_xDisp;
|
||||
|
@ -578,7 +890,7 @@ class WindowXlib : public IWindow
|
|||
Window m_windowId;
|
||||
XIMStyle m_bestStyle;
|
||||
XIC m_xIC = nullptr;
|
||||
GraphicsContextGLX m_gfxCtx;
|
||||
std::unique_ptr<GraphicsContextXlib> m_gfxCtx;
|
||||
uint32_t m_visualId;
|
||||
|
||||
/* Last known input device id (0xffff if not yet set) */
|
||||
|
@ -624,16 +936,22 @@ class WindowXlib : public IWindow
|
|||
public:
|
||||
WindowXlib(const std::string& title,
|
||||
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
||||
GLXContext lastCtx)
|
||||
GLXContext lastCtx, bool useVulkan)
|
||||
: m_xDisp(display), m_callback(nullptr),
|
||||
m_gfxCtx(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
|
||||
this, display, defaultScreen,
|
||||
lastCtx, m_visualId),
|
||||
m_bestStyle(bestInputStyle)
|
||||
{
|
||||
if (!S_ATOMS)
|
||||
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 */
|
||||
Screen* screen = ScreenOfDisplay(display, defaultScreen);
|
||||
m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM;
|
||||
|
@ -726,13 +1044,13 @@ public:
|
|||
setCursor(EMouseCursor::Pointer);
|
||||
XFlush(m_xDisp);
|
||||
|
||||
m_gfxCtx.initializeContext();
|
||||
m_gfxCtx->initializeContext();
|
||||
}
|
||||
|
||||
~WindowXlib()
|
||||
{
|
||||
XLockDisplay(m_xDisp);
|
||||
m_gfxCtx.destroy();
|
||||
m_gfxCtx->destroy();
|
||||
XUnmapWindow(m_xDisp, m_windowId);
|
||||
XDestroyWindow(m_xDisp, m_windowId);
|
||||
XFreeColormap(m_xDisp, m_colormapId);
|
||||
|
@ -1109,8 +1427,8 @@ public:
|
|||
|
||||
void waitForRetrace()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_gfxCtx.m_vsyncmt);
|
||||
m_gfxCtx.m_vsynccv.wait(lk);
|
||||
std::unique_lock<std::mutex> lk(m_gfxCtx->m_vsyncmt);
|
||||
m_gfxCtx->m_vsynccv.wait(lk);
|
||||
}
|
||||
|
||||
uintptr_t getPlatformHandle() const
|
||||
|
@ -1594,22 +1912,22 @@ public:
|
|||
|
||||
IGraphicsCommandQueue* getCommandQueue()
|
||||
{
|
||||
return m_gfxCtx.getCommandQueue();
|
||||
return m_gfxCtx->getCommandQueue();
|
||||
}
|
||||
|
||||
IGraphicsDataFactory* getDataFactory()
|
||||
{
|
||||
return m_gfxCtx.getDataFactory();
|
||||
return m_gfxCtx->getDataFactory();
|
||||
}
|
||||
|
||||
IGraphicsDataFactory* getMainContextDataFactory()
|
||||
{
|
||||
return m_gfxCtx.getMainContextDataFactory();
|
||||
return m_gfxCtx->getMainContextDataFactory();
|
||||
}
|
||||
|
||||
IGraphicsDataFactory* getLoadContextDataFactory()
|
||||
{
|
||||
return m_gfxCtx.getLoadContextDataFactory();
|
||||
return m_gfxCtx->getLoadContextDataFactory();
|
||||
}
|
||||
|
||||
bool _isWindowMapped()
|
||||
|
@ -1624,10 +1942,10 @@ public:
|
|||
|
||||
IWindow* _WindowXlibNew(const std::string& title,
|
||||
Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset,
|
||||
GLXContext lastCtx)
|
||||
GLXContext lastCtx, bool useVulkan)
|
||||
{
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue