From 77b23a58f06e3c36c2328430349dcfb8dd60945b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 6 Jan 2025 07:01:36 +0100 Subject: [PATCH] Boot vulkan without a surface --- src/common/platform/posix/cocoa/i_video.mm | 21 +++++++---- src/common/platform/posix/sdl/base_sysfb.cpp | 28 ++++++++++----- src/common/platform/win32/win32vulkanvideo.h | 35 ++++++++++++------- .../vulkan/framebuffers/vk_framebuffer.cpp | 22 +++++++----- .../rendering/vulkan/vk_renderdevice.cpp | 12 ++++--- src/common/rendering/vulkan/vk_renderdevice.h | 6 +++- src/d_main.cpp | 12 +++++-- 7 files changed, 92 insertions(+), 44 deletions(-) diff --git a/src/common/platform/posix/cocoa/i_video.mm b/src/common/platform/posix/cocoa/i_video.mm index 741e70fea..ec94a1f92 100644 --- a/src/common/platform/posix/cocoa/i_video.mm +++ b/src/common/platform/posix/cocoa/i_video.mm @@ -37,6 +37,7 @@ #endif #include "i_common.h" +#include "i_interface.h" #include "v_video.h" #include "bitmap.h" @@ -357,17 +358,23 @@ public: VulkanInstanceBuilder builder; builder.DebugLayer(vk_debug); builder.RequireExtension(VK_KHR_SURFACE_EXTENSION_NAME); // KHR_surface, required - builder.OptionalExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME); // EXT_metal_surface, optional, preferred - builder.OptionalExtension(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); // MVK_macos_surface, optional, deprecated + if (!RunningAsTool) + { + builder.OptionalExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME); // EXT_metal_surface, optional, preferred + builder.OptionalExtension(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); // MVK_macos_surface, optional, deprecated + } auto vulkanInstance = builder.Create(); - VkSurfaceKHR surfacehandle = nullptr; - if (!I_CreateVulkanSurface(vulkanInstance->Instance, &surfacehandle)) - VulkanError("I_CreateVulkanSurface failed"); + if (!RunningAsTool) + { + VkSurfaceKHR surfacehandle = nullptr; + if (!I_CreateVulkanSurface(vulkanInstance->Instance, &surfacehandle)) + VulkanError("I_CreateVulkanSurface failed"); - m_vulkanSurface = std::make_shared(vulkanInstance, surfacehandle); + m_vulkanSurface = std::make_shared(vulkanInstance, surfacehandle); + } - fb = new VulkanRenderDevice(nullptr, vid_fullscreen, m_vulkanSurface); + fb = new VulkanRenderDevice(nullptr, vid_fullscreen, vulkanInstance, m_vulkanSurface); #else #error "Vulkan support must be enabled!" #endif diff --git a/src/common/platform/posix/sdl/base_sysfb.cpp b/src/common/platform/posix/sdl/base_sysfb.cpp index e0d70a847..05b84de7d 100644 --- a/src/common/platform/posix/sdl/base_sysfb.cpp +++ b/src/common/platform/posix/sdl/base_sysfb.cpp @@ -37,6 +37,7 @@ #include "i_soundinternal.h" #include "i_system.h" #include "i_video.h" +#include "i_interface.h" #include "m_argv.h" #include "v_video.h" #include "version.h" @@ -334,22 +335,31 @@ DFrameBuffer *SDLVideo::CreateFrameBuffer () unsigned int count = 64; const char* names[64]; - if (!I_GetVulkanPlatformExtensions(&count, names)) - VulkanError("I_GetVulkanPlatformExtensions failed"); + if (!RunningAsTool) + { + if (!I_GetVulkanPlatformExtensions(&count, names)) + VulkanError("I_GetVulkanPlatformExtensions failed"); + } VulkanInstanceBuilder builder; builder.DebugLayer(vk_debug); - for (unsigned int i = 0; i < count; i++) - builder.RequireExtension(names[i]); + if (!RunningAsTool) + { + for (unsigned int i = 0; i < count; i++) + builder.RequireExtension(names[i]); + } auto instance = builder.Create(); - VkSurfaceKHR surfacehandle = nullptr; - if (!I_CreateVulkanSurface(instance->Instance, &surfacehandle)) - VulkanError("I_CreateVulkanSurface failed"); + if (!RunningAsTool) + { + VkSurfaceKHR surfacehandle = nullptr; + if (!I_CreateVulkanSurface(instance->Instance, &surfacehandle)) + VulkanError("I_CreateVulkanSurface failed"); - surface = std::make_shared(instance, surfacehandle); + surface = std::make_shared(instance, surfacehandle); + } - fb = new VulkanRenderDevice(nullptr, vid_fullscreen, surface); + fb = new VulkanRenderDevice(nullptr, vid_fullscreen, instance, surface); #endif return fb; diff --git a/src/common/platform/win32/win32vulkanvideo.h b/src/common/platform/win32/win32vulkanvideo.h index 611800478..c1fd0e3e8 100644 --- a/src/common/platform/win32/win32vulkanvideo.h +++ b/src/common/platform/win32/win32vulkanvideo.h @@ -3,6 +3,7 @@ #include "win32basevideo.h" #include "c_cvars.h" #include "vulkan/vk_renderdevice.h" +#include "i_interface.h" #include #include @@ -22,26 +23,34 @@ EXTERN_CVAR(Int, vk_device) class Win32VulkanVideo : public Win32BaseVideo { - std::shared_ptr surface; public: Win32VulkanVideo() { unsigned int count = 64; const char* names[64]; - if (!I_GetVulkanPlatformExtensions(&count, names)) - VulkanError("I_GetVulkanPlatformExtensions failed"); + if (!RunningAsTool) + { + if (!I_GetVulkanPlatformExtensions(&count, names)) + VulkanError("I_GetVulkanPlatformExtensions failed"); + } VulkanInstanceBuilder builder; builder.DebugLayer(vk_debug); - for (unsigned int i = 0; i < count; i++) - builder.RequireExtension(names[i]); - auto instance = builder.Create(); + if (!RunningAsTool) + { + for (unsigned int i = 0; i < count; i++) + builder.RequireExtension(names[i]); + } + instance = builder.Create(); - VkSurfaceKHR surfacehandle = nullptr; - if (!I_CreateVulkanSurface(instance->Instance, &surfacehandle)) - VulkanError("I_CreateVulkanSurface failed"); + if (!RunningAsTool) + { + VkSurfaceKHR surfacehandle = nullptr; + if (!I_CreateVulkanSurface(instance->Instance, &surfacehandle)) + VulkanError("I_CreateVulkanSurface failed"); - surface = std::make_shared(instance, surfacehandle); + surface = std::make_shared(instance, surfacehandle); + } } ~Win32VulkanVideo() @@ -55,9 +64,11 @@ public: DFrameBuffer *CreateFrameBuffer() override { - auto fb = new VulkanRenderDevice(m_hMonitor, vid_fullscreen, surface); + auto fb = new VulkanRenderDevice(m_hMonitor, vid_fullscreen, instance, surface); return fb; } -protected: +private: + std::shared_ptr instance; + std::shared_ptr surface; }; diff --git a/src/common/rendering/vulkan/framebuffers/vk_framebuffer.cpp b/src/common/rendering/vulkan/framebuffers/vk_framebuffer.cpp index 0ffee0cc0..1343d3877 100644 --- a/src/common/rendering/vulkan/framebuffers/vk_framebuffer.cpp +++ b/src/common/rendering/vulkan/framebuffers/vk_framebuffer.cpp @@ -33,16 +33,19 @@ CVAR(Bool, vk_exclusivefullscreen, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); VkFramebufferManager::VkFramebufferManager(VulkanRenderDevice* fb) : fb(fb) { - SwapChain = VulkanSwapChainBuilder() - .Create(fb->GetDevice()); + if (fb->IsSurfaceAvailable()) + { + SwapChain = VulkanSwapChainBuilder() + .Create(fb->GetDevice()); - SwapChainImageAvailableSemaphore = SemaphoreBuilder() - .DebugName("SwapChainImageAvailableSemaphore") - .Create(fb->GetDevice()); + SwapChainImageAvailableSemaphore = SemaphoreBuilder() + .DebugName("SwapChainImageAvailableSemaphore") + .Create(fb->GetDevice()); - RenderFinishedSemaphore = SemaphoreBuilder() - .DebugName("RenderFinishedSemaphore") - .Create(fb->GetDevice()); + RenderFinishedSemaphore = SemaphoreBuilder() + .DebugName("RenderFinishedSemaphore") + .Create(fb->GetDevice()); + } } VkFramebufferManager::~VkFramebufferManager() @@ -51,6 +54,9 @@ VkFramebufferManager::~VkFramebufferManager() void VkFramebufferManager::AcquireImage() { + if (!SwapChain) + return; + bool exclusiveFullscreen = fb->IsFullscreen() && vk_exclusivefullscreen; if (SwapChain->Lost() || fb->GetClientWidth() != CurrentWidth || fb->GetClientHeight() != CurrentHeight || fb->GetVSync() != CurrentVSync || CurrentHdr != vk_hdr || CurrentExclusiveFullscreen != exclusiveFullscreen) { diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index d26232adf..049072205 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -160,15 +160,19 @@ void VulkanPrintLog(const char* typestr, const std::string& msg) } } -VulkanRenderDevice::VulkanRenderDevice(void *hMonitor, bool fullscreen, std::shared_ptr surface) : SystemBaseFrameBuffer(hMonitor, fullscreen) +VulkanRenderDevice::VulkanRenderDevice(void *hMonitor, bool fullscreen, std::shared_ptr instance, std::shared_ptr surface) : SystemBaseFrameBuffer(hMonitor, fullscreen) { VulkanDeviceBuilder builder; builder.OptionalRayQuery(); builder.RequireExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); - builder.Surface(surface); + if (surface) + { + HasSurface = true; + builder.Surface(surface); + } builder.SelectDevice(vk_device); - SupportedDevices = builder.FindDevices(surface->Instance); - mDevice = builder.Create(surface->Instance); + SupportedDevices = builder.FindDevices(instance); + mDevice = builder.Create(instance); bool supportsBindless = mDevice->EnabledFeatures.DescriptorIndexing.descriptorBindingPartiallyBound && diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index 07859ed06..3776345f6 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -28,7 +28,7 @@ class VkRenderPassSetup; class VulkanRenderDevice : public SystemBaseFrameBuffer { public: - VulkanRenderDevice(void* hMonitor, bool fullscreen, std::shared_ptr surface); + VulkanRenderDevice(void* hMonitor, bool fullscreen, std::shared_ptr instance, std::shared_ptr surface); ~VulkanRenderDevice(); VulkanDevice* GetDevice() { return mDevice.get(); } @@ -98,11 +98,15 @@ public: const VkPipelineKey& GetLevelMeshPipelineKey(int id) const; + bool IsSurfaceAvailable() { return HasSurface; } + private: void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; void PrintStartupLog(); void CopyScreenToBuffer(int w, int h, uint8_t *data) override; + bool HasSurface = false; + std::shared_ptr mDevice; std::unique_ptr mCommands; std::unique_ptr mBufferManager; diff --git a/src/d_main.cpp b/src/d_main.cpp index 8af45de10..f7269fb14 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -3538,10 +3538,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector& allw } if (RunningAsTool) - { - // To do: is enough of the engine initialized now for running tool commandlets? return 0; - } if (StartScreen) { @@ -3852,6 +3849,15 @@ static int D_DoomMain_Internal (void) iwad_man = NULL; if (ret != 0) return ret; + if (RunningAsTool) + { + // To do: We got a game loaded and can now process commandlets + + Printf("\n"); + Printf("Specify " TEXTCOLOR_ORANGE "--help" TEXTCOLOR_NORMAL " for a list of commands\n"); + return 0; + } + D_DoAnonStats(); I_UpdateWindowTitle(); D_DoomLoop (); // this only returns if a 'restart' CCMD is given.