mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-03-30 07:01:37 +00:00
197 lines
6.3 KiB
C++
197 lines
6.3 KiB
C++
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
|
|
#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 <algorithm>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <exception>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <stdlib.h>
|
|
#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;
|
|
}
|
|
}
|
|
|
|
Root::Root() {
|
|
// 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 << "' ";
|
|
switch (profile->first) {
|
|
case ls::IdentType::OVERRIDE:
|
|
std::cerr << "(identified via override)\n";
|
|
break;
|
|
case ls::IdentType::EXECUTABLE:
|
|
std::cerr << "(identified via executable)\n";
|
|
break;
|
|
case ls::IdentType::WINE_EXECUTABLE:
|
|
std::cerr << "(identified via wine executable)\n";
|
|
break;
|
|
case ls::IdentType::PROCESS_NAME:
|
|
std::cerr << "(identified via process name)\n";
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool Root::update() {
|
|
if (!this->config.update())
|
|
return false;
|
|
|
|
const auto& profile = findProfile(this->config.get(), ls::identify());
|
|
if (profile.has_value())
|
|
this->active_profile = profile->second;
|
|
else
|
|
this->active_profile = std::nullopt;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Root::modifyInstanceCreateInfo(VkInstanceCreateInfo& createInfo,
|
|
const std::function<void(void)>& finish) const {
|
|
if (!this->active_profile.has_value())
|
|
return;
|
|
|
|
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();
|
|
}
|
|
|
|
void Root::modifyDeviceCreateInfo(VkDeviceCreateInfo& createInfo,
|
|
const std::function<void(void)>& finish) const {
|
|
if (!this->active_profile.has_value())
|
|
return;
|
|
|
|
auto extensions = add_extensions(
|
|
createInfo.ppEnabledExtensionNames,
|
|
createInfo.enabledExtensionCount,
|
|
{
|
|
"VK_KHR_external_memory",
|
|
"VK_KHR_external_memory_fd",
|
|
"VK_EXT_external_memory_dma_buf",
|
|
"VK_KHR_image_format_list",
|
|
"VK_KHR_bind_memory2",
|
|
"VK_KHR_maintenance1",
|
|
"VK_KHR_get_memory_requirements2",
|
|
"VK_KHR_sampler_ycbcr_conversion",
|
|
"VK_EXT_image_drm_format_modifier",
|
|
"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();
|
|
|
|
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 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
|
|
const auto& global = this->config.get().global();
|
|
|
|
setenv("DISABLE_LSFGVK", "1", 1);
|
|
|
|
try {
|
|
std::string dll{};
|
|
if (global.dll.has_value())
|
|
dll = *global.dll;
|
|
else
|
|
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);
|
|
},
|
|
dll, global.allow_fp16
|
|
);
|
|
} catch (const std::exception& e) {
|
|
unsetenv("DISABLE_LSFGVK");
|
|
throw ls::error("failed to create backend instance", e);
|
|
}
|
|
|
|
unsetenv("DISABLE_LSFGVK");
|
|
}
|
|
|
|
this->swapchains.emplace(swapchain,
|
|
Swapchain(vk, this->backend.mut(), profile, info));
|
|
}
|
|
|
|
void Root::removeSwapchainContext(VkSwapchainKHR swapchain) {
|
|
this->swapchains.erase(swapchain);
|
|
}
|