Avoid reading env vars inside library constructor functions.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index fa02809..3db0682 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -29,6 +29,7 @@
- Fix tessellation break when control stage declares but does not use position builtin.
- Fix inconsistency in reporting device local memory between type and heap on macOS.
- Fix bug where dynamic shader buffers are overflowing.
+- Avoid reading env vars inside library constructor functions.
- Update `VK_MVK_MOLTENVK_SPEC_VERSION` to `23`.
- Cube demo use `VK_EXT_metal_surface` extension.
- Support *Xcode 11.3*.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index ab70f77..ca5b289 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -272,7 +272,7 @@
case VK_IMAGE_TYPE_1D:
maxExt.height = 1;
maxExt.depth = 1;
- if (_mvkTexture1DAs2D) {
+ if (mvkTreatTexture1DAs2D()) {
maxExt.width = pLimits->maxImageDimension2D;
maxLevels = mvkMipmapLevels3D(maxExt);
} else {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index f948005..5746f45 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -662,7 +662,7 @@
if (validSamples == VK_SAMPLE_COUNT_1_BIT) { return validSamples; }
// Don't use getImageType() because it hasn't been set yet.
- if ( !((pCreateInfo->imageType == VK_IMAGE_TYPE_2D) || ((pCreateInfo->imageType == VK_IMAGE_TYPE_1D) && _mvkTexture1DAs2D)) ) {
+ if ( !((pCreateInfo->imageType == VK_IMAGE_TYPE_2D) || ((pCreateInfo->imageType == VK_IMAGE_TYPE_1D) && mvkTreatTexture1DAs2D())) ) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, multisampling can only be used with a 2D image type. Setting sample count to 1."));
validSamples = VK_SAMPLE_COUNT_1_BIT;
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 43541a4..6aad20c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -1158,7 +1158,7 @@
_tessCtlPatchOutputBufferIndex = layout->getTessCtlPatchOutputBufferIndex();
_tessCtlLevelBufferIndex = layout->getTessCtlLevelBufferIndex();
- shaderContext.options.mslOptions.texture_1D_as_2D = _mvkTexture1DAs2D;
+ shaderContext.options.mslOptions.texture_1D_as_2D = mvkTreatTexture1DAs2D();
shaderContext.options.mslOptions.enable_point_size_builtin = isRenderingPoints(pCreateInfo, reflectData);
shaderContext.options.shouldFlipVertexY = _device->_pMVKConfig->shaderConversionFlipVertexY;
shaderContext.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle;
@@ -1351,7 +1351,7 @@
shaderContext.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle;
shaderContext.options.mslOptions.texture_buffer_native = _device->_pMetalFeatures->textureBuffers;
shaderContext.options.mslOptions.dispatch_base = _allowsDispatchBase;
- shaderContext.options.mslOptions.texture_1D_as_2D = _mvkTexture1DAs2D;
+ shaderContext.options.mslOptions.texture_1D_as_2D = mvkTreatTexture1DAs2D();
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm
index 2e76c54..8b83b5b 100644
--- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm
+++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm
@@ -36,14 +36,17 @@
#endif
static uint32_t _mvkLogLevel = MVK_CONFIG_LOG_LEVEL;
-
-// Initialize log level from environment
static bool _mvkLoggingInitialized = false;
-__attribute__((constructor)) static void MVKInitLogging() {
- if (_mvkLoggingInitialized ) { return; }
- _mvkLoggingInitialized = true;
- MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkLogLevel, MVK_CONFIG_LOG_LEVEL);
+// Returns log level from environment variable.
+// We do this once lazily instead of in a library constructor function to
+// ensure the NSProcessInfo environment is available when called upon.
+static inline uint32_t getMVKLogLevel() {
+ if ( !_mvkLoggingInitialized ) {
+ _mvkLoggingInitialized = true;
+ MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkLogLevel, MVK_CONFIG_LOG_LEVEL);
+ }
+ return _mvkLogLevel;
}
static const char* getReportingLevelString(int aslLvl) {
@@ -99,7 +102,7 @@
MVKVulkanAPIObject* mvkAPIObj = mvkObj ? mvkObj->getVulkanAPIObject() : nullptr;
MVKInstance* mvkInst = mvkAPIObj ? mvkAPIObj->getInstance() : nullptr;
bool hasDebugCallbacks = mvkInst && mvkInst->hasDebugCallbacks();
- bool shouldLog = (aslLvl < (_mvkLogLevel << 2));
+ bool shouldLog = (aslLvl < (getMVKLogLevel() << 2));
// Fail fast to avoid further unnecessary processing.
if ( !(shouldLog || hasDebugCallbacks) ) { return; }
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
index 66c880d..75681b7 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
@@ -31,10 +31,6 @@
* which is part of the public external MoltenVK C API.
*/
-/** Support the MVK_CONFIG_TEXTURE_1D_AS_2D runtime environment variable. */
-extern bool _mvkTexture1DAs2D;
-
-
#pragma mark -
#pragma mark Support for VK_EXT_debug_report extension
@@ -91,4 +87,7 @@
/** Enumerates all formats that support the given features, calling a specified function for each one. */
void mvkEnumerateSupportedFormats(VkFormatProperties properties, bool any, std::function<bool(VkFormat)> func);
+/** Returns whether 1D textures should be treated as Metal 2D textures with height 1. */
+bool mvkTreatTexture1DAs2D();
+
#endif
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
index 5d4eee4..0ccba28 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
@@ -822,7 +822,7 @@
bool isMultisample) {
switch (vkImageType) {
case VK_IMAGE_TYPE_3D: return MTLTextureType3D;
- case VK_IMAGE_TYPE_1D: return (_mvkTexture1DAs2D
+ case VK_IMAGE_TYPE_1D: return (mvkTreatTexture1DAs2D()
? mvkMTLTextureTypeFromVkImageType(VK_IMAGE_TYPE_2D, arraySize, isMultisample)
: (arraySize > 1 ? MTLTextureType1DArray : MTLTextureType1D));
case VK_IMAGE_TYPE_2D:
@@ -854,8 +854,8 @@
case VK_IMAGE_VIEW_TYPE_3D: return MTLTextureType3D;
case VK_IMAGE_VIEW_TYPE_CUBE: return MTLTextureTypeCube;
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return MTLTextureTypeCubeArray;
- case VK_IMAGE_VIEW_TYPE_1D: return _mvkTexture1DAs2D ? mvkMTLTextureTypeFromVkImageViewType(VK_IMAGE_VIEW_TYPE_2D, isMultisample) : MTLTextureType1D;
- case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return _mvkTexture1DAs2D ? mvkMTLTextureTypeFromVkImageViewType(VK_IMAGE_VIEW_TYPE_2D_ARRAY, isMultisample) : MTLTextureType1DArray;
+ case VK_IMAGE_VIEW_TYPE_1D: return mvkTreatTexture1DAs2D() ? mvkMTLTextureTypeFromVkImageViewType(VK_IMAGE_VIEW_TYPE_2D, isMultisample) : MTLTextureType1D;
+ case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return mvkTreatTexture1DAs2D() ? mvkMTLTextureTypeFromVkImageViewType(VK_IMAGE_VIEW_TYPE_2D_ARRAY, isMultisample) : MTLTextureType1DArray;
case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
#if MVK_MACOS
@@ -1450,12 +1450,24 @@
return (mtlStorageMode << MTLResourceStorageModeShift) | (mtlCPUCacheMode << MTLResourceCPUCacheModeShift);
}
+static bool _mvkTexture1DAs2D = MVK_CONFIG_TEXTURE_1D_AS_2D;
+static bool _mvkTexture1DAs2DInitialized = false;
+
+// Returns environment variable indicating whether to use Metal 2D textures for 1D textures.
+// We do this once lazily instead of in a library constructor function to
+// ensure the NSProcessInfo environment is available when called upon.
+bool mvkTreatTexture1DAs2D() {
+ if ( !_mvkTexture1DAs2DInitialized ) {
+ _mvkTexture1DAs2DInitialized = true;
+ MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkTexture1DAs2D, MVK_CONFIG_TEXTURE_1D_AS_2D);
+ }
+ return _mvkTexture1DAs2D;
+}
+
#pragma mark -
#pragma mark Library initialization
-bool _mvkTexture1DAs2D = MVK_CONFIG_TEXTURE_1D_AS_2D;
-
/**
* Called automatically when the framework is loaded and initialized.
*
@@ -1464,12 +1476,9 @@
static bool _mvkDataTypesInitialized = false;
__attribute__((constructor)) static void MVKInitDataTypes() {
if (_mvkDataTypesInitialized ) { return; }
+ _mvkDataTypesInitialized = true;
MVKInitFormatMaps();
-
- MVK_SET_FROM_ENV_OR_BUILD_BOOL(_mvkTexture1DAs2D, MVK_CONFIG_TEXTURE_1D_AS_2D);
-
- _mvkDataTypesInitialized = true;
}
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index 0170dca..6ebfd3d 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -51,19 +51,24 @@
# define MVK_CONFIG_TRACE_VULKAN_CALLS 0
#endif
-static uint32_t _mvkTraceVulkanCalls = 0;
+static uint32_t _mvkTraceVulkanCalls = MVK_CONFIG_TRACE_VULKAN_CALLS;
static bool _mvkVulkanCallTracingInitialized = false;
-__attribute__((constructor)) static void MVKInitVulkanCallTracing() {
- if (_mvkVulkanCallTracingInitialized ) { return; }
- _mvkVulkanCallTracingInitialized = true;
- MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkTraceVulkanCalls, MVK_CONFIG_TRACE_VULKAN_CALLS);
+// Returns Vulkan call trace level from environment variable.
+// We do this once lazily instead of in a library constructor function to
+// ensure the NSProcessInfo environment is available when called upon.
+static inline uint32_t getCallTraceLevel() {
+ if ( !_mvkVulkanCallTracingInitialized ) {
+ _mvkVulkanCallTracingInitialized = true;
+ MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkTraceVulkanCalls, MVK_CONFIG_TRACE_VULKAN_CALLS);
+ }
+ return _mvkTraceVulkanCalls;
}
// Optionally log start of function calls to stderr
static inline uint64_t MVKTraceVulkanCallStartImpl(const char* funcName) {
uint64_t timestamp = 0;
- switch(_mvkTraceVulkanCalls) {
+ switch(getCallTraceLevel()) {
case 3: // Fall through
timestamp = mvkGetTimestamp();
case 2:
@@ -81,7 +86,7 @@
// Optionally log end of function calls and timings to stderr
static inline void MVKTraceVulkanCallEndImpl(const char* funcName, uint64_t startTime) {
- switch(_mvkTraceVulkanCalls) {
+ switch(getCallTraceLevel()) {
case 3:
fprintf(stderr, "[mvk-trace] } %s() (%.4f ms)\n", funcName, mvkGetElapsedMilliseconds(startTime));
break;