mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-05-10 03:01:40 +00:00
feat(bindless): Implement updated backend in lsfg-vk-layer
This commit is contained in:
parent
fd0746c049
commit
50c3895c62
7 changed files with 241 additions and 227 deletions
|
|
@ -67,6 +67,10 @@ vk::PhysicalDevice vkhelper::findPhysicalDevice(
|
|||
|
||||
auto& props{info.properties};
|
||||
|
||||
// Check first if id is not given
|
||||
if (id.empty())
|
||||
return physdev;
|
||||
|
||||
// Compare device name
|
||||
props.deviceName.back() = '\0'; // Ensure null-termination
|
||||
if (id == std::string(props.deviceName))
|
||||
|
|
|
|||
|
|
@ -29,4 +29,3 @@ Checks:
|
|||
# Vulkan layers often require C-style memory access
|
||||
- -cppcoreguidelines-pro-bounds-pointer-arithmetic
|
||||
- -cppcoreguidelines-pro-type-union-access
|
||||
- -clang-diagnostic-unsafe-buffer-usage
|
||||
|
|
|
|||
|
|
@ -22,17 +22,17 @@
|
|||
using namespace lsfgvk::layer;
|
||||
|
||||
namespace {
|
||||
// global layer info initialized at layer negotiation
|
||||
/// Global layer info initialized at layer negotiation
|
||||
struct LayerInfo {
|
||||
std::unordered_map<std::string, PFN_vkVoidFunction> map; //!< function pointer override map
|
||||
std::unordered_map<std::string, PFN_vkVoidFunction> map; //!< Function pointer override map
|
||||
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
||||
|
||||
Root root;
|
||||
}* layer_info; // NOLINT (global variable)
|
||||
|
||||
// instance-wide info initialized at instance creation(s)
|
||||
/// Instance-wide info initialized at instance creation(s)
|
||||
struct InstanceInfo {
|
||||
std::vector<VkInstance> handles; // there may be several instances
|
||||
std::vector<VkInstance> handles; // There may be several instances
|
||||
vk::VulkanInstanceFuncs funcs;
|
||||
|
||||
std::unordered_map<VkDevice, vk::Vulkan> devices;
|
||||
|
|
@ -40,44 +40,44 @@ namespace {
|
|||
std::unordered_map<VkSwapchainKHR, SwapchainInfo> swapchainInfos;
|
||||
}* instance_info; // NOLINT (global variable)
|
||||
|
||||
// create instance
|
||||
/// Create instance
|
||||
VkResult myvkCreateInstance(
|
||||
const VkInstanceCreateInfo* info,
|
||||
const VkAllocationCallbacks* alloc,
|
||||
VkInstance* instance) {
|
||||
// apply layer chaining
|
||||
// Apply layer chaining
|
||||
auto* layerInfo = reinterpret_cast<VkLayerInstanceCreateInfo*>(const_cast<void*>(info->pNext));
|
||||
while (layerInfo && (layerInfo->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
|
||||
|| layerInfo->function != VK_LAYER_LINK_INFO)) {
|
||||
layerInfo = reinterpret_cast<VkLayerInstanceCreateInfo*>(const_cast<void*>(layerInfo->pNext));
|
||||
}
|
||||
if (!layerInfo) {
|
||||
std::cerr << "lsfg-vk: no layer info found in pNext chain, "
|
||||
std::cerr << "lsfg-vk: No layer info found in pNext chain, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
auto* linkInfo = layerInfo->u.pLayerInfo;
|
||||
if (!linkInfo) {
|
||||
std::cerr << "lsfg-vk: link info is null, "
|
||||
std::cerr << "lsfg-vk: Link info is null, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
layer_info->GetInstanceProcAddr = linkInfo->pfnNextGetInstanceProcAddr;
|
||||
if (!layer_info->GetInstanceProcAddr) {
|
||||
std::cerr << "lsfg-vk: next layer's vkGetInstanceProcAddr is null, "
|
||||
std::cerr << "lsfg-vk: Next layer's vkGetInstanceProcAddr is null, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
layerInfo->u.pLayerInfo = linkInfo->pNext; // advance for next layer
|
||||
layerInfo->u.pLayerInfo = linkInfo->pNext; // Advance for next layer
|
||||
|
||||
// create instance
|
||||
// Create instance
|
||||
auto* vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(
|
||||
layer_info->GetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance"));
|
||||
if (!vkCreateInstance) {
|
||||
std::cerr << "lsfg-vk: failed to get next layer's vkCreateInstance, "
|
||||
std::cerr << "lsfg-vk: Failed to get next layer's vkCreateInstance, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
|
@ -103,64 +103,64 @@ namespace {
|
|||
return VK_SUCCESS;
|
||||
} 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. "
|
||||
std::cerr << "lsfg-vk: Required Vulkan instance extensions are not present. "
|
||||
"Your GPU driver is not supported.\n";
|
||||
return e.error();
|
||||
}
|
||||
}
|
||||
|
||||
// create device
|
||||
/// Create device
|
||||
VkResult myvkCreateDevice(
|
||||
VkPhysicalDevice physdev,
|
||||
const VkDeviceCreateInfo* info,
|
||||
const VkAllocationCallbacks* alloc,
|
||||
VkDevice* device) {
|
||||
// apply layer chaining
|
||||
// Apply layer chaining
|
||||
auto* layerInfo = reinterpret_cast<VkLayerDeviceCreateInfo*>(const_cast<void*>(info->pNext));
|
||||
while (layerInfo && (layerInfo->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
|
||||
|| layerInfo->function != VK_LAYER_LINK_INFO)) {
|
||||
layerInfo = reinterpret_cast<VkLayerDeviceCreateInfo*>(const_cast<void*>(layerInfo->pNext));
|
||||
}
|
||||
if (!layerInfo) {
|
||||
std::cerr << "lsfg-vk: no layer info found in pNext chain, "
|
||||
std::cerr << "lsfg-vk: No layer info found in pNext chain, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
auto* linkInfo = layerInfo->u.pLayerInfo;
|
||||
if (!linkInfo) {
|
||||
std::cerr << "lsfg-vk: link info is null, "
|
||||
std::cerr << "lsfg-vk: Link info is null, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
instance_info->funcs.GetDeviceProcAddr = linkInfo->pfnNextGetDeviceProcAddr;
|
||||
if (!linkInfo->pfnNextGetDeviceProcAddr) {
|
||||
std::cerr << "lsfg-vk: next layer's vkGetDeviceProcAddr is null, "
|
||||
std::cerr << "lsfg-vk: Next layer's vkGetDeviceProcAddr is null, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
layerInfo->u.pLayerInfo = linkInfo->pNext; // advance for next layer
|
||||
layerInfo->u.pLayerInfo = linkInfo->pNext; // Advance for next layer
|
||||
|
||||
// fetch device loader functions
|
||||
// Fetch device loader functions
|
||||
layerInfo = reinterpret_cast<VkLayerDeviceCreateInfo*>(const_cast<void*>(info->pNext));
|
||||
while (layerInfo && (layerInfo->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
|
||||
|| layerInfo->function != VK_LOADER_DATA_CALLBACK)) {
|
||||
layerInfo = reinterpret_cast<VkLayerDeviceCreateInfo*>(const_cast<void*>(layerInfo->pNext));
|
||||
}
|
||||
if (!layerInfo) {
|
||||
std::cerr << "lsfg-vk: no layer loader data found in pNext chain.\n";
|
||||
std::cerr << "lsfg-vk: No layer loader data found in pNext chain.\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
auto* setLoaderData = layerInfo->u.pfnSetDeviceLoaderData;
|
||||
if (!setLoaderData) {
|
||||
std::cerr << "lsfg-vk: instance loader data function is null.\n";
|
||||
std::cerr << "lsfg-vk: Instance loader data function is null.\n";
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
// create device
|
||||
// Create device
|
||||
try {
|
||||
VkDeviceCreateInfo newInfo = *info;
|
||||
layer_info->root.modifyDeviceCreateInfo(newInfo,
|
||||
|
|
@ -172,12 +172,12 @@ namespace {
|
|||
);
|
||||
} 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. "
|
||||
std::cerr << "lsfg-vk: Required Vulkan device extensions are not present. "
|
||||
"Your GPU driver is not supported.\n";
|
||||
return e.error();
|
||||
}
|
||||
|
||||
// create layer instance
|
||||
// Create layer instance
|
||||
try {
|
||||
instance_info->devices.emplace(
|
||||
*device,
|
||||
|
|
@ -189,25 +189,25 @@ namespace {
|
|||
)
|
||||
);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "lsfg-vk: something went wrong during lsfg-vk initialization:\n";
|
||||
std::cerr << "lsfg-vk: Something went wrong during lsfg-vk initialization:\n";
|
||||
std::cerr << "- " << e.what() << '\n';
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
// destroy device
|
||||
/// Destroy device
|
||||
void myvkDestroyDevice(VkDevice device, const VkAllocationCallbacks* alloc) {
|
||||
// destroy layer instance
|
||||
// Destroy layer instance
|
||||
auto it = instance_info->devices.find(device);
|
||||
if (it != instance_info->devices.end())
|
||||
instance_info->devices.erase(it);
|
||||
|
||||
// destroy device
|
||||
// Destroy device
|
||||
auto vkDestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
|
||||
instance_info->funcs.GetDeviceProcAddr(device, "vkDestroyDevice"));
|
||||
if (!vkDestroyDevice) {
|
||||
std::cerr << "lsfg-vk: failed to get next layer's vkDestroyDevice, "
|
||||
std::cerr << "lsfg-vk: Failed to get next layer's vkDestroyDevice, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return;
|
||||
}
|
||||
|
|
@ -215,24 +215,24 @@ namespace {
|
|||
vkDestroyDevice(device, alloc);
|
||||
}
|
||||
|
||||
// destroy instance
|
||||
/// Destroy instance
|
||||
void myvkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* alloc) {
|
||||
// remove instance handle
|
||||
// Remove instance handle
|
||||
auto it = std::ranges::find(instance_info->handles, instance);
|
||||
if (it != instance_info->handles.end())
|
||||
instance_info->handles.erase(it);
|
||||
|
||||
// destroy instance info if no handles remain
|
||||
// Destroy instance info if no handles remain
|
||||
if (instance_info->handles.empty()) {
|
||||
delete instance_info; // NOLINT (memory management)
|
||||
instance_info = nullptr;
|
||||
}
|
||||
|
||||
// destroy instance
|
||||
// Destroy instance
|
||||
auto vkDestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
|
||||
layer_info->GetInstanceProcAddr(instance, "vkDestroyInstance"));
|
||||
if (!vkDestroyInstance) {
|
||||
std::cerr << "lsfg-vk: failed to get next layer's vkDestroyInstance, "
|
||||
std::cerr << "lsfg-vk: Failed to get next layer's vkDestroyInstance, "
|
||||
"the previous layer does not follow spec\n";
|
||||
return;
|
||||
}
|
||||
|
|
@ -240,7 +240,7 @@ namespace {
|
|||
vkDestroyInstance(instance, alloc);
|
||||
}
|
||||
|
||||
// get optional function pointer override
|
||||
/// Get optional function pointer override
|
||||
PFN_vkVoidFunction getProcAddr(const std::string& name) {
|
||||
auto it = layer_info->map.find(name);
|
||||
if (it != layer_info->map.end())
|
||||
|
|
@ -248,7 +248,7 @@ namespace {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// get instance-level function pointers
|
||||
/// Get instance-level function pointers
|
||||
PFN_vkVoidFunction myvkGetInstanceProcAddr(VkInstance instance, const char* name) {
|
||||
if (!name) return nullptr;
|
||||
|
||||
|
|
@ -259,7 +259,7 @@ namespace {
|
|||
return layer_info->GetInstanceProcAddr(instance, name);
|
||||
}
|
||||
|
||||
// get device-level function pointers
|
||||
/// Get device-level function pointers
|
||||
PFN_vkVoidFunction myvkGetDeviceProcAddr(VkDevice device, const char* name) {
|
||||
if (!name) return nullptr;
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ namespace {
|
|||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
|
||||
try {
|
||||
// retire old swapchain
|
||||
// Retire old swapchain
|
||||
if (info->oldSwapchain) {
|
||||
const auto& info_mapping = instance_info->swapchainInfos.find(info->oldSwapchain);
|
||||
if (info_mapping != instance_info->swapchainInfos.end())
|
||||
|
|
@ -295,9 +295,9 @@ namespace {
|
|||
layer_info->root.removeSwapchainContext(info->oldSwapchain);
|
||||
}
|
||||
|
||||
layer_info->root.update(); // ensure config is up to date
|
||||
layer_info->root.update(); // Ensure config is up to date
|
||||
|
||||
// create swapchain
|
||||
// Create swapchain
|
||||
VkSwapchainCreateInfoKHR newInfo = *info;
|
||||
layer_info->root.modifySwapchainCreateInfo(it->second, newInfo,
|
||||
[=, newInfo = &newInfo]() {
|
||||
|
|
@ -308,7 +308,7 @@ namespace {
|
|||
}
|
||||
);
|
||||
|
||||
// get all swapchain images
|
||||
// Get all swapchain images
|
||||
uint32_t imageCount{};
|
||||
auto res = it->second.df().GetSwapchainImagesKHR(device, *swapchain,
|
||||
&imageCount, VK_NULL_HANDLE);
|
||||
|
|
@ -329,7 +329,7 @@ namespace {
|
|||
.presentMode = newInfo.presentMode
|
||||
}).first->second;
|
||||
|
||||
// create lsfg-vk swapchain
|
||||
// Create lsfg-vk swapchain
|
||||
layer_info->root.createSwapchainContext(it->second, *swapchain, info);
|
||||
|
||||
instance_info->swapchains.emplace(*swapchain,
|
||||
|
|
@ -337,11 +337,11 @@ namespace {
|
|||
|
||||
return res;
|
||||
} catch (const ls::vulkan_error& e) {
|
||||
std::cerr << "lsfg-vk: something went wrong during lsfg-vk swapchain creation:\n";
|
||||
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 << "lsfg-vk: Something went wrong during lsfg-vk swapchain creation:\n";
|
||||
std::cerr << "- " << e.what() << '\n';
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
|
@ -352,12 +352,12 @@ namespace {
|
|||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
// ensure layer config is up to date
|
||||
// Ensure layer config is up to date
|
||||
bool reload{};
|
||||
try {
|
||||
reload = layer_info->root.update();
|
||||
} catch (const std::exception&) {
|
||||
reload = false; // ignore parse errors
|
||||
reload = false; // Ignore parse errors
|
||||
}
|
||||
|
||||
if (reload) {
|
||||
|
|
@ -376,7 +376,7 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
// present each swapchain
|
||||
// Present each swapchain
|
||||
for (size_t i = 0; i < info->swapchainCount; i++) {
|
||||
const auto& swapchain = info->pSwapchains[i];
|
||||
|
||||
|
|
@ -402,7 +402,7 @@ namespace {
|
|||
if (e.error() != VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
std::cerr << "lsfg-vk: something went wrong during lsfg-vk swapchain presentation:\n";
|
||||
std::cerr << "- " << e.what() << '\n';
|
||||
} // silently swallow out-of-date errors
|
||||
} // Silently swallow out-of-date errors
|
||||
|
||||
result = e.error();
|
||||
} catch (const std::exception& e) {
|
||||
|
|
@ -437,7 +437,7 @@ namespace {
|
|||
|
||||
layer_info->root.removeSwapchainContext(swapchain);
|
||||
|
||||
// destroy swapchain
|
||||
// Destroy swapchain
|
||||
it->second.df().DestroySwapchainKHR(device, swapchain, alloc);
|
||||
}
|
||||
}
|
||||
|
|
@ -445,13 +445,13 @@ namespace {
|
|||
/// Vulkan layer entrypoint
|
||||
__attribute__((visibility("default")))
|
||||
VkResult vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface* pVersionStruct) {
|
||||
// ensure loader compatibility
|
||||
// Ensure loader compatibility
|
||||
if (!pVersionStruct
|
||||
|| pVersionStruct->sType != LAYER_NEGOTIATE_INTERFACE_STRUCT
|
||||
|| pVersionStruct->loaderLayerInterfaceVersion < 2)
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
|
||||
// if the layer has already been initialized, skip
|
||||
// If the layer has already been initialized, skip
|
||||
if (layer_info) {
|
||||
pVersionStruct->loaderLayerInterfaceVersion = 2;
|
||||
pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
|
||||
|
|
@ -460,7 +460,7 @@ VkResult vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface* pVers
|
|||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
// load the layer configuration
|
||||
// Load the layer configuration
|
||||
try {
|
||||
layer_info = new LayerInfo { // NOLINT (memory management)
|
||||
.map = {
|
||||
|
|
@ -477,20 +477,20 @@ VkResult vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface* pVers
|
|||
.root = Root()
|
||||
};
|
||||
|
||||
if (!layer_info->root.active()) { // skip inactive
|
||||
if (!layer_info->root.active()) { // Skip inactive
|
||||
delete layer_info; // NOLINT (memory management)
|
||||
layer_info = nullptr;
|
||||
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "lsfg-vk: something went wrong during lsfg-vk layer initialization:\n";
|
||||
std::cerr << "lsfg-vk: Something went wrong during lsfg-vk layer initialization:\n";
|
||||
std::cerr << "- " << e.what() << '\n';
|
||||
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
// emplace function pointers/version
|
||||
// Emplace function pointers/version
|
||||
pVersionStruct->loaderLayerInterfaceVersion = 2;
|
||||
pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
|
||||
pVersionStruct->pfnGetDeviceProcAddr = myvkGetDeviceProcAddr;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
#include "instance.hpp"
|
||||
#include "lsfg-vk-common/helpers/paths.hpp"
|
||||
#include "swapchain.hpp"
|
||||
#include "lsfg-vk-common/configuration/detection.hpp"
|
||||
#include "lsfg-vk-common/helpers/errors.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
|
@ -25,7 +25,7 @@ using namespace lsfgvk;
|
|||
using namespace lsfgvk::layer;
|
||||
|
||||
namespace {
|
||||
/// helper function to add required extensions
|
||||
/// 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);
|
||||
|
|
@ -45,14 +45,14 @@ namespace {
|
|||
}
|
||||
|
||||
Root::Root() {
|
||||
// find active profile
|
||||
// Find active profile
|
||||
const auto& profile = findProfile(this->config.get(), ls::identify());
|
||||
if (!profile.has_value())
|
||||
return;
|
||||
|
||||
this->active_profile = profile->second;
|
||||
|
||||
std::cerr << "lsfg-vk: using profile with name '" << this->active_profile->name << "' ";
|
||||
std::cerr << "lsfg-vk: Using profile with name '" << this->active_profile->name << "' ";
|
||||
switch (profile->first) {
|
||||
case ls::IdentType::OVERRIDE:
|
||||
std::cerr << "(identified via override)\n";
|
||||
|
|
@ -167,10 +167,10 @@ void Root::modifySwapchainCreateInfo(const vk::Vulkan& vk, VkSwapchainCreateInfo
|
|||
void Root::createSwapchainContext(const vk::Vulkan& vk,
|
||||
VkSwapchainKHR swapchain, const SwapchainInfo& info) {
|
||||
if (!this->active_profile.has_value())
|
||||
throw ls::error("attempted to create swapchain context while layer is inactive");
|
||||
throw ls::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
|
||||
if (!this->backend.has_value()) { // Emplace backend late, due to loader bug
|
||||
const auto& global = this->config.get().global();
|
||||
|
||||
setenv("DISABLE_LSFGVK", "1", 1);
|
||||
|
|
@ -183,23 +183,12 @@ void Root::createSwapchainContext(const vk::Vulkan& vk,
|
|||
dll = ls::findShaderDll();
|
||||
|
||||
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);
|
||||
},
|
||||
profile.gpu.value_or(""),
|
||||
dll, global.allow_fp16
|
||||
);
|
||||
} catch (const std::exception& e) {
|
||||
unsetenv("DISABLE_LSFGVK");
|
||||
throw ls::error("failed to create backend instance", e);
|
||||
throw ls::error("Failed to create backend instance", e);
|
||||
}
|
||||
|
||||
unsetenv("DISABLE_LSFGVK");
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/configuration/config.hpp"
|
||||
#include "lsfg-vk-common/helpers/errors.hpp"
|
||||
#include "lsfg-vk-common/helpers/pointers.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
|
|
@ -16,49 +17,75 @@
|
|||
|
||||
namespace lsfgvk::layer {
|
||||
|
||||
/// root context of the lsfg-vk layer
|
||||
///
|
||||
/// Root context of the lsfg-vk layer
|
||||
///
|
||||
class Root {
|
||||
public:
|
||||
/// create the lsfg-vk root context
|
||||
///
|
||||
/// Create the lsfg-vk root context
|
||||
///
|
||||
/// @throws ls::error on failure
|
||||
///
|
||||
Root();
|
||||
|
||||
/// check if the layer is active
|
||||
/// @return true if active
|
||||
///
|
||||
/// Check if the layer is active
|
||||
///
|
||||
/// @return true If active
|
||||
///
|
||||
[[nodiscard]] bool active() const { return this->active_profile.has_value(); }
|
||||
|
||||
/// ensure the layer is up-to-date
|
||||
/// @return true if the configuration was updated
|
||||
///
|
||||
/// Ensure the layer is up-to-date
|
||||
///
|
||||
/// @return true If the configuration was updated
|
||||
///
|
||||
bool update();
|
||||
|
||||
/// modify instance create info
|
||||
/// @param createInfo original create info
|
||||
/// @param finish function to call after modification
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// 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
|
||||
|
||||
///
|
||||
/// Create swapchain context
|
||||
///
|
||||
/// @param vk Vulkan instance
|
||||
/// @param swapchain Swapchain handle
|
||||
/// @param info Swapchain info
|
||||
/// @throws ls::error on failure
|
||||
///
|
||||
void createSwapchainContext(const vk::Vulkan& vk, VkSwapchainKHR swapchain,
|
||||
const SwapchainInfo& info);
|
||||
/// get swapchain context
|
||||
/// @param swapchain swapchain handle
|
||||
/// @return swapchain context
|
||||
///
|
||||
/// Get swapchain context
|
||||
///
|
||||
/// @param swapchain Swapchain handle
|
||||
/// @return swapchain Context
|
||||
/// @throws ls::error if not found
|
||||
///
|
||||
[[nodiscard]] Swapchain& getSwapchainContext(VkSwapchainKHR swapchain) {
|
||||
const auto& it = this->swapchains.find(swapchain);
|
||||
if (it == this->swapchains.end())
|
||||
|
|
@ -66,14 +93,17 @@ namespace lsfgvk::layer {
|
|||
|
||||
return it->second;
|
||||
}
|
||||
/// remove swapchain context
|
||||
/// @param swapchain swapchain handle
|
||||
///
|
||||
/// Remove swapchain context
|
||||
///
|
||||
/// @param swapchain Swapchain handle
|
||||
///
|
||||
void removeSwapchainContext(VkSwapchainKHR swapchain);
|
||||
private:
|
||||
ls::WatchedConfig config;
|
||||
std::optional<ls::GameConf> active_profile;
|
||||
|
||||
ls::lazy<backend::Instance> backend;
|
||||
ls::lazy<lsfgvk::Instance> backend;
|
||||
std::unordered_map<VkSwapchainKHR, Swapchain> swapchains;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#include "swapchain.hpp"
|
||||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/configuration/config.hpp"
|
||||
#include "lsfg-vk-common/helpers/errors.hpp"
|
||||
#include "lsfg-vk-common/helpers/pointers.hpp"
|
||||
|
|
@ -10,11 +10,10 @@
|
|||
#include "lsfg-vk-common/vulkan/semaphore.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
|
@ -25,6 +24,7 @@ using namespace lsfgvk;
|
|||
using namespace lsfgvk::layer;
|
||||
|
||||
namespace {
|
||||
/// Barrier helper
|
||||
VkImageMemoryBarrier barrierHelper(VkImage handle,
|
||||
VkAccessFlags srcAccessMask,
|
||||
VkAccessFlags dstAccessMask,
|
||||
|
|
@ -66,66 +66,45 @@ void layer::context_ModifySwapchainCreateInfo(const ls::GameConf& profile, uint3
|
|||
}
|
||||
}
|
||||
|
||||
Swapchain::Swapchain(const vk::Vulkan& vk, backend::Instance& backend,
|
||||
Swapchain::Swapchain(const vk::Vulkan& vk, lsfgvk::Instance& backend,
|
||||
ls::GameConf profile, SwapchainInfo info) :
|
||||
instance(backend),
|
||||
profile(std::move(profile)), info(std::move(info)) {
|
||||
const VkExtent2D extent = this->info.extent;
|
||||
const bool hdr = this->info.format > 57;
|
||||
|
||||
std::vector<int> sourceFds(2);
|
||||
std::vector<int> destinationFds(this->profile.multiplier - 1);
|
||||
|
||||
this->sourceImages.reserve(sourceFds.size());
|
||||
for (int& fd : sourceFds)
|
||||
this->sourceImages.emplace_back(vk,
|
||||
extent, hdr ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
std::nullopt, &fd);
|
||||
|
||||
this->destinationImages.reserve(destinationFds.size());
|
||||
for (int& fd : destinationFds)
|
||||
this->destinationImages.emplace_back(vk,
|
||||
extent, hdr ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
std::nullopt, &fd);
|
||||
|
||||
int syncFd{};
|
||||
this->syncSemaphore.emplace(vk, 0, std::nullopt, &syncFd);
|
||||
|
||||
try {
|
||||
this->ctx = ls::owned_ptr<ls::R<backend::Context>>(
|
||||
new ls::R<backend::Context>(backend.openContext(
|
||||
{ sourceFds.at(0), sourceFds.at(1) }, destinationFds, syncFd,
|
||||
extent.width, extent.height,
|
||||
hdr, 1.0F / this->profile.flow_scale, this->profile.performance_mode
|
||||
)),
|
||||
[backend = &backend](ls::R<backend::Context>& ctx) {
|
||||
backend->closeContext(ctx);
|
||||
}
|
||||
this->ctx = std::make_unique<lsfgvk::Context>(
|
||||
backend,
|
||||
extent.width, extent.height,
|
||||
this->profile.flow_scale,
|
||||
this->profile.performance_mode
|
||||
);
|
||||
|
||||
backend::makeLeaking(); // don't worry about it :3
|
||||
this->total = static_cast<uint32_t>(this->profile.multiplier) - 1;
|
||||
} catch (const std::exception& e) {
|
||||
throw ls::error("failed to create swapchain context", e);
|
||||
throw ls::error("Failed to create swapchain context", e);
|
||||
}
|
||||
|
||||
const auto exportedFds = this->ctx->exportFds();
|
||||
this->sourceImage.emplace(vk,
|
||||
extent, VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
exportedFds.sourceFd, std::nullopt, 2);
|
||||
this->destinationImage.emplace(vk,
|
||||
extent, VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
exportedFds.destinationFd, std::nullopt, 2); // FIXME: Should be 1
|
||||
this->syncSemaphore.emplace(vk, 0, exportedFds.syncFd);
|
||||
|
||||
this->renderCommandBuffer.emplace(vk);
|
||||
this->renderFence.emplace(vk);
|
||||
for (size_t i = 0; i < this->destinationImages.size(); i++) {
|
||||
this->finalSemaphore.emplace(vk);
|
||||
for (size_t i = 0; i < this->total; i++) {
|
||||
this->passes.emplace_back(RenderPass {
|
||||
.commandBuffer = vk::CommandBuffer(vk),
|
||||
.acquireSemaphore = vk::Semaphore(vk)
|
||||
.acquireSemaphore = vk::Semaphore(vk),
|
||||
.copySemaphore = vk::Semaphore(vk)
|
||||
});
|
||||
}
|
||||
|
||||
const size_t frames = std::max(this->info.images.size(), this->destinationImages.size() + 2);
|
||||
for (size_t i = 0; i < frames; i++) {
|
||||
this->postCopySemaphores.emplace_back(
|
||||
vk::Semaphore(vk),
|
||||
vk::Semaphore(vk)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
VkResult Swapchain::present(const vk::Vulkan& vk,
|
||||
|
|
@ -133,19 +112,18 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
void* next_chain, uint32_t imageIdx,
|
||||
const std::vector<VkSemaphore>& semaphores) {
|
||||
const auto& swapchainImage = this->info.images.at(imageIdx);
|
||||
const auto& sourceImage = this->sourceImages.at(this->fidx % 2);
|
||||
const auto sourceImageIdx{static_cast<uint32_t>(this->iteration) % 2};
|
||||
|
||||
// schedule frame generation
|
||||
// Schedule frame generation
|
||||
try {
|
||||
this->instance.get().scheduleFrames(this->ctx.get());
|
||||
this->ctx->dispatch(this->total);
|
||||
} catch (const std::exception& e) {
|
||||
throw ls::error("failed to schedule frames", e);
|
||||
throw ls::error("Failed to schedule frames", e);
|
||||
}
|
||||
|
||||
// update present mode when not using pacing
|
||||
// Update present mode when not using pacing
|
||||
if (this->profile.pacing == ls::Pacing::None) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
auto* info = reinterpret_cast<VkSwapchainPresentModeInfoEXT*>(next_chain);
|
||||
while (info) {
|
||||
|
|
@ -160,12 +138,12 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
// wait for completion of previous frame
|
||||
if (this->fidx && !this->renderFence->wait(vk, 150ULL * 1000 * 1000))
|
||||
// Wait for completion of previous frame
|
||||
if (this->iteration && !this->renderFence->wait(vk, 150ULL * 1000 * 1000))
|
||||
throw ls::vulkan_error(VK_TIMEOUT, "vkWaitForFences() failed");
|
||||
this->renderFence->reset(vk);
|
||||
|
||||
// copy swapchain image into backend source image
|
||||
// Copy swapchain image into backend source image
|
||||
const auto& cmdbuf = *this->renderCommandBuffer;
|
||||
cmdbuf.begin(vk);
|
||||
|
||||
|
|
@ -177,15 +155,15 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
|
||||
),
|
||||
barrierHelper(sourceImage.handle(),
|
||||
barrierHelper(this->sourceImage->handle(),
|
||||
VK_ACCESS_NONE,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
|
||||
),
|
||||
},
|
||||
{ swapchainImage, sourceImage.handle() },
|
||||
sourceImage.getExtent(),
|
||||
{ swapchainImage, this->sourceImage->handle() },
|
||||
this->sourceImage->getExtent(),
|
||||
{
|
||||
barrierHelper(swapchainImage,
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
|
|
@ -193,39 +171,40 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
||||
),
|
||||
}
|
||||
},
|
||||
0, sourceImageIdx
|
||||
);
|
||||
|
||||
cmdbuf.end(vk);
|
||||
|
||||
cmdbuf.submit(vk,
|
||||
semaphores, VK_NULL_HANDLE, 0,
|
||||
{}, this->syncSemaphore->handle(), this->idx++
|
||||
{}, this->syncSemaphore->handle(), this->syncValue
|
||||
);
|
||||
|
||||
for (size_t i = 0; i < this->destinationImages.size(); i++) {
|
||||
auto& pcs = this->postCopySemaphores.at(this->idx % this->postCopySemaphores.size());
|
||||
auto& destinationImage = this->destinationImages.at(i);
|
||||
auto& pass = this->passes.at(i);
|
||||
for (size_t i = 0; i < this->passes.size(); i++) {
|
||||
auto& pass{this->passes.at(i)};
|
||||
const bool last{i == (this->passes.size() - 1)};
|
||||
|
||||
// acquire swapchain image
|
||||
uint32_t aqImageIdx{};
|
||||
// Acquire swapchain image
|
||||
uint32_t swapchainImageIdx{};
|
||||
auto res = vk.df().AcquireNextImageKHR(vk.dev(), swapchain,
|
||||
UINT64_MAX, pass.acquireSemaphore.handle(),
|
||||
VK_NULL_HANDLE,
|
||||
&aqImageIdx
|
||||
&swapchainImageIdx
|
||||
);
|
||||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||
throw ls::vulkan_error(res, "vkAcquireNextImageKHR() failed");
|
||||
|
||||
const auto& aquiredSwapchainImage = this->info.images.at(aqImageIdx);
|
||||
const auto& aquiredSwapchainImage = this->info.images.at(swapchainImageIdx);
|
||||
|
||||
// copy backend destination image into swapchain image
|
||||
// Copy backend destination image into swapchain image
|
||||
auto& cmdbuf = pass.commandBuffer;
|
||||
cmdbuf.begin(vk);
|
||||
|
||||
cmdbuf.blitImage(vk,
|
||||
{
|
||||
barrierHelper(destinationImage.handle(),
|
||||
barrierHelper(this->destinationImage->handle(),
|
||||
VK_ACCESS_NONE,
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
|
|
@ -238,8 +217,8 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
|
||||
),
|
||||
},
|
||||
{ destinationImage.handle(), aquiredSwapchainImage },
|
||||
destinationImage.getExtent(),
|
||||
{ this->destinationImage->handle(), aquiredSwapchainImage },
|
||||
this->destinationImage->getExtent(),
|
||||
{
|
||||
barrierHelper(aquiredSwapchainImage,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
|
|
@ -250,48 +229,43 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
}
|
||||
);
|
||||
|
||||
std::vector<VkSemaphore> waitSemaphores{ pass.acquireSemaphore.handle() };
|
||||
if (i) { // non-first pass
|
||||
const auto& prevPCS = this->postCopySemaphores.at((this->idx - 1) % this->postCopySemaphores.size());
|
||||
waitSemaphores.push_back(prevPCS.second.handle());
|
||||
}
|
||||
|
||||
const std::vector<VkSemaphore> signalSemaphores{
|
||||
pcs.first.handle(),
|
||||
pcs.second.handle()
|
||||
};
|
||||
|
||||
cmdbuf.end(vk);
|
||||
|
||||
std::vector<VkSemaphore> signalSemaphores{ pass.copySemaphore.handle() };
|
||||
if (last)
|
||||
signalSemaphores.push_back(this->finalSemaphore->handle());
|
||||
|
||||
this->syncValue++;
|
||||
|
||||
cmdbuf.submit(vk,
|
||||
waitSemaphores, this->syncSemaphore->handle(), this->idx,
|
||||
signalSemaphores, VK_NULL_HANDLE, 0,
|
||||
i == this->destinationImages.size() - 1 ? this->renderFence->handle() : VK_NULL_HANDLE
|
||||
{ pass.acquireSemaphore.handle() }, this->syncSemaphore->handle(), this->syncValue,
|
||||
signalSemaphores, last ? nullptr : this->syncSemaphore->handle(), this->syncValue + 1,
|
||||
last ? this->renderFence->handle() : VK_NULL_HANDLE
|
||||
);
|
||||
|
||||
// present swapchain image
|
||||
this->syncValue++;
|
||||
|
||||
// Present swapchain image
|
||||
const VkPresentInfoKHR presentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = i ? nullptr : next_chain,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &pcs.first.handle(),
|
||||
.pWaitSemaphores = &pass.copySemaphore.handle(),
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain,
|
||||
.pImageIndices = &aqImageIdx,
|
||||
.pImageIndices = &swapchainImageIdx,
|
||||
};
|
||||
res = vk.df().QueuePresentKHR(queue,
|
||||
&presentInfo);
|
||||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||
throw ls::vulkan_error(res, "vkQueuePresentKHR() failed");
|
||||
|
||||
this->idx++;
|
||||
}
|
||||
|
||||
// present original swapchain image
|
||||
auto& lastPCS = this->postCopySemaphores.at((this->idx - 1) % this->postCopySemaphores.size());
|
||||
// Present original swapchain image
|
||||
const VkPresentInfoKHR presentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &lastPCS.second.handle(),
|
||||
.pWaitSemaphores = &this->finalSemaphore->handle(),
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain,
|
||||
.pImageIndices = &imageIdx,
|
||||
|
|
@ -300,6 +274,7 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||
throw ls::vulkan_error(res, "vkQueuePresentKHR() failed");
|
||||
|
||||
this->fidx++;
|
||||
this->iteration++;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/configuration/config.hpp"
|
||||
#include "lsfg-vk-common/helpers/pointers.hpp"
|
||||
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
|
||||
|
|
@ -12,15 +12,18 @@
|
|||
#include "lsfg-vk-common/vulkan/timeline_semaphore.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
namespace lsfgvk::layer {
|
||||
|
||||
/// swapchain info struct
|
||||
///
|
||||
/// Swapchain info struct
|
||||
///
|
||||
struct SwapchainInfo {
|
||||
std::vector<VkImage> images;
|
||||
VkFormat format;
|
||||
|
|
@ -29,53 +32,67 @@ namespace lsfgvk::layer {
|
|||
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
|
||||
///
|
||||
/// 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 ls::GameConf& profile, uint32_t maxImages,
|
||||
VkSwapchainCreateInfoKHR& createInfo);
|
||||
|
||||
/// swapchain context for a layer instance
|
||||
///
|
||||
/// Swapchain context for a layer instance
|
||||
///
|
||||
class Swapchain {
|
||||
public:
|
||||
/// create a new swapchain context
|
||||
/// @param vk vulkan instance
|
||||
///
|
||||
/// Create a new swapchain context
|
||||
///
|
||||
/// @param vk Vulkan instance
|
||||
/// @param backend lsfg-vk backend instance
|
||||
/// @param profile active game profile
|
||||
/// @param info swapchain info
|
||||
Swapchain(const vk::Vulkan& vk, backend::Instance& backend,
|
||||
/// @param profile Active game profile
|
||||
/// @param info Swapchain info
|
||||
///
|
||||
Swapchain(const vk::Vulkan& vk, lsfgvk::Instance& backend,
|
||||
ls::GameConf profile, SwapchainInfo info);
|
||||
|
||||
/// present a frame
|
||||
/// @param vk vulkan instance
|
||||
/// @param queue presentation queue
|
||||
/// @param next_chain next chain pointer for the present info (WARN: shared!)
|
||||
/// @param imageIdx swapchain image index to present to
|
||||
/// @param semaphores semaphores to wait on before presenting
|
||||
/// @throws ls::vulkan_error on vulkan errors
|
||||
///
|
||||
/// Present a frame
|
||||
///
|
||||
/// @param vk Vulkan instance
|
||||
/// @param queue Presentation queue
|
||||
/// @param next_chain next chain pointer for the present info (WARNING: shared!)
|
||||
/// @param imageIdx Swapchain image index to present to
|
||||
/// @param semaphores Semaphores to wait on before presenting
|
||||
/// @throws ls::vulkan_error on vulkan error
|
||||
///
|
||||
VkResult present(const vk::Vulkan& vk,
|
||||
VkQueue queue, VkSwapchainKHR swapchain,
|
||||
void* next_chain, uint32_t imageIdx,
|
||||
const std::vector<VkSemaphore>& semaphores);
|
||||
private:
|
||||
std::vector<vk::Image> sourceImages;
|
||||
std::vector<vk::Image> destinationImages;
|
||||
ls::lazy<vk::Image> sourceImage;
|
||||
ls::lazy<vk::Image> destinationImage;
|
||||
ls::lazy<vk::TimelineSemaphore> syncSemaphore;
|
||||
|
||||
ls::lazy<vk::CommandBuffer> renderCommandBuffer;
|
||||
ls::lazy<vk::Fence> renderFence;
|
||||
ls::lazy<vk::Semaphore> finalSemaphore;
|
||||
struct RenderPass {
|
||||
vk::CommandBuffer commandBuffer;
|
||||
vk::Semaphore acquireSemaphore;
|
||||
vk::Semaphore copySemaphore;
|
||||
};
|
||||
std::vector<RenderPass> passes;
|
||||
std::vector<std::pair<vk::Semaphore, vk::Semaphore>> postCopySemaphores;
|
||||
|
||||
ls::R<backend::Instance> instance;
|
||||
ls::owned_ptr<ls::R<backend::Context>> ctx;
|
||||
size_t idx{1};
|
||||
size_t fidx{0}; // real frame index
|
||||
ls::R<lsfgvk::Instance> instance;
|
||||
std::unique_ptr<lsfgvk::Context> ctx;
|
||||
uint32_t total{};
|
||||
|
||||
size_t iteration{0};
|
||||
size_t syncValue{1};
|
||||
|
||||
ls::GameConf profile;
|
||||
SwapchainInfo info;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue