[vk] SL Sample Count Clamp

This commit is contained in:
CamilleLaVey 2025-12-04 06:40:14 -04:00 committed by lizzie
parent ee0af33a9a
commit 5307008bbf
6 changed files with 124 additions and 17 deletions

View file

@ -116,6 +116,24 @@ constexpr std::array R16G16B16A16_UNORM{
} // namespace Alternatives
constexpr std::array<VkSampleCountFlagBits, Device::sample_location_table_size>
sample_location_query_counts{
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT,
VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT,
VK_SAMPLE_COUNT_64_BIT,
};
static_assert(sample_location_query_counts.size() == Device::sample_location_table_size);
constexpr size_t SampleCountIndex(VkSampleCountFlagBits samples) {
for (size_t index = 0; index < sample_location_query_counts.size(); ++index) {
if (sample_location_query_counts[index] == samples) {
return index;
}
}
return sample_location_query_counts.size();
}
[[maybe_unused]] constexpr VkShaderStageFlags GraphicsStageMask =
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT |
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | VK_SHADER_STAGE_GEOMETRY_BIT |
@ -1273,6 +1291,8 @@ bool Device::GetSuitability(bool requires_swapchain) {
features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable = false;
}
PopulateSampleLocationGrids();
// Return whether we were suitable.
return suitable;
}
@ -1472,6 +1492,66 @@ void Device::RemoveUnsuitableExtensions() {
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance4, features.maintenance4,
VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
VkExtent2D Device::SampleLocationGridSizeFor(VkSampleCountFlagBits samples) const {
const auto sanitize = [](VkExtent2D grid) {
if (grid.width == 0 || grid.height == 0) {
return VkExtent2D{1, 1};
}
return grid;
};
const VkExtent2D fallback = sanitize(properties.sample_locations.maxSampleLocationGridSize);
if (!extensions.sample_locations) {
return fallback;
}
const size_t index = SampleCountIndex(samples);
if (index >= sample_location_grids.size()) {
return fallback;
}
const VkExtent2D grid = sample_location_grids[index];
return grid.width == 0 || grid.height == 0 ? fallback : grid;
}
void Device::PopulateSampleLocationGrids() {
for (auto& grid : sample_location_grids) {
grid = VkExtent2D{1, 1};
}
if (!extensions.sample_locations) {
return;
}
const auto sanitize = [](VkExtent2D grid) {
if (grid.width == 0 || grid.height == 0) {
return VkExtent2D{1, 1};
}
return grid;
};
const VkExtent2D fallback = sanitize(properties.sample_locations.maxSampleLocationGridSize);
const VkSampleCountFlags supported_counts =
properties.sample_locations.sampleLocationSampleCounts;
if (supported_counts == 0) {
return;
}
const bool can_query = dld.vkGetPhysicalDeviceMultisamplePropertiesEXT != nullptr;
for (size_t index = 0; index < sample_location_grids.size(); ++index) {
const VkSampleCountFlagBits bit = sample_location_query_counts[index];
if ((supported_counts & bit) == 0) {
continue;
}
VkExtent2D grid = fallback;
if (can_query) {
VkMultisamplePropertiesEXT props{
.sType = VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT,
.pNext = nullptr,
};
dld.vkGetPhysicalDeviceMultisamplePropertiesEXT(physical, bit, &props);
if (props.maxSampleLocationGridSize.width != 0 &&
props.maxSampleLocationGridSize.height != 0) {
grid = props.maxSampleLocationGridSize;
}
}
sample_location_grids[index] = grid;
}
}
// VK_KHR_maintenance5
extensions.maintenance5 = features.maintenance5.maintenance5;
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance5, features.maintenance5,

View file

@ -7,6 +7,7 @@
#pragma once
#include <algorithm>
#include <array>
#include <optional>
#include <set>
#include <span>
@ -349,6 +350,9 @@ public:
return properties.sample_locations;
}
/// Returns the host-supported sample location grid for the requested sample count.
VkExtent2D SampleLocationGridSizeFor(VkSampleCountFlagBits samples) const;
/// Returns true if ASTC is natively supported.
bool IsOptimalAstcSupported() const {
return features.features.textureCompressionASTC_LDR;
@ -959,6 +963,8 @@ public:
void ShutdownGPULogging();
private:
static constexpr size_t sample_location_table_size = 7;
/// Checks if the physical device is suitable and configures the object state
/// with all necessary info about its properties.
bool GetSuitability(bool requires_swapchain);
@ -966,6 +972,8 @@ private:
// Remove extensions which have incomplete feature support.
void RemoveUnsuitableExtensions();
void PopulateSampleLocationGrids();
void RemoveExtension(bool& extension, const std::string& extension_name);
void RemoveExtensionIfUnsuitable(bool& extension, const std::string& extension_name);
@ -1059,6 +1067,8 @@ private:
VkPhysicalDeviceFeatures2 features2{};
VkPhysicalDeviceProperties2 properties2{};
std::array<VkExtent2D, sample_location_table_size> sample_location_grids{};
// Misc features
bool is_optimal_astc_supported{}; ///< Support for all guest ASTC formats.
bool is_blit_depth24_stencil8_supported{}; ///< Support for blitting from and to D24S8.

View file

@ -292,6 +292,7 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
X(vkDestroySurfaceKHR);
X(vkGetPhysicalDeviceFeatures2);
X(vkGetPhysicalDeviceProperties2);
X(vkGetPhysicalDeviceMultisamplePropertiesEXT);
X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
X(vkGetPhysicalDeviceSurfaceFormatsKHR);
X(vkGetPhysicalDeviceSurfacePresentModesKHR);

View file

@ -172,6 +172,7 @@ struct InstanceDispatch {
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties{};
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2{};
PFN_vkGetPhysicalDeviceToolProperties vkGetPhysicalDeviceToolProperties{};
PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT{};
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties{};
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR{};
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR{};