mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-04-26 12:21:43 +00:00
refactor(cleanup): initial swapchain logic & temporary backend creation
This commit is contained in:
parent
9ba80142b2
commit
7e936784ab
9 changed files with 457 additions and 124 deletions
|
|
@ -29,6 +29,10 @@ namespace ls {
|
|||
return *this->opt;
|
||||
}
|
||||
|
||||
/// check if value is present
|
||||
/// @return true if value is present
|
||||
[[nodiscard]] bool has_value() const { return this->opt.has_value(); }
|
||||
|
||||
/// get reference to value
|
||||
/// @return reference to value
|
||||
/// @throws std::logic_error if no value present
|
||||
|
|
@ -46,6 +50,15 @@ namespace ls {
|
|||
throw std::logic_error("lazy: no value present");
|
||||
return &(*this->opt);
|
||||
}
|
||||
|
||||
/// get a mutable reference to value
|
||||
/// @return mutable reference to value
|
||||
/// @throws std::logic_error if no value present
|
||||
T& mut() {
|
||||
if (!this->opt.has_value())
|
||||
throw std::logic_error("lazy: no value present");
|
||||
return *this->opt;
|
||||
}
|
||||
private:
|
||||
std::optional<T> opt{};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,12 +25,18 @@ namespace vk {
|
|||
PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties;
|
||||
PFN_vkCreateDevice CreateDevice;
|
||||
PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
|
||||
|
||||
// extension functions
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||
};
|
||||
|
||||
/// initialize vulkan instance function pointers
|
||||
/// @param instance vulkan instance handle
|
||||
/// @param mpa function to get instance proc addresses
|
||||
VulkanInstanceFuncs initVulkanInstanceFuncs(VkInstance instance, PFN_vkGetInstanceProcAddr mpa);
|
||||
/// @param graphical whether the device is graphical (rather than compute)
|
||||
/// @return initialized function pointers
|
||||
VulkanInstanceFuncs initVulkanInstanceFuncs(VkInstance instance, PFN_vkGetInstanceProcAddr mpa,
|
||||
bool graphical);
|
||||
|
||||
using PhysicalDeviceSelector = const std::function<
|
||||
VkPhysicalDevice(
|
||||
|
|
@ -98,12 +104,18 @@ namespace vk {
|
|||
PFN_vkGetMemoryFdKHR GetMemoryFdKHR;
|
||||
PFN_vkImportSemaphoreFdKHR ImportSemaphoreFdKHR;
|
||||
PFN_vkGetSemaphoreFdKHR GetSemaphoreFdKHR;
|
||||
PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
|
||||
PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
|
||||
};
|
||||
|
||||
/// initialize vulkan device function pointers
|
||||
/// @param fi instance function pointers
|
||||
/// @param device logical device handle
|
||||
VulkanDeviceFuncs initVulkanDeviceFuncs(const VulkanInstanceFuncs& fi, VkDevice device);
|
||||
/// @param graphical whether the device is graphical (rather than compute)
|
||||
/// @return initialized function pointers
|
||||
VulkanDeviceFuncs initVulkanDeviceFuncs(const VulkanInstanceFuncs& fi, VkDevice device,
|
||||
bool graphical);
|
||||
|
||||
/// vulkan version wrapper
|
||||
class version {
|
||||
|
|
@ -167,6 +179,9 @@ namespace vk {
|
|||
/// get the vulkan device
|
||||
/// @return the device handle
|
||||
[[nodiscard]] const auto& dev() const { return this->device.get(); }
|
||||
/// get the physical device
|
||||
/// @return the physical device handle
|
||||
[[nodiscard]] VkPhysicalDevice physdev() const { return this->phys_dev; }
|
||||
/// get the command pool
|
||||
/// @return the command pool handle
|
||||
[[nodiscard]] const auto& cmdpool() const { return this->cmdPool.get(); }
|
||||
|
|
@ -181,6 +196,9 @@ namespace vk {
|
|||
/// @return true if fp16 is supported
|
||||
[[nodiscard]] bool supportsFP16() const { return this->fp16; }
|
||||
|
||||
/// get instance-level function pointers
|
||||
/// @return the instance function pointers
|
||||
[[nodiscard]] const auto& fi() const { return this->instance_funcs; }
|
||||
/// get device-level function pointers
|
||||
/// @return the device function pointers
|
||||
[[nodiscard]] const auto& df() const { return this->device_funcs; }
|
||||
|
|
@ -191,7 +209,7 @@ namespace vk {
|
|||
ls::owned_ptr<VkInstance> instance;
|
||||
VulkanInstanceFuncs instance_funcs;
|
||||
|
||||
VkPhysicalDevice physdev;
|
||||
VkPhysicalDevice phys_dev;
|
||||
uint32_t queueFamilyIdx;
|
||||
bool fp16;
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,8 @@ namespace {
|
|||
const std::vector<const char*> requestedExtensions{
|
||||
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
|
||||
VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME // TODO: possibly attempt to get rid of
|
||||
VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME, // TODO: possibly attempt to get rid of
|
||||
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME
|
||||
};
|
||||
const VkDeviceCreateInfo deviceInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
|
|
@ -268,7 +269,8 @@ namespace {
|
|||
}
|
||||
|
||||
/// initialize vulkan instance function pointers
|
||||
VulkanInstanceFuncs vk::initVulkanInstanceFuncs(VkInstance i, PFN_vkGetInstanceProcAddr mpa) {
|
||||
VulkanInstanceFuncs vk::initVulkanInstanceFuncs(VkInstance i, PFN_vkGetInstanceProcAddr mpa,
|
||||
bool graphical) {
|
||||
return {
|
||||
.DestroyInstance = ipa<PFN_vkDestroyInstance>(mpa, i, "vkDestroyInstance"),
|
||||
.EnumeratePhysicalDevices = ipa<PFN_vkEnumeratePhysicalDevices>(mpa, i,
|
||||
|
|
@ -280,17 +282,22 @@ VulkanInstanceFuncs vk::initVulkanInstanceFuncs(VkInstance i, PFN_vkGetInstanceP
|
|||
.GetPhysicalDeviceQueueFamilyProperties =
|
||||
ipa<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(mpa, i,
|
||||
"vkGetPhysicalDeviceQueueFamilyProperties"),
|
||||
.GetPhysicalDeviceFeatures2 = ipa<PFN_vkGetPhysicalDeviceFeatures2>(mpa, i,
|
||||
"vkGetPhysicalDeviceFeatures2"),
|
||||
.GetPhysicalDeviceFeatures2 = graphical ?
|
||||
nullptr : ipa<PFN_vkGetPhysicalDeviceFeatures2>(mpa, i, "vkGetPhysicalDeviceFeatures2"),
|
||||
.GetPhysicalDeviceMemoryProperties = ipa<PFN_vkGetPhysicalDeviceMemoryProperties>(mpa, i,
|
||||
"vkGetPhysicalDeviceMemoryProperties"),
|
||||
.CreateDevice = ipa<PFN_vkCreateDevice>(mpa, i, "vkCreateDevice"),
|
||||
.GetDeviceProcAddr = ipa<PFN_vkGetDeviceProcAddr>(mpa, i, "vkGetDeviceProcAddr"),
|
||||
|
||||
.GetPhysicalDeviceSurfaceCapabilitiesKHR = graphical ?
|
||||
ipa<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(mpa, i,
|
||||
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR") : nullptr
|
||||
};
|
||||
}
|
||||
|
||||
/// initialize vulkan device function pointers
|
||||
VulkanDeviceFuncs vk::initVulkanDeviceFuncs(const VulkanInstanceFuncs& f, VkDevice d) {
|
||||
VulkanDeviceFuncs vk::initVulkanDeviceFuncs(const VulkanInstanceFuncs& f, VkDevice d,
|
||||
bool graphical) {
|
||||
return {
|
||||
.GetDeviceQueue = dpa<PFN_vkGetDeviceQueue>(f, d, "vkGetDeviceQueue"),
|
||||
.DeviceWaitIdle = dpa<PFN_vkDeviceWaitIdle>(f, d, "vkDeviceWaitIdle"),
|
||||
|
|
@ -355,6 +362,13 @@ VulkanDeviceFuncs vk::initVulkanDeviceFuncs(const VulkanInstanceFuncs& f, VkDevi
|
|||
.GetMemoryFdKHR = dpa<PFN_vkGetMemoryFdKHR>(f, d, "vkGetMemoryFdKHR"),
|
||||
.ImportSemaphoreFdKHR = dpa<PFN_vkImportSemaphoreFdKHR>(f, d, "vkImportSemaphoreFdKHR"),
|
||||
.GetSemaphoreFdKHR = dpa<PFN_vkGetSemaphoreFdKHR>(f, d, "vkGetSemaphoreFdKHR"),
|
||||
|
||||
.CreateSwapchainKHR = graphical ?
|
||||
dpa<PFN_vkCreateSwapchainKHR>(f, d, "vkCreateSwapchainKHR") : nullptr,
|
||||
.GetSwapchainImagesKHR = graphical ?
|
||||
dpa<PFN_vkGetSwapchainImagesKHR>(f, d, "vkGetSwapchainImagesKHR") : nullptr,
|
||||
.DestroySwapchainKHR = graphical ?
|
||||
dpa<PFN_vkDestroySwapchainKHR>(f, d, "vkDestroySwapchainKHR") : nullptr
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -367,23 +381,23 @@ Vulkan::Vulkan(const std::string& appName, version appVersion,
|
|||
appName, appVersion,
|
||||
engineName, engineVersion
|
||||
)),
|
||||
instance_funcs(initVulkanInstanceFuncs(*this->instance, get_mpa())),
|
||||
physdev(findPhysicalDevice(this->instance_funcs,
|
||||
instance_funcs(initVulkanInstanceFuncs(*this->instance, get_mpa(), false)),
|
||||
phys_dev(findPhysicalDevice(this->instance_funcs,
|
||||
*this->instance,
|
||||
selectPhysicalDevice
|
||||
)),
|
||||
queueFamilyIdx(findQFI(this->instance_funcs, this->physdev,
|
||||
queueFamilyIdx(findQFI(this->instance_funcs, this->phys_dev,
|
||||
isGraphical ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_COMPUTE_BIT)),
|
||||
fp16(checkFP16(this->instance_funcs, this->physdev)),
|
||||
fp16(checkFP16(this->instance_funcs, this->phys_dev)),
|
||||
device(createLogicalDevice(this->instance_funcs,
|
||||
this->physdev,
|
||||
this->phys_dev,
|
||||
this->queueFamilyIdx,
|
||||
this->fp16
|
||||
)),
|
||||
setLoaderData(setLoaderData),
|
||||
device_funcs(initVulkanDeviceFuncs(
|
||||
this->instance_funcs,
|
||||
*this->device
|
||||
*this->device, false
|
||||
)),
|
||||
computeQueue(getQueue(this->device_funcs, *this->device,
|
||||
this->setLoaderData,
|
||||
|
|
@ -405,8 +419,8 @@ Vulkan::Vulkan(VkInstance instance, VkDevice device,
|
|||
std::optional<PFN_vkSetDeviceLoaderData> setLoaderData) :
|
||||
instance(new VkInstance(instance)),
|
||||
instance_funcs(instanceFuncs),
|
||||
physdev(physdev),
|
||||
queueFamilyIdx(findQFI(this->instance_funcs, this->physdev,
|
||||
phys_dev(physdev),
|
||||
queueFamilyIdx(findQFI(this->instance_funcs, this->phys_dev,
|
||||
isGraphical ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_COMPUTE_BIT)),
|
||||
fp16(false),
|
||||
device(new VkDevice(device)),
|
||||
|
|
@ -431,7 +445,7 @@ std::optional<uint32_t> Vulkan::findMemoryTypeIndex(
|
|||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
|
||||
VkPhysicalDeviceMemoryProperties props;
|
||||
this->instance_funcs.GetPhysicalDeviceMemoryProperties(this->physdev, &props);
|
||||
this->instance_funcs.GetPhysicalDeviceMemoryProperties(this->phys_dev, &props);
|
||||
|
||||
std::array<VkMemoryType, 32> memTypes = std::to_array(props.memoryTypes);
|
||||
for (uint32_t i = 0; i < props.memoryTypeCount; ++i)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ set(LAYER_SOURCES
|
|||
"src/configuration/config.cpp"
|
||||
"src/configuration/detection.cpp"
|
||||
"src/context/instance.cpp"
|
||||
"src/context/swapchain.cpp"
|
||||
"src/entrypoint.cpp")
|
||||
|
||||
add_library(lsfg-vk-layer SHARED ${LAYER_SOURCES})
|
||||
|
|
|
|||
|
|
@ -1,20 +1,45 @@
|
|||
#include "instance.hpp"
|
||||
#include "../configuration/config.hpp"
|
||||
#include "../configuration/detection.hpp"
|
||||
#include "swapchain.hpp"
|
||||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/helpers/errors.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
using namespace lsfgvk;
|
||||
using namespace lsfgvk::layer;
|
||||
|
||||
namespace {
|
||||
/// helper function to add required extensions
|
||||
std::vector<const char*> add_extensions(const char* const* existingExtensions, size_t count,
|
||||
const std::vector<const char*>& requiredExtensions) {
|
||||
std::vector<const char*> extensions(count);
|
||||
std::copy_n(existingExtensions, count, extensions.data());
|
||||
|
||||
for (const auto& requiredExtension : requiredExtensions) {
|
||||
auto it = std::ranges::find_if(extensions,
|
||||
[requiredExtension](const char* extension) {
|
||||
return std::string(extension) == std::string(requiredExtension);
|
||||
});
|
||||
if (it == extensions.end())
|
||||
extensions.push_back(requiredExtension);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
// find the shader dll
|
||||
std::filesystem::path findShaderDll() {
|
||||
const std::vector<std::filesystem::path> FRAGMENTS{{
|
||||
|
|
@ -82,47 +107,130 @@ Root::Root() {
|
|||
std::cerr << "(identified via process name)\n";
|
||||
break;
|
||||
}
|
||||
|
||||
// create backend
|
||||
/*const auto& global = this->config.getGlobalConf();
|
||||
this->backend.emplace(
|
||||
[gpu = profile->second.gpu](
|
||||
const std::string& deviceName,
|
||||
std::pair<const std::string&, const std::string&> ids,
|
||||
const std::optional<std::string>& pci
|
||||
) {
|
||||
if (!gpu)
|
||||
return true;
|
||||
|
||||
return (deviceName == *gpu)
|
||||
|| (ids.first + ":" + ids.second == *gpu)
|
||||
|| (pci && *pci == *gpu);
|
||||
},
|
||||
global.dll.value_or(findShaderDll()),
|
||||
global.allow_fp16
|
||||
);*/
|
||||
}
|
||||
|
||||
std::vector<const char*> Root::instanceExtensions() const {
|
||||
void Root::update() {
|
||||
if (!this->config.isUpToDate())
|
||||
this->config.reload();
|
||||
}
|
||||
|
||||
void Root::modifyInstanceCreateInfo(VkInstanceCreateInfo& createInfo,
|
||||
const std::function<void(void)>& finish) const {
|
||||
if (!this->active_profile.has_value())
|
||||
return {};
|
||||
return;
|
||||
|
||||
return {
|
||||
"VK_KHR_get_physical_device_properties2",
|
||||
"VK_KHR_external_memory_capabilities",
|
||||
"VK_KHR_external_semaphore_capabilities"
|
||||
};
|
||||
auto extensions = add_extensions(
|
||||
createInfo.ppEnabledExtensionNames,
|
||||
createInfo.enabledExtensionCount,
|
||||
{
|
||||
"VK_KHR_get_physical_device_properties2",
|
||||
"VK_KHR_external_memory_capabilities",
|
||||
"VK_KHR_external_semaphore_capabilities"
|
||||
}
|
||||
);
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
std::vector<const char*> Root::deviceExtensions() const {
|
||||
void Root::modifyDeviceCreateInfo(VkDeviceCreateInfo& createInfo,
|
||||
const std::function<void(void)>& finish) const {
|
||||
if (!this->active_profile.has_value())
|
||||
return {};
|
||||
return;
|
||||
|
||||
return {
|
||||
"VK_KHR_external_memory",
|
||||
"VK_KHR_external_memory_fd",
|
||||
"VK_KHR_external_semaphore",
|
||||
"VK_KHR_external_semaphore_fd",
|
||||
"VK_KHR_timeline_semaphore"
|
||||
auto extensions = add_extensions(
|
||||
createInfo.ppEnabledExtensionNames,
|
||||
createInfo.enabledExtensionCount,
|
||||
{
|
||||
"VK_KHR_external_memory",
|
||||
"VK_KHR_external_memory_fd",
|
||||
"VK_KHR_external_semaphore",
|
||||
"VK_KHR_external_semaphore_fd",
|
||||
"VK_KHR_timeline_semaphore"
|
||||
}
|
||||
);
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
||||
bool isFeatureEnabled = false;
|
||||
auto* featureInfo = reinterpret_cast<VkBaseInStructure*>(const_cast<void*>(createInfo.pNext));
|
||||
while (featureInfo) {
|
||||
if (featureInfo->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) {
|
||||
auto* features = reinterpret_cast<VkPhysicalDeviceVulkan12Features*>(featureInfo);
|
||||
features->timelineSemaphore = VK_TRUE;
|
||||
isFeatureEnabled = true;
|
||||
} else if (featureInfo->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES) {
|
||||
auto* features = reinterpret_cast<VkPhysicalDeviceTimelineSemaphoreFeatures*>(featureInfo);
|
||||
features->timelineSemaphore = VK_TRUE;
|
||||
isFeatureEnabled = true;
|
||||
}
|
||||
|
||||
featureInfo = const_cast<VkBaseInStructure*>(featureInfo->pNext);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceTimelineSemaphoreFeatures timelineFeatures{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
|
||||
.pNext = const_cast<void*>(createInfo.pNext),
|
||||
.timelineSemaphore = VK_TRUE
|
||||
};
|
||||
if (!isFeatureEnabled)
|
||||
createInfo.pNext = &timelineFeatures;
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
void Root::modifySwapchainCreateInfo(const vk::Vulkan& vk, VkSwapchainCreateInfoKHR& createInfo,
|
||||
const std::function<void(void)>& finish) const {
|
||||
if (!this->active_profile.has_value())
|
||||
return;
|
||||
|
||||
VkSurfaceCapabilitiesKHR caps{};
|
||||
auto res = vk.fi().GetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||
vk.physdev(), createInfo.surface, &caps);
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() failed");
|
||||
|
||||
context_ModifySwapchainCreateInfo(*this->active_profile, caps.maxImageCount, createInfo);
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
void Root::createSwapchainContext(const vk::Vulkan& vk,
|
||||
VkSwapchainKHR swapchain, const SwapchainInfo& info) {
|
||||
if (!this->active_profile.has_value())
|
||||
throw lsfgvk::error("attempted to create swapchain context while layer is inactive");
|
||||
const auto& profile = *this->active_profile;
|
||||
|
||||
if (!this->backend.has_value()) { // emplace backend late, due to loader bug
|
||||
const auto& global = this->config.getGlobalConf();
|
||||
|
||||
setenv("DISABLE_LSFGVK", "1", 1); // NOLINT (c++-include)
|
||||
|
||||
this->backend.emplace(
|
||||
[gpu = profile.gpu](
|
||||
const std::string& deviceName,
|
||||
std::pair<const std::string&, const std::string&> ids,
|
||||
const std::optional<std::string>& pci
|
||||
) {
|
||||
if (!gpu)
|
||||
return true;
|
||||
|
||||
return (deviceName == *gpu)
|
||||
|| (ids.first + ":" + ids.second == *gpu)
|
||||
|| (pci && *pci == *gpu);
|
||||
},
|
||||
global.dll.value_or(findShaderDll()),
|
||||
global.allow_fp16
|
||||
);
|
||||
|
||||
unsetenv("DISABLE_LSFGVK"); // NOLINT (c++-include)
|
||||
}
|
||||
|
||||
this->swapchains.emplace(swapchain,
|
||||
Swapchain(vk, this->backend.mut(), profile, info));
|
||||
}
|
||||
|
||||
void Root::removeSwapchainContext(VkSwapchainKHR swapchain) {
|
||||
this->swapchains.erase(swapchain);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@
|
|||
#include "../configuration/config.hpp"
|
||||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/helpers/pointers.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
namespace lsfgvk::layer {
|
||||
|
||||
|
|
@ -20,17 +24,59 @@ namespace lsfgvk::layer {
|
|||
/// @return true if active
|
||||
[[nodiscard]] bool active() const { return this->active_profile.has_value(); }
|
||||
|
||||
/// required instance extensions
|
||||
/// @return list of extension names
|
||||
[[nodiscard]] std::vector<const char*> instanceExtensions() const;
|
||||
/// required device extensions
|
||||
/// @return list of extension names
|
||||
[[nodiscard]] std::vector<const char*> deviceExtensions() const;
|
||||
/// ensure the layer is up-to-date
|
||||
void update();
|
||||
|
||||
// /// required instance extensions
|
||||
// /// @return list of extension names
|
||||
// [[nodiscard]] std::vector<const char*> instanceExtensions() const;
|
||||
// /// required device extensions
|
||||
// /// @return list of extension names
|
||||
// [[nodiscard]] std::vector<const char*> deviceExtensions() const;
|
||||
|
||||
/// modify instance create info
|
||||
/// @param createInfo original create info
|
||||
/// @param finish function to call after modification
|
||||
void modifyInstanceCreateInfo(VkInstanceCreateInfo& createInfo,
|
||||
const std::function<void(void)>& finish) const;
|
||||
/// modify device create info
|
||||
/// @param createInfo original create info
|
||||
/// @param finish function to call after modification
|
||||
void modifyDeviceCreateInfo(VkDeviceCreateInfo& createInfo,
|
||||
const std::function<void(void)>& finish) const;
|
||||
|
||||
/// modify swapchain create info
|
||||
/// @param vk vulkan instance
|
||||
/// @param createInfo original create info
|
||||
/// @param finish function to call after modification
|
||||
void modifySwapchainCreateInfo(const vk::Vulkan& vk, VkSwapchainCreateInfoKHR& createInfo,
|
||||
const std::function<void(void)>& finish) const;
|
||||
/// create swapchain context
|
||||
/// @param vk vulkan instance
|
||||
/// @param swapchain swapchain handle
|
||||
/// @param info swapchain info
|
||||
void createSwapchainContext(const vk::Vulkan& vk, VkSwapchainKHR swapchain,
|
||||
const SwapchainInfo& info);
|
||||
/// get swapchain context
|
||||
/// @param swapchain swapchain handle
|
||||
/// @return swapchain context
|
||||
/// @throws lsfgvk::error if not found
|
||||
[[nodiscard]] Swapchain& getSwapchainContext(VkSwapchainKHR swapchain) {
|
||||
const auto& it = this->swapchains.find(swapchain);
|
||||
if (it == this->swapchains.end())
|
||||
throw lsfgvk::error("swapchain context not found");
|
||||
|
||||
return it->second;
|
||||
}
|
||||
/// remove swapchain context
|
||||
/// @param swapchain swapchain handle
|
||||
void removeSwapchainContext(VkSwapchainKHR swapchain);
|
||||
private:
|
||||
Configuration config;
|
||||
std::optional<GameConf> active_profile;
|
||||
|
||||
ls::lazy<lsfgvk::Instance> backend;
|
||||
std::unordered_map<VkSwapchainKHR, Swapchain> swapchains;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
33
lsfg-vk-layer/src/context/swapchain.cpp
Normal file
33
lsfg-vk-layer/src/context/swapchain.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "swapchain.hpp"
|
||||
#include "../configuration/config.hpp"
|
||||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <iostream>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
using namespace lsfgvk;
|
||||
using namespace lsfgvk::layer;
|
||||
|
||||
void layer::context_ModifySwapchainCreateInfo(const GameConf& profile, uint32_t maxImages,
|
||||
VkSwapchainCreateInfoKHR& createInfo) {
|
||||
createInfo.imageUsage |=
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
switch (profile.pacing) {
|
||||
case lsfgvk::layer::Pacing::None:
|
||||
createInfo.minImageCount += profile.multiplier;
|
||||
if (maxImages && createInfo.minImageCount > maxImages)
|
||||
createInfo.minImageCount = maxImages;
|
||||
|
||||
createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Swapchain::Swapchain(const vk::Vulkan& vk, lsfgvk::Instance& backend,
|
||||
const GameConf& profile, const SwapchainInfo& info) {
|
||||
std::cerr << "lsfg-vk: swapchain created :3\n";
|
||||
}
|
||||
42
lsfg-vk-layer/src/context/swapchain.hpp
Normal file
42
lsfg-vk-layer/src/context/swapchain.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include "../configuration/config.hpp"
|
||||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
namespace lsfgvk::layer {
|
||||
|
||||
/// swapchain info struct
|
||||
struct SwapchainInfo {
|
||||
std::vector<VkImage> images;
|
||||
VkFormat format;
|
||||
VkColorSpaceKHR colorSpace;
|
||||
VkExtent2D extent;
|
||||
VkPresentModeKHR presentMode;
|
||||
};
|
||||
|
||||
/// modify the swapchain create info based on the profile pre-swapchain creation
|
||||
/// @param profile active game profile
|
||||
/// @param maxImages maximum number of images supported by the surface
|
||||
/// @param createInfo swapchain create info to modify
|
||||
void context_ModifySwapchainCreateInfo(const GameConf& profile, uint32_t maxImages,
|
||||
VkSwapchainCreateInfoKHR& createInfo);
|
||||
|
||||
/// swapchain context for a layer instance
|
||||
class Swapchain {
|
||||
public:
|
||||
/// create a new swapchain context
|
||||
/// @param vk vulkan instance
|
||||
/// @param profile active game profile
|
||||
/// @param backend lsfg-vk backend instance
|
||||
/// @param info swapchain info
|
||||
Swapchain(const vk::Vulkan& vk, lsfgvk::Instance& backend,
|
||||
const GameConf& profile, const SwapchainInfo& info);
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
#include "context/instance.hpp"
|
||||
#include "lsfg-vk-common/helpers/errors.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vk_layer.h>
|
||||
|
|
@ -15,26 +15,6 @@
|
|||
|
||||
using namespace lsfgvk;
|
||||
|
||||
namespace {
|
||||
/// helper function to add required extensions
|
||||
std::vector<const char*> add_extensions(const char* const* existingExtensions, size_t count,
|
||||
const std::vector<const char*>& requiredExtensions) {
|
||||
std::vector<const char*> extensions(count);
|
||||
std::copy_n(existingExtensions, count, extensions.data());
|
||||
|
||||
for (const auto& requiredExtension : requiredExtensions) {
|
||||
auto it = std::ranges::find_if(extensions,
|
||||
[requiredExtension](const char* extension) {
|
||||
return std::string(extension) == std::string(requiredExtension);
|
||||
});
|
||||
if (it == extensions.end())
|
||||
extensions.push_back(requiredExtension);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// global layer info initialized at layer negotiation
|
||||
struct LayerInfo {
|
||||
|
|
@ -94,26 +74,25 @@ namespace {
|
|||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
auto extensions = add_extensions(
|
||||
info->ppEnabledExtensionNames,
|
||||
info->enabledExtensionCount,
|
||||
layer_info->root.instanceExtensions());
|
||||
|
||||
VkInstanceCreateInfo newInfo = *info;
|
||||
newInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
newInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
||||
auto res = vkCreateInstance(&newInfo, alloc, instance);
|
||||
if (res == VK_ERROR_EXTENSION_NOT_PRESENT)
|
||||
std::cerr << "lsfg-vk: required Vulkan instance extensions are not present. "
|
||||
"Your GPU driver is not supported.\n";
|
||||
|
||||
if (res != VK_SUCCESS)
|
||||
return res;
|
||||
try {
|
||||
VkInstanceCreateInfo newInfo = *info;
|
||||
layer_info->root.modifyInstanceCreateInfo(newInfo,
|
||||
[=, newInfo = &newInfo]() {
|
||||
auto res = vkCreateInstance(newInfo, alloc, instance);
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "vkCreateInstance() failed");
|
||||
}
|
||||
);
|
||||
} catch (const ls::vulkan_error& e) {
|
||||
if (e.error() == VK_ERROR_EXTENSION_NOT_PRESENT)
|
||||
std::cerr << "lsfg-vk: required Vulkan instance extensions are not present. "
|
||||
"Your GPU driver is not supported.\n";
|
||||
return e.error();
|
||||
}
|
||||
|
||||
instance_info = new InstanceInfo{
|
||||
.handle = *instance,
|
||||
.funcs = vk::initVulkanInstanceFuncs(*instance, layer_info->GetInstanceProcAddr),
|
||||
.funcs = vk::initVulkanInstanceFuncs(*instance, layer_info->GetInstanceProcAddr, true),
|
||||
.devices = {}
|
||||
};
|
||||
return VK_SUCCESS;
|
||||
|
|
@ -171,22 +150,21 @@ namespace {
|
|||
}
|
||||
|
||||
// create device
|
||||
auto extensions = add_extensions(
|
||||
info->ppEnabledExtensionNames,
|
||||
info->enabledExtensionCount,
|
||||
layer_info->root.deviceExtensions());
|
||||
|
||||
VkDeviceCreateInfo newInfo = *info;
|
||||
newInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
newInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
||||
auto res = instance_info->funcs.CreateDevice(physdev, &newInfo, alloc, device);
|
||||
if (res == VK_ERROR_EXTENSION_NOT_PRESENT)
|
||||
std::cerr << "lsfg-vk: required Vulkan device extensions are not present. "
|
||||
"Your GPU driver is not supported.\n";
|
||||
|
||||
if (res != VK_SUCCESS)
|
||||
return res;
|
||||
try {
|
||||
VkDeviceCreateInfo newInfo = *info;
|
||||
layer_info->root.modifyDeviceCreateInfo(newInfo,
|
||||
[=, newInfo = &newInfo]() {
|
||||
auto res = instance_info->funcs.CreateDevice(physdev, newInfo, alloc, device);
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "vkCreateDevice() failed");
|
||||
}
|
||||
);
|
||||
} catch (const ls::vulkan_error& e) {
|
||||
if (e.error() == VK_ERROR_EXTENSION_NOT_PRESENT)
|
||||
std::cerr << "lsfg-vk: required Vulkan device extensions are not present. "
|
||||
"Your GPU driver is not supported.\n";
|
||||
return e.error();
|
||||
}
|
||||
|
||||
// create layer instance
|
||||
try {
|
||||
|
|
@ -194,7 +172,8 @@ namespace {
|
|||
*device,
|
||||
vk::Vulkan(
|
||||
instance_info->handle, *device, physdev,
|
||||
instance_info->funcs, vk::initVulkanDeviceFuncs(instance_info->funcs, *device),
|
||||
instance_info->funcs, vk::initVulkanDeviceFuncs(instance_info->funcs, *device,
|
||||
true),
|
||||
true, setLoaderData
|
||||
)
|
||||
);
|
||||
|
|
@ -260,30 +239,107 @@ namespace {
|
|||
}
|
||||
|
||||
// get instance-level function pointers
|
||||
PFN_vkVoidFunction myvkGetInstanceProcAddr(VkInstance instance, const char* pName) {
|
||||
if (!pName) return nullptr;
|
||||
PFN_vkVoidFunction myvkGetInstanceProcAddr(VkInstance instance, const char* name) {
|
||||
if (!name) return nullptr;
|
||||
|
||||
if (std::string(pName) == "vkCreateInstance") // pre-instance function
|
||||
if (std::string(name) == "vkCreateInstance") // pre-instance function
|
||||
return reinterpret_cast<PFN_vkVoidFunction>(myvkCreateInstance);
|
||||
|
||||
auto func = getProcAddr(pName);
|
||||
auto func = getProcAddr(name);
|
||||
if (func) return func;
|
||||
|
||||
if (!layer_info->GetInstanceProcAddr) return nullptr;
|
||||
return layer_info->GetInstanceProcAddr(instance, pName);
|
||||
return layer_info->GetInstanceProcAddr(instance, name);
|
||||
}
|
||||
|
||||
// get device-level function pointers
|
||||
PFN_vkVoidFunction myvkGetDeviceProcAddr(VkDevice device, const char* pName) {
|
||||
if (!pName) return nullptr;
|
||||
PFN_vkVoidFunction myvkGetDeviceProcAddr(VkDevice device, const char* name) {
|
||||
if (!name) return nullptr;
|
||||
|
||||
auto func = getProcAddr(pName);
|
||||
auto func = getProcAddr(name);
|
||||
if (func) return func;
|
||||
|
||||
if (!instance_info->funcs.GetDeviceProcAddr) return nullptr;
|
||||
return instance_info->funcs.GetDeviceProcAddr(device, pName);
|
||||
return instance_info->funcs.GetDeviceProcAddr(device, name);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
VkResult myvkCreateSwapchainKHR(
|
||||
VkDevice device,
|
||||
const VkSwapchainCreateInfoKHR* info,
|
||||
const VkAllocationCallbacks* alloc,
|
||||
VkSwapchainKHR* swapchain) {
|
||||
const auto& it = instance_info->devices.find(device);
|
||||
if (it == instance_info->devices.end())
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
|
||||
try {
|
||||
// retire old swapchain
|
||||
if (info->oldSwapchain)
|
||||
layer_info->root.removeSwapchainContext(info->oldSwapchain);
|
||||
|
||||
layer_info->root.update(); // ensure config is up to date
|
||||
|
||||
// create swapchain
|
||||
VkSwapchainCreateInfoKHR newInfo = *info;
|
||||
layer_info->root.modifySwapchainCreateInfo(it->second, newInfo,
|
||||
[=, newInfo = &newInfo]() {
|
||||
auto res = it->second.df().CreateSwapchainKHR(
|
||||
device, newInfo, alloc, swapchain);
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "vkCreateSwapchainKHR() failed");
|
||||
}
|
||||
);
|
||||
|
||||
// get all swapchain images
|
||||
uint32_t imageCount{};
|
||||
auto res = it->second.df().GetSwapchainImagesKHR(device, *swapchain,
|
||||
&imageCount, nullptr);
|
||||
if (res != VK_SUCCESS || imageCount == 0)
|
||||
throw ls::vulkan_error(res, "vkGetSwapchainImagesKHR() failed");
|
||||
|
||||
std::vector<VkImage> swapchainImages(imageCount);
|
||||
res = it->second.df().GetSwapchainImagesKHR(device, *swapchain,
|
||||
&imageCount, swapchainImages.data());
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "vkGetSwapchainImagesKHR() failed");
|
||||
|
||||
// create lsfg-vk swapchain
|
||||
layer_info->root.createSwapchainContext(it->second, *swapchain, {
|
||||
.images = std::move(swapchainImages),
|
||||
.format = newInfo.imageFormat,
|
||||
.colorSpace = newInfo.imageColorSpace,
|
||||
.extent = newInfo.imageExtent,
|
||||
.presentMode = newInfo.presentMode
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (const ls::vulkan_error& e) {
|
||||
std::cerr << "lsfg-vk: something went wrong during lsfg-vk swapchain creation:\n";
|
||||
std::cerr << "- " << e.what() << '\n';
|
||||
return e.error();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "lsfg-vk: something went wrong during lsfg-vk swapchain creation:\n";
|
||||
std::cerr << "- " << e.what() << '\n';
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
void myvkDestroySwapchainKHR(
|
||||
VkDevice device,
|
||||
VkSwapchainKHR swapchain,
|
||||
const VkAllocationCallbacks* alloc) {
|
||||
const auto& it = instance_info->devices.find(device);
|
||||
if (it == instance_info->devices.end())
|
||||
return;
|
||||
|
||||
// destroy lsfg-vk swapchain
|
||||
layer_info->root.removeSwapchainContext(swapchain);
|
||||
|
||||
// destroy swapchain
|
||||
it->second.df().DestroySwapchainKHR(device, swapchain, alloc);
|
||||
}
|
||||
}
|
||||
|
||||
/// Vulkan layer entrypoint
|
||||
|
|
@ -303,7 +359,9 @@ VkResult vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface* pVers
|
|||
{ "vkCreateInstance", VKPTR(myvkCreateInstance) },
|
||||
{ "vkCreateDevice", VKPTR(myvkCreateDevice) },
|
||||
{ "vkDestroyDevice", VKPTR(myvkDestroyDevice) },
|
||||
{ "vkDestroyInstance", VKPTR(myvkDestroyInstance) }
|
||||
{ "vkDestroyInstance", VKPTR(myvkDestroyInstance) },
|
||||
{ "vkCreateSwapchainKHR", VKPTR(myvkCreateSwapchainKHR) },
|
||||
{ "vkDestroySwapchainKHR", VKPTR(myvkDestroySwapchainKHR) }
|
||||
#undef VKPTR
|
||||
},
|
||||
.root = layer::Root()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue