lsfg-vk/lsfg-vk-layer/src/instance.cpp
PancakeTAS 7e07c4ba3a test(dualgpu): Create separate image for DMA-BUFs
This, again, is a temporary change just for messing around
2026-02-10 20:54:29 +01:00

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);
}