From 295d100ca3879016083b4fc20b45d0001e2fc13e Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Thu, 30 Jun 2016 16:30:29 -1000 Subject: [PATCH] Initial vulkan rendering within URDE --- include/boo/IGraphicsContext.hpp | 2 +- lib/graphicsdev/Vulkan.cpp | 54 ++++++++++++++++------------ lib/mac/WindowCocoa.mm | 6 ++-- lib/win/WindowWin32.cpp | 4 +-- lib/x11/ApplicationXlib.hpp | 62 +++++++++++++++++++++++++++++--- lib/x11/WindowWayland.cpp | 2 +- lib/x11/WindowXlib.cpp | 47 +++++------------------- 7 files changed, 104 insertions(+), 73 deletions(-) diff --git a/include/boo/IGraphicsContext.hpp b/include/boo/IGraphicsContext.hpp index 8d31fb2..c7bc534 100644 --- a/include/boo/IGraphicsContext.hpp +++ b/include/boo/IGraphicsContext.hpp @@ -45,7 +45,7 @@ public: virtual EGraphicsAPI getAPI() const=0; virtual EPixelFormat getPixelFormat() const=0; virtual void setPixelFormat(EPixelFormat pf)=0; - virtual void initializeContext()=0; + virtual void initializeContext(void* handle)=0; virtual void makeCurrent()=0; virtual void postInit()=0; virtual void present()=0; diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp index 2275471..f8f5d1b 100644 --- a/lib/graphicsdev/Vulkan.cpp +++ b/lib/graphicsdev/Vulkan.cpp @@ -654,12 +654,15 @@ class VulkanGraphicsBufferS : public IGraphicsBufferS bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufInfo.flags = 0; ThrowIfFailed(vk::CreateBuffer(ctx->m_dev, &bufInfo, nullptr, &m_bufferInfo.buffer)); + m_bufferInfo.offset = 0; + m_bufferInfo.range = m_sz; } public: size_t size() const {return m_sz;} size_t m_stride; size_t m_count; VkDescriptorBufferInfo m_bufferInfo; + VkDeviceSize m_memOffset; bool m_uniform = false; ~VulkanGraphicsBufferS() { @@ -668,30 +671,29 @@ public: VkDeviceSize sizeForGPU(VulkanContext* ctx, uint32_t& memTypeBits, VkDeviceSize offset) { - if (m_uniform && ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment) + if (m_uniform) { - offset = (offset + - ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1) & - ~(ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1); + size_t minOffset = std::max(VkDeviceSize(256), + ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment); + offset = (offset + minOffset - 1) & ~(minOffset - 1); } VkMemoryRequirements memReqs; vk::GetBufferMemoryRequirements(ctx->m_dev, m_bufferInfo.buffer, &memReqs); memTypeBits &= memReqs.memoryTypeBits; - m_bufferInfo.offset = offset; + m_memOffset = offset; offset += m_sz; offset = (offset + memReqs.alignment - 1) & ~(memReqs.alignment - 1); - m_bufferInfo.range = offset - m_bufferInfo.offset; return offset; } void placeForGPU(VulkanContext* ctx, VkDeviceMemory mem, uint8_t* buf) { - memmove(buf + m_bufferInfo.offset, m_stagingBuf.get(), m_sz); + memmove(buf + m_memOffset, m_stagingBuf.get(), m_sz); m_stagingBuf.reset(); - ThrowIfFailed(vk::BindBufferMemory(ctx->m_dev, m_bufferInfo.buffer, mem, m_bufferInfo.offset)); + ThrowIfFailed(vk::BindBufferMemory(ctx->m_dev, m_bufferInfo.buffer, mem, m_memOffset)); } }; @@ -718,6 +720,10 @@ class VulkanGraphicsBufferD : public IGraphicsBufferD bufInfo.flags = 0; ThrowIfFailed(vk::CreateBuffer(ctx->m_dev, &bufInfo, nullptr, &m_bufferInfo[0].buffer)); ThrowIfFailed(vk::CreateBuffer(ctx->m_dev, &bufInfo, nullptr, &m_bufferInfo[1].buffer)); + m_bufferInfo[0].offset = 0; + m_bufferInfo[0].range = m_cpuSz; + m_bufferInfo[1].offset = 0; + m_bufferInfo[1].range = m_cpuSz; } void update(int b); @@ -725,6 +731,7 @@ public: size_t m_stride; size_t m_count; VkDeviceMemory m_mem; + VkDeviceSize m_memOffset[2]; VkDescriptorBufferInfo m_bufferInfo[2]; bool m_uniform = false; ~VulkanGraphicsBufferD(); @@ -736,21 +743,20 @@ public: { for (int i=0 ; i<2 ; ++i) { - if (m_uniform && ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment) + if (m_uniform) { - offset = (offset + - ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1) & - ~(ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment - 1); + size_t minOffset = std::max(VkDeviceSize(256), + ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment); + offset = (offset + minOffset - 1) & ~(minOffset - 1); } VkMemoryRequirements memReqs; vk::GetBufferMemoryRequirements(ctx->m_dev, m_bufferInfo[i].buffer, &memReqs); memTypeBits &= memReqs.memoryTypeBits; - m_bufferInfo[i].offset = offset; + m_memOffset[i] = offset; offset += memReqs.size; offset = (offset + memReqs.alignment - 1) & ~(memReqs.alignment - 1); - m_bufferInfo[i].range = offset - m_bufferInfo[i].offset; } return offset; @@ -759,8 +765,8 @@ public: void placeForGPU(VulkanContext* ctx, VkDeviceMemory mem) { m_mem = mem; - ThrowIfFailed(vk::BindBufferMemory(ctx->m_dev, m_bufferInfo[0].buffer, mem, m_bufferInfo[0].offset)); - ThrowIfFailed(vk::BindBufferMemory(ctx->m_dev, m_bufferInfo[1].buffer, mem, m_bufferInfo[1].offset)); + ThrowIfFailed(vk::BindBufferMemory(ctx->m_dev, m_bufferInfo[0].buffer, mem, m_memOffset[0])); + ThrowIfFailed(vk::BindBufferMemory(ctx->m_dev, m_bufferInfo[1].buffer, mem, m_memOffset[1])); } }; @@ -1647,6 +1653,7 @@ class VulkanShaderPipeline : public IShaderPipeline { friend class VulkanDataFactory; VulkanContext* m_ctx; + VkPipelineCache m_pipelineCache; VulkanShaderPipeline(VulkanContext* ctx, VkShaderModule vert, VkShaderModule frag, @@ -1654,7 +1661,7 @@ class VulkanShaderPipeline : public IShaderPipeline const VulkanVertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) - : m_ctx(ctx) + : m_ctx(ctx), m_pipelineCache(pipelineCache) { VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE] = {}; VkPipelineDynamicStateCreateInfo dynamicState = {}; @@ -1770,6 +1777,7 @@ public: ~VulkanShaderPipeline() { vk::DestroyPipeline(m_ctx->m_dev, m_pipeline, nullptr); + vk::DestroyPipelineCache(m_ctx->m_dev, m_pipelineCache, nullptr); } VulkanShaderPipeline& operator=(const VulkanShaderPipeline&) = delete; VulkanShaderPipeline(const VulkanShaderPipeline&) = delete; @@ -1869,7 +1877,7 @@ struct VulkanShaderDataBinding : IShaderDataBinding IGraphicsBuffer* m_ibuf; size_t m_ubufCount; std::unique_ptr m_ubufs; - std::vector m_ubufOffs; + std::vector> m_ubufOffs; size_t m_texCount; std::unique_ptr m_texs; @@ -1911,7 +1919,9 @@ struct VulkanShaderDataBinding : IShaderDataBinding if (ubufOffs[i] % 256) Log.report(logvisor::Fatal, "non-256-byte-aligned uniform-offset %d provided to newShaderDataBinding", int(i)); #endif - m_ubufOffs.push_back({VK_NULL_HANDLE, ubufOffs[i], (ubufSizes[i] + 255) & ~255}); + std::array fillArr; + fillArr.fill({VK_NULL_HANDLE, ubufOffs[i], (ubufSizes[i] + 255) & ~255}); + m_ubufOffs.push_back(fillArr); } } for (size_t i=0 ; ibuffer; modInfo.offset += origInfo->offset; writes[totalWrites].pBufferInfo = &modInfo; @@ -2614,7 +2624,7 @@ void VulkanGraphicsBufferD::update(int b) { void* ptr; ThrowIfFailed(vk::MapMemory(m_q->m_ctx->m_dev, m_mem, - m_bufferInfo[b].offset, m_bufferInfo[b].range, 0, &ptr)); + m_memOffset[b], m_cpuSz, 0, &ptr)); memmove(ptr, m_cpuBuf.get(), m_cpuSz); vk::UnmapMemory(m_q->m_ctx->m_dev, m_mem); m_validSlots |= slot; @@ -2886,8 +2896,6 @@ IShaderPipeline* VulkanDataFactory::Context::newShaderPipeline } } - vk::DestroyPipelineCache(m_parent.m_ctx->m_dev, pipelineCache, nullptr); - vk::DestroyShaderModule(m_parent.m_ctx->m_dev, fragModule, nullptr); vk::DestroyShaderModule(m_parent.m_ctx->m_dev, vertModule, nullptr); diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm index 89e94e0..3bed422 100644 --- a/lib/mac/WindowCocoa.mm +++ b/lib/mac/WindowCocoa.mm @@ -219,7 +219,7 @@ public: m_pf = pf; } - void initializeContext() + void initializeContext(void*) { m_nsContext = [[GraphicsContextCocoaGLInternal alloc] initWithBooContext:this]; if (!m_nsContext) @@ -375,7 +375,7 @@ public: m_pf = pf; } - void initializeContext() + void initializeContext(void*) { MetalContext::Window& w = m_metalCtx->m_windows[m_parentWindow]; m_nsContext = [[GraphicsContextCocoaMetalInternal alloc] initWithBooContext:this]; @@ -1246,7 +1246,7 @@ public: #endif m_gfxCtx = static_cast(_GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this, lastGLCtx, sampleCount)); - m_gfxCtx->initializeContext(); + m_gfxCtx->initializeContext(nullptr); }); } diff --git a/lib/win/WindowWin32.cpp b/lib/win/WindowWin32.cpp index 1854cc4..2fe62ba 100644 --- a/lib/win/WindowWin32.cpp +++ b/lib/win/WindowWin32.cpp @@ -154,7 +154,7 @@ public: m_pf = pf; } - void initializeContext() {} + void initializeContext(void*) {} void makeCurrent() {} @@ -295,7 +295,7 @@ public: m_pf = pf; } - void initializeContext() {} + void initializeContext(void*) {} void makeCurrent() { diff --git a/lib/x11/ApplicationXlib.hpp b/lib/x11/ApplicationXlib.hpp index 61cdb90..9fff911 100644 --- a/lib/x11/ApplicationXlib.hpp +++ b/lib/x11/ApplicationXlib.hpp @@ -27,6 +27,8 @@ DBusConnection* RegisterDBus(const char* appName, bool& isFirst); #if BOO_HAS_VULKAN #include +#include +#include #endif namespace boo @@ -115,7 +117,7 @@ static Window GetWindowOfEvent(XEvent* event, bool& windowEvent) IWindow* _WindowXlibNew(const std::string& title, Display* display, void* xcbConn, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, - GLXContext lastCtx, bool useVulkan, uint32_t drawSamples); + GLXContext lastCtx, void* vulkanHandle, uint32_t drawSamples); static XIMStyle ChooseBetterStyle(XIMStyle style1, XIMStyle style2) { @@ -177,8 +179,37 @@ class ApplicationXlib final : public IApplication #if BOO_HAS_VULKAN /* Vulkan enable */ - bool m_useVulkan = true; xcb_connection_t* m_xcbConn; + + void* m_vkHandle = nullptr; + PFN_vkGetInstanceProcAddr m_getVkProc = 0; + bool loadVk() + { + const char filename[] = "libvulkan.so"; + void *handle, *symbol; + +#ifdef UNINSTALLED_LOADER + handle = dlopen(UNINSTALLED_LOADER, RTLD_LAZY); + if (!handle) + handle = dlopen(filename, RTLD_LAZY); +#else + handle = dlopen(filename, RTLD_LAZY); +#endif + + if (handle) + symbol = dlsym(handle, "vkGetInstanceProcAddr"); + + if (!handle || !symbol) { + + if (handle) + dlclose(handle); + return false; + } + + m_vkHandle = handle; + m_getVkProc = reinterpret_cast(symbol); + return true; + } #endif void _deletedWindow(IWindow* window) @@ -200,6 +231,29 @@ public: m_args(args), m_singleInstance(singleInstance) { +#if BOO_HAS_VULKAN + /* Check for Vulkan presence and preference */ + bool hasVk = loadVk(); + if (hasVk) + { + for (const std::string& arg : args) + { + if (!arg.compare("--gl")) + { + dlclose(m_vkHandle); + m_vkHandle = nullptr; + m_getVkProc = 0; + break; + } + } + } + + if (m_getVkProc) + Log.report(logvisor::Info, "using Vulkan renderer"); + else +#endif + Log.report(logvisor::Info, "using OpenGL renderer"); + /* DBus single instance registration */ bool isFirst; m_dbus = RegisterDBus(uniqueName.c_str(), isFirst); @@ -477,10 +531,10 @@ public: { #if BOO_HAS_VULKAN IWindow* newWindow = _WindowXlibNew(title, m_xDisp, m_xcbConn, m_xDefaultScreen, m_xIM, - m_bestStyle, m_fontset, m_lastGlxCtx, m_useVulkan, drawSamples); + m_bestStyle, m_fontset, m_lastGlxCtx, (void*)m_getVkProc, drawSamples); #else IWindow* newWindow = _WindowXlibNew(title, m_xDisp, nullptr, m_xDefaultScreen, m_xIM, - m_bestStyle, m_fontset, m_lastGlxCtx, false, drawSamples); + m_bestStyle, m_fontset, m_lastGlxCtx, nullptr, drawSamples); #endif m_windows[(Window)newWindow->getPlatformHandle()] = newWindow; return newWindow; diff --git a/lib/x11/WindowWayland.cpp b/lib/x11/WindowWayland.cpp index 6243e88..f271d1c 100644 --- a/lib/x11/WindowWayland.cpp +++ b/lib/x11/WindowWayland.cpp @@ -50,7 +50,7 @@ public: m_pf = pf; } - void initializeContext() + void initializeContext(void*) { } diff --git a/lib/x11/WindowXlib.cpp b/lib/x11/WindowXlib.cpp index d4b8f05..efc7b89 100644 --- a/lib/x11/WindowXlib.cpp +++ b/lib/x11/WindowXlib.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -440,7 +439,7 @@ public: m_pf = pf; } - void initializeContext() + void initializeContext(void*) { if (!glXCreateContextAttribsARB) { @@ -729,36 +728,7 @@ public: m_pf = pf; } - static void* m_vkHandle; - static PFN_vkGetInstanceProcAddr loadVk() - { - const char filename[] = "libvulkan.so"; - void *handle, *symbol; - -#ifdef UNINSTALLED_LOADER - handle = dlopen(UNINSTALLED_LOADER, RTLD_LAZY); - if (!handle) - handle = dlopen(filename, RTLD_LAZY); -#else - handle = dlopen(filename, RTLD_LAZY); -#endif - - if (handle) - symbol = dlsym(handle, "vkGetInstanceProcAddr"); - - if (!handle || !symbol) { - Log.report(logvisor::Fatal, "unable to load vulkan: %s", dlerror()); - - if (handle) - dlclose(handle); - } - - m_vkHandle = handle; - - return reinterpret_cast(symbol); - } - - void initializeContext() + void initializeContext(void* getVkProc) { if (!glXWaitVideoSyncSGI) { @@ -768,7 +738,7 @@ public: Log.report(logvisor::Fatal, "unable to resolve glXWaitVideoSyncSGI"); } - vk::init_dispatch_table_top(loadVk()); + vk::init_dispatch_table_top(PFN_vkGetInstanceProcAddr(getVkProc)); if (m_ctx->m_instance == VK_NULL_HANDLE) m_ctx->initVulkan(APP->getUniqueName().c_str()); @@ -928,7 +898,6 @@ public: void present() {} }; -void* GraphicsContextXlibVulkan::m_vkHandle = nullptr; #endif class WindowXlib : public IWindow @@ -992,7 +961,7 @@ public: WindowXlib(const std::string& title, Display* display, void* xcbConn, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, - GLXContext lastCtx, bool useVulkan, uint32_t drawSamples) + GLXContext lastCtx, void* vulkanHandle, uint32_t drawSamples) : m_xDisp(display), m_callback(nullptr), m_bestStyle(bestInputStyle) { @@ -1000,7 +969,7 @@ public: S_ATOMS = new XlibAtoms(display); #if BOO_HAS_VULKAN - if (useVulkan) + if (vulkanHandle) m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, (xcb_connection_t*)xcbConn, defaultScreen, &g_VulkanContext, m_visualId, drawSamples)); else @@ -1100,7 +1069,7 @@ public: setCursor(EMouseCursor::Pointer); XFlush(m_xDisp); - m_gfxCtx->initializeContext(); + m_gfxCtx->initializeContext(vulkanHandle); } ~WindowXlib() @@ -2029,11 +1998,11 @@ public: IWindow* _WindowXlibNew(const std::string& title, Display* display, void* xcbConn, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, - GLXContext lastCtx, bool useVulkan, uint32_t drawSamples) + GLXContext lastCtx, void* vulkanHandle, uint32_t drawSamples) { XLockDisplay(display); IWindow* ret = new WindowXlib(title, display, xcbConn, defaultScreen, xIM, - bestInputStyle, fontset, lastCtx, useVulkan, drawSamples); + bestInputStyle, fontset, lastCtx, vulkanHandle, drawSamples); XUnlockDisplay(display); return ret; }