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)
|
Device::Device(Window* window)
|
||||||
: headless{window == nullptr},
|
: headless{window == nullptr},
|
||||||
enabledExtensions{headless ? std::vector<const char*>{}
|
enabledExtensions{headless ? std::vector<const char*>{}
|
||||||
@@ -386,6 +456,10 @@ bool Device::isPhysicalDeviceSuitable(const vk::PhysicalDevice& device) {
|
|||||||
|
|
||||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
||||||
|
|
||||||
|
if (!checkDeviceFeatureSupport(device)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->headless) {
|
if (this->headless) {
|
||||||
return indices.graphicsFamily.has_value() && extensionsSupported;
|
return indices.graphicsFamily.has_value() && extensionsSupported;
|
||||||
}
|
}
|
||||||
@@ -443,15 +517,17 @@ void Device::createLogicalDevice() {
|
|||||||
{vk::DeviceQueueCreateFlags(), queueFamily, 1, &queuePriority});
|
{vk::DeviceQueueCreateFlags(), queueFamily, 1, &queuePriority});
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::PhysicalDeviceVulkan13Features vulkan13Features{};
|
DeviceFeatureChain enabledFeatures;
|
||||||
vulkan13Features.dynamicRendering = vk::True;
|
forEachRequiredFeature(enabledFeatures, [](vk::Bool32& feature, const char*) {
|
||||||
|
feature = vk::True;
|
||||||
|
});
|
||||||
|
|
||||||
auto deviceFeatures = vk::PhysicalDeviceFeatures();
|
|
||||||
auto createInfo = vk::DeviceCreateInfo(
|
auto createInfo = vk::DeviceCreateInfo(
|
||||||
vk::DeviceCreateFlags(), static_cast<uint32_t>(queueCreateInfos.size()),
|
vk::DeviceCreateFlags(), static_cast<uint32_t>(queueCreateInfos.size()),
|
||||||
queueCreateInfos.data());
|
queueCreateInfos.data());
|
||||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
// Core features are passed through PhysicalDeviceFeatures2 in the pNext
|
||||||
createInfo.pNext = &vulkan13Features;
|
// chain, so pEnabledFeatures must stay null.
|
||||||
|
createInfo.pNext = &enabledFeatures.get<vk::PhysicalDeviceFeatures2>();
|
||||||
|
|
||||||
createInfo.enabledExtensionCount =
|
createInfo.enabledExtensionCount =
|
||||||
static_cast<uint32_t>(this->enabledExtensions.size());
|
static_cast<uint32_t>(this->enabledExtensions.size());
|
||||||
@@ -473,6 +549,7 @@ void Device::createLogicalDevice() {
|
|||||||
|
|
||||||
void Device::createAllocator() {
|
void Device::createAllocator() {
|
||||||
VmaAllocatorCreateInfo createInfo = {};
|
VmaAllocatorCreateInfo createInfo = {};
|
||||||
|
createInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
||||||
createInfo.vulkanApiVersion = SOPHIA_VULKAN_API_VERSION;
|
createInfo.vulkanApiVersion = SOPHIA_VULKAN_API_VERSION;
|
||||||
createInfo.instance = this->instance.get();
|
createInfo.instance = this->instance.get();
|
||||||
createInfo.physicalDevice = this->physicalDevice;
|
createInfo.physicalDevice = this->physicalDevice;
|
||||||
|
|||||||
Reference in New Issue
Block a user