Merge pull request #1905 from billhollings/id-unsupp-dvc-feat-flags
Identify each unsupported device feature flag that the app attempts to enable.
This commit is contained in:
commit
9c55ef3116
@ -21,6 +21,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <streambuf>
|
||||
#include <vector>
|
||||
#include <cxxabi.h>
|
||||
|
||||
namespace mvk {
|
||||
|
||||
@ -59,6 +61,26 @@ namespace mvk {
|
||||
return varName;
|
||||
}
|
||||
|
||||
/** Returns a string containing the ordinal suffix for a numeric value.*/
|
||||
inline const char* getOrdinalSuffix(int64_t val) {
|
||||
static const char* suffixes[] = {"th", "st", "nd", "rd"};
|
||||
auto ord = val % 100;
|
||||
if (ord > 10 && ord < 20) { return suffixes[0]; } // All teens end in th.
|
||||
ord = ord % 10;
|
||||
if (ord > 3) { return suffixes[0]; } // 4-9 end in th.
|
||||
return suffixes[ord];
|
||||
}
|
||||
|
||||
/** Returns the name of a C++ type. */
|
||||
template<typename T>
|
||||
inline std::string getTypeName(const T* pObj) {
|
||||
int status;
|
||||
char* demangledName = abi::__cxa_demangle(typeid(*pObj).name(), 0, 0, &status);
|
||||
std::string tName = demangledName;
|
||||
free(demangledName);
|
||||
return tName;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Streams
|
||||
|
@ -30,6 +30,7 @@ Released TBD
|
||||
- Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively
|
||||
disable recent fixes to handling LOD for arrayed depth images in shaders,
|
||||
on Apple Silicon, when those fixes cause regression in rendering behavior.
|
||||
- Identify each unsupported device feature flag that the app attempts to be enable.
|
||||
- For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`.
|
||||
- Improve GitHub CI production of binary artifacts on submission and release.
|
||||
|
||||
|
@ -886,8 +886,8 @@ protected:
|
||||
void initQueues(const VkDeviceCreateInfo* pCreateInfo);
|
||||
void reservePrivateData(const VkDeviceCreateInfo* pCreateInfo);
|
||||
void enableFeatures(const VkDeviceCreateInfo* pCreateInfo);
|
||||
void enableFeatures(VkBaseInStructure* pEnabled, const VkBaseInStructure* pRequested, const VkBaseInStructure* pAvailable, uint32_t count);
|
||||
void enableFeatures(VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count);
|
||||
template<typename S> void enableFeatures(S* pEnabled, const S* pRequested, const S* pAvailable, uint32_t count);
|
||||
template<typename S> void enableFeatures(S* pRequested, VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count);
|
||||
void enableExtensions(const VkDeviceCreateInfo* pCreateInfo);
|
||||
const char* getActivityPerformanceDescription(MVKPerformanceTracker& activity, MVKPerformanceStatistics& perfStats);
|
||||
void logActivityPerformance(MVKPerformanceTracker& activity, MVKPerformanceStatistics& perfStats, bool isInline = false);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "MVKCommandPool.h"
|
||||
#include "MVKFoundation.h"
|
||||
#include "MVKCodec.h"
|
||||
#include "MVKStrings.h"
|
||||
#include <MoltenVKShaderConverter/SPIRVToMSLConverter.h>
|
||||
|
||||
#import "CAMetalLayer+MoltenVK.h"
|
||||
@ -4590,7 +4591,8 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) {
|
||||
//Enable device features based on requested and available features,
|
||||
// including extended features that are requested in the pNext chain.
|
||||
if (pCreateInfo->pEnabledFeatures) {
|
||||
enableFeatures(&_enabledFeatures.robustBufferAccess,
|
||||
enableFeatures(pCreateInfo->pEnabledFeatures,
|
||||
&_enabledFeatures.robustBufferAccess,
|
||||
&pCreateInfo->pEnabledFeatures->robustBufferAccess,
|
||||
&pdFeats2.features.robustBufferAccess, 55);
|
||||
}
|
||||
@ -4599,29 +4601,36 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) {
|
||||
switch ((uint32_t)next->sType) {
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: {
|
||||
auto* requestedFeatures = (VkPhysicalDeviceFeatures2*)next;
|
||||
enableFeatures(&_enabledFeatures.robustBufferAccess,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledFeatures.robustBufferAccess,
|
||||
&requestedFeatures->features.robustBufferAccess,
|
||||
&pdFeats2.features.robustBufferAccess, 55);
|
||||
break;
|
||||
}
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: {
|
||||
auto* requestedFeatures = (VkPhysicalDeviceVulkan11Features*)next;
|
||||
enableFeatures(&_enabled16BitStorageFeatures.storageBuffer16BitAccess,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabled16BitStorageFeatures.storageBuffer16BitAccess,
|
||||
&requestedFeatures->storageBuffer16BitAccess,
|
||||
&pd16BitStorageFeatures.storageBuffer16BitAccess, 4);
|
||||
enableFeatures(&_enabledMultiviewFeatures.multiview,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledMultiviewFeatures.multiview,
|
||||
&requestedFeatures->multiview,
|
||||
&pdMultiviewFeatures.multiview, 3);
|
||||
enableFeatures(&_enabledVariablePointerFeatures.variablePointersStorageBuffer,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledVariablePointerFeatures.variablePointersStorageBuffer,
|
||||
&requestedFeatures->variablePointersStorageBuffer,
|
||||
&pdVariablePointerFeatures.variablePointersStorageBuffer, 2);
|
||||
enableFeatures(&_enabledProtectedMemoryFeatures.protectedMemory,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledProtectedMemoryFeatures.protectedMemory,
|
||||
&requestedFeatures->protectedMemory,
|
||||
&pdProtectedMemoryFeatures.protectedMemory, 1);
|
||||
enableFeatures(&_enabledSamplerYcbcrConversionFeatures.samplerYcbcrConversion,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledSamplerYcbcrConversionFeatures.samplerYcbcrConversion,
|
||||
&requestedFeatures->samplerYcbcrConversion,
|
||||
&pdSamplerYcbcrConversionFeatures.samplerYcbcrConversion, 1);
|
||||
enableFeatures(&_enabledShaderDrawParametersFeatures.shaderDrawParameters,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledShaderDrawParametersFeatures.shaderDrawParameters,
|
||||
&requestedFeatures->shaderDrawParameters,
|
||||
&pdShaderDrawParametersFeatures.shaderDrawParameters, 1);
|
||||
break;
|
||||
@ -4629,55 +4638,72 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) {
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: {
|
||||
auto& pdvulkan12FeaturesNoExt = _physicalDevice->_vulkan12FeaturesNoExt;
|
||||
auto* requestedFeatures = (VkPhysicalDeviceVulkan12Features*)next;
|
||||
enableFeatures(&_enabledVulkan12FeaturesNoExt.samplerMirrorClampToEdge,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledVulkan12FeaturesNoExt.samplerMirrorClampToEdge,
|
||||
&requestedFeatures->samplerMirrorClampToEdge,
|
||||
&pdvulkan12FeaturesNoExt.samplerMirrorClampToEdge, 2);
|
||||
enableFeatures(&_enabled8BitStorageFeatures.storageBuffer8BitAccess,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabled8BitStorageFeatures.storageBuffer8BitAccess,
|
||||
&requestedFeatures->storageBuffer8BitAccess,
|
||||
&pd8BitStorageFeatures.storageBuffer8BitAccess, 3);
|
||||
enableFeatures(&_enabledShaderAtomicInt64Features.shaderBufferInt64Atomics,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledShaderAtomicInt64Features.shaderBufferInt64Atomics,
|
||||
&requestedFeatures->shaderBufferInt64Atomics,
|
||||
&pdShaderAtomicInt64Features.shaderBufferInt64Atomics, 2);
|
||||
enableFeatures(&_enabledShaderFloat16Int8Features.shaderFloat16,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledShaderFloat16Int8Features.shaderFloat16,
|
||||
&requestedFeatures->shaderFloat16,
|
||||
&pdShaderFloat16Int8Features.shaderFloat16, 2);
|
||||
enableFeatures(&_enabledVulkan12FeaturesNoExt.descriptorIndexing,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledVulkan12FeaturesNoExt.descriptorIndexing,
|
||||
&requestedFeatures->descriptorIndexing,
|
||||
&pdvulkan12FeaturesNoExt.descriptorIndexing, 1);
|
||||
enableFeatures(&_enabledDescriptorIndexingFeatures.shaderInputAttachmentArrayDynamicIndexing,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledDescriptorIndexingFeatures.shaderInputAttachmentArrayDynamicIndexing,
|
||||
&requestedFeatures->shaderInputAttachmentArrayDynamicIndexing,
|
||||
&pdDescriptorIndexingFeatures.shaderInputAttachmentArrayDynamicIndexing, 20);
|
||||
enableFeatures(&_enabledVulkan12FeaturesNoExt.samplerFilterMinmax,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledVulkan12FeaturesNoExt.samplerFilterMinmax,
|
||||
&requestedFeatures->samplerFilterMinmax,
|
||||
&pdvulkan12FeaturesNoExt.samplerFilterMinmax, 1);
|
||||
enableFeatures(&_enabledScalarBlockLayoutFeatures.scalarBlockLayout,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledScalarBlockLayoutFeatures.scalarBlockLayout,
|
||||
&requestedFeatures->scalarBlockLayout,
|
||||
&pdScalarBlockLayoutFeatures.scalarBlockLayout, 1);
|
||||
enableFeatures(&_enabledImagelessFramebufferFeatures.imagelessFramebuffer,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledImagelessFramebufferFeatures.imagelessFramebuffer,
|
||||
&requestedFeatures->imagelessFramebuffer,
|
||||
&pdImagelessFramebufferFeatures.imagelessFramebuffer, 1);
|
||||
enableFeatures(&_enabledUniformBufferStandardLayoutFeatures.uniformBufferStandardLayout,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledUniformBufferStandardLayoutFeatures.uniformBufferStandardLayout,
|
||||
&requestedFeatures->uniformBufferStandardLayout,
|
||||
&pdUniformBufferStandardLayoutFeatures.uniformBufferStandardLayout, 1);
|
||||
enableFeatures(&_enabledShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes,
|
||||
&requestedFeatures->shaderSubgroupExtendedTypes,
|
||||
&pdShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes, 1);
|
||||
enableFeatures(&_enabledSeparateDepthStencilLayoutsFeatures.separateDepthStencilLayouts,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledSeparateDepthStencilLayoutsFeatures.separateDepthStencilLayouts,
|
||||
&requestedFeatures->separateDepthStencilLayouts,
|
||||
&pdSeparateDepthStencilLayoutsFeatures.separateDepthStencilLayouts, 1);
|
||||
enableFeatures(&_enabledHostQueryResetFeatures.hostQueryReset,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledHostQueryResetFeatures.hostQueryReset,
|
||||
&requestedFeatures->hostQueryReset,
|
||||
&pdHostQueryResetFeatures.hostQueryReset, 1);
|
||||
enableFeatures(&_enabledTimelineSemaphoreFeatures.timelineSemaphore,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledTimelineSemaphoreFeatures.timelineSemaphore,
|
||||
&requestedFeatures->timelineSemaphore,
|
||||
&pdTimelineSemaphoreFeatures.timelineSemaphore, 1);
|
||||
enableFeatures(&_enabledBufferDeviceAddressFeatures.bufferDeviceAddress,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledBufferDeviceAddressFeatures.bufferDeviceAddress,
|
||||
&requestedFeatures->bufferDeviceAddress,
|
||||
&pdBufferDeviceAddressFeatures.bufferDeviceAddress, 3);
|
||||
enableFeatures(&_enabledVulkanMemoryModelFeatures.vulkanMemoryModel,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledVulkanMemoryModelFeatures.vulkanMemoryModel,
|
||||
&requestedFeatures->vulkanMemoryModel,
|
||||
&pdVulkanMemoryModelFeatures.vulkanMemoryModel, 3);
|
||||
enableFeatures(&_enabledVulkan12FeaturesNoExt.shaderOutputViewportIndex,
|
||||
enableFeatures(requestedFeatures,
|
||||
&_enabledVulkan12FeaturesNoExt.shaderOutputViewportIndex,
|
||||
&requestedFeatures->shaderOutputViewportIndex,
|
||||
&pdvulkan12FeaturesNoExt.shaderOutputViewportIndex, 3);
|
||||
break;
|
||||
@ -4685,17 +4711,17 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) {
|
||||
|
||||
#define MVK_DEVICE_FEATURE(structName, enumName, flagCount) \
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##enumName##_FEATURES: { \
|
||||
enableFeatures((VkBaseInStructure*)&_enabled##structName##Features, \
|
||||
next, \
|
||||
(VkBaseInStructure*)&pd##structName##Features, \
|
||||
enableFeatures(&_enabled##structName##Features, \
|
||||
(VkPhysicalDevice##structName##Features*)next, \
|
||||
&pd##structName##Features, \
|
||||
flagCount); \
|
||||
break; \
|
||||
}
|
||||
#define MVK_DEVICE_FEATURE_EXTN(structName, enumName, extnSfx, flagCount) \
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##enumName##_FEATURES_##extnSfx: { \
|
||||
enableFeatures((VkBaseInStructure*)&_enabled##structName##Features, \
|
||||
next, \
|
||||
(VkBaseInStructure*)&pd##structName##Features, \
|
||||
enableFeatures(&_enabled##structName##Features, \
|
||||
(VkPhysicalDevice##structName##Features##extnSfx*)next, \
|
||||
&pd##structName##Features, \
|
||||
flagCount); \
|
||||
break; \
|
||||
}
|
||||
@ -4707,18 +4733,23 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
void MVKDevice::enableFeatures(VkBaseInStructure* pEnabled, const VkBaseInStructure* pRequested, const VkBaseInStructure* pAvailable, uint32_t count) {
|
||||
enableFeatures((VkBool32*)(&(pEnabled->pNext) + 1),
|
||||
(VkBool32*)(&(pRequested->pNext) + 1),
|
||||
(VkBool32*)(&(pAvailable->pNext) + 1),
|
||||
template<typename S>
|
||||
void MVKDevice::enableFeatures(S* pEnabled, const S* pRequested, const S* pAvailable, uint32_t count) {
|
||||
enableFeatures(pRequested,
|
||||
(VkBool32*)mvkGetAddressOfFirstMember(pEnabled),
|
||||
(VkBool32*)mvkGetAddressOfFirstMember(pRequested),
|
||||
(VkBool32*)mvkGetAddressOfFirstMember(pAvailable),
|
||||
count);
|
||||
}
|
||||
|
||||
void MVKDevice::enableFeatures(VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count) {
|
||||
template<typename S>
|
||||
void MVKDevice::enableFeatures(S* pRequested, VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
pEnabledBools[i] = pRequestedBools[i] && pAvailableBools[i];
|
||||
if (pRequestedBools[i] && !pAvailableBools[i]) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateDevice(): Requested feature is not available on this device."));
|
||||
uintptr_t mbrOffset = (uintptr_t)&pRequestedBools[i] - (uintptr_t)mvkGetAddressOfFirstMember(pRequested);
|
||||
size_t mbrIdxOrd = (mbrOffset / sizeof(VkBool32)) + 1;
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateDevice(): Requested physical device feature specified by the %zu%s flag in %s is not available on this device.", mbrIdxOrd, mvk::getOrdinalSuffix(mbrIdxOrd), mvk::getTypeName(pRequested).c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "MVKInstance.h"
|
||||
#include "MVKFoundation.h"
|
||||
#include "MVKOSExtensions.h"
|
||||
#include <cxxabi.h>
|
||||
#include "MVKStrings.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -44,13 +44,7 @@ static const char* getReportingLevelString(MVKConfigLogLevel logLevel) {
|
||||
#pragma mark -
|
||||
#pragma mark MVKBaseObject
|
||||
|
||||
string MVKBaseObject::getClassName() {
|
||||
int status;
|
||||
char* demangled = abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status);
|
||||
string clzName = demangled;
|
||||
free(demangled);
|
||||
return clzName;
|
||||
}
|
||||
string MVKBaseObject::getClassName() { return mvk::getTypeName(this); }
|
||||
|
||||
void MVKBaseObject::reportMessage(MVKConfigLogLevel logLevel, const char* format, ...) {
|
||||
va_list args;
|
||||
|
@ -217,6 +217,44 @@ static constexpr uint64_t mvkAlignByteCount(uint64_t byteCount, uint64_t byteAli
|
||||
return mvkAlignByteRef(byteCount, byteAlignment, alignDown);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile time indication if the struct contains a specific member.
|
||||
*
|
||||
* If S::mbr is well-formed because the struct contains that member, the decltype() and
|
||||
* comma operator together trigger a true_type, otherwise it falls back to a false_type.
|
||||
*
|
||||
* Credit to: https://fekir.info/post/detect-member-variables/
|
||||
*/
|
||||
#define mvk_define_has_member(mbr) \
|
||||
template <typename T, typename = void> struct mvk_has_##mbr : std::false_type {}; \
|
||||
template <typename T> struct mvk_has_##mbr<T, decltype((void)T::mbr, void())> : std::true_type {};
|
||||
|
||||
mvk_define_has_member(pNext); // Defines the mvk_has_pNext() function.
|
||||
|
||||
/** Returns the address of the first member of a structure, which is just the address of the structure. */
|
||||
template <typename S>
|
||||
void* mvkGetAddressOfFirstMember(const S* pStruct, std::false_type){
|
||||
return (void*)pStruct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the first member of a Vulkan structure containing a pNext member.
|
||||
* The first member is the one after the pNext member.
|
||||
*/
|
||||
template <class S>
|
||||
void* mvkGetAddressOfFirstMember(const S* pStruct, std::true_type){
|
||||
return (void*)(&(pStruct->pNext) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the first member of a structure. If the structure is a Vulkan
|
||||
* structure containing a pNext member, the first member is the one after the pNext member.
|
||||
*/
|
||||
template <class S>
|
||||
void* mvkGetAddressOfFirstMember(const S* pStruct){
|
||||
return mvkGetAddressOfFirstMember(pStruct, mvk_has_pNext<S>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the order of the rows in the specified data block.
|
||||
* The transformation is performed in-place.
|
||||
|
Loading…
x
Reference in New Issue
Block a user