2D scene rendering + image loading #15
@@ -57,6 +57,76 @@ void destroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||
}
|
||||
}
|
||||
|
||||
using DeviceFeatureChain = vk::StructureChain<
|
||||
vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan11Features,
|
||||
vk::PhysicalDeviceVulkan12Features, vk::PhysicalDeviceVulkan13Features>;
|
||||
|
||||
// Single source of truth for the device features Sophia requires. Calls
|
||||
// fn(featureRef, name) for each one, so the same list drives both the
|
||||
// suitability check and device creation.
|
||||
template <typename Fn>
|
||||
static void forEachRequiredFeature(DeviceFeatureChain& chain, Fn&& fn) {
|
||||
auto& f10 = chain.get<vk::PhysicalDeviceFeatures2>().features;
|
||||
auto& f11 = chain.get<vk::PhysicalDeviceVulkan11Features>();
|
||||
auto& f12 = chain.get<vk::PhysicalDeviceVulkan12Features>();
|
||||
auto& f13 = chain.get<vk::PhysicalDeviceVulkan13Features>();
|
||||
|
||||
#define SOPHIA_FEATURE(features, name) fn(features.name, #name)
|
||||
// Indirect drawing
|
||||
SOPHIA_FEATURE(f10, multiDrawIndirect);
|
||||
SOPHIA_FEATURE(f10, drawIndirectFirstInstance);
|
||||
SOPHIA_FEATURE(f11, shaderDrawParameters);
|
||||
SOPHIA_FEATURE(f12, drawIndirectCount);
|
||||
|
||||
// Bindless descriptors
|
||||
SOPHIA_FEATURE(f12, descriptorIndexing);
|
||||
SOPHIA_FEATURE(f12, runtimeDescriptorArray);
|
||||
SOPHIA_FEATURE(f12, descriptorBindingPartiallyBound);
|
||||
SOPHIA_FEATURE(f12, descriptorBindingVariableDescriptorCount);
|
||||
SOPHIA_FEATURE(f12, descriptorBindingUpdateUnusedWhilePending);
|
||||
SOPHIA_FEATURE(f12, descriptorBindingSampledImageUpdateAfterBind);
|
||||
SOPHIA_FEATURE(f12, descriptorBindingStorageImageUpdateAfterBind);
|
||||
SOPHIA_FEATURE(f12, descriptorBindingStorageBufferUpdateAfterBind);
|
||||
SOPHIA_FEATURE(f12, shaderSampledImageArrayNonUniformIndexing);
|
||||
SOPHIA_FEATURE(f12, shaderStorageImageArrayNonUniformIndexing);
|
||||
SOPHIA_FEATURE(f12, shaderStorageBufferArrayNonUniformIndexing);
|
||||
|
||||
// Buffer pointers
|
||||
SOPHIA_FEATURE(f12, bufferDeviceAddress);
|
||||
SOPHIA_FEATURE(f12, scalarBlockLayout);
|
||||
|
||||
// Synchronization
|
||||
SOPHIA_FEATURE(f12, timelineSemaphore);
|
||||
SOPHIA_FEATURE(f13, synchronization2);
|
||||
|
||||
// Rendering
|
||||
SOPHIA_FEATURE(f13, dynamicRendering);
|
||||
#undef SOPHIA_FEATURE
|
||||
}
|
||||
|
||||
static bool checkDeviceFeatureSupport(const vk::PhysicalDevice& device) {
|
||||
vk::PhysicalDeviceProperties properties = device.getProperties();
|
||||
if (properties.apiVersion < SOPHIA_VULKAN_API_VERSION) {
|
||||
log::verbose("Skipping ", properties.deviceName,
|
||||
": Vulkan 1.3 not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto supported = device.getFeatures2<
|
||||
vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan11Features,
|
||||
vk::PhysicalDeviceVulkan12Features, vk::PhysicalDeviceVulkan13Features>();
|
||||
|
||||
bool allSupported = true;
|
||||
forEachRequiredFeature(supported, [&](vk::Bool32 has, const char* name) {
|
||||
if (!has) {
|
||||
log::verbose("Skipping ", properties.deviceName,
|
||||
": missing device feature ", name);
|
||||
allSupported = false;
|
||||
}
|
||||
});
|
||||
return allSupported;
|
||||
}
|
||||
|
||||
Device::Device(Window* window)
|
||||
: headless{window == nullptr},
|
||||
enabledExtensions{headless ? std::vector<const char*>{}
|
||||
@@ -386,6 +456,10 @@ bool Device::isPhysicalDeviceSuitable(const vk::PhysicalDevice& device) {
|
||||
|
||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
||||
|
||||
if (!checkDeviceFeatureSupport(device)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->headless) {
|
||||
return indices.graphicsFamily.has_value() && extensionsSupported;
|
||||
}
|
||||
@@ -443,15 +517,17 @@ void Device::createLogicalDevice() {
|
||||
{vk::DeviceQueueCreateFlags(), queueFamily, 1, &queuePriority});
|
||||
}
|
||||
|
||||
vk::PhysicalDeviceVulkan13Features vulkan13Features{};
|
||||
vulkan13Features.dynamicRendering = vk::True;
|
||||
DeviceFeatureChain enabledFeatures;
|
||||
forEachRequiredFeature(enabledFeatures, [](vk::Bool32& feature, const char*) {
|
||||
feature = vk::True;
|
||||
});
|
||||
|
||||
auto deviceFeatures = vk::PhysicalDeviceFeatures();
|
||||
auto createInfo = vk::DeviceCreateInfo(
|
||||
vk::DeviceCreateFlags(), static_cast<uint32_t>(queueCreateInfos.size()),
|
||||
queueCreateInfos.data());
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
createInfo.pNext = &vulkan13Features;
|
||||
// Core features are passed through PhysicalDeviceFeatures2 in the pNext
|
||||
// chain, so pEnabledFeatures must stay null.
|
||||
createInfo.pNext = &enabledFeatures.get<vk::PhysicalDeviceFeatures2>();
|
||||
|
||||
createInfo.enabledExtensionCount =
|
||||
static_cast<uint32_t>(this->enabledExtensions.size());
|
||||
@@ -473,6 +549,7 @@ void Device::createLogicalDevice() {
|
||||
|
||||
void Device::createAllocator() {
|
||||
VmaAllocatorCreateInfo createInfo = {};
|
||||
createInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
||||
createInfo.vulkanApiVersion = SOPHIA_VULKAN_API_VERSION;
|
||||
createInfo.instance = this->instance.get();
|
||||
createInfo.physicalDevice = this->physicalDevice;
|
||||
|
||||
Reference in New Issue
Block a user