blob: 94092f78a5a318e223e684b342bac51147b1c33a [file] [log] [blame]
/*
* MVKOSExtensions.mm
*
* Copyright (c) 2014-2018 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MVKOSExtensions.h"
#include "MVKFoundation.h"
#include "MVKCommonEnvironment.h"
#include <vector>
#include <mach/mach_host.h>
#include <mach/mach_time.h>
#if MVK_MACOS
# import <CoreFoundation/CFData.h>
# import <IOKit/IOKitLib.h>
# import <IOKit/IOKitKeys.h>
#endif
#if MVK_IOS
# import <UIKit/UIDevice.h>
#endif
using namespace std;
static const MVKOSVersion kMVKOSVersionUnknown = 0.0f;
static MVKOSVersion _mvkOSVersion = kMVKOSVersionUnknown;
MVKOSVersion mvkOSVersion() {
if (_mvkOSVersion == kMVKOSVersionUnknown) {
NSOperatingSystemVersion osVer = [[NSProcessInfo processInfo] operatingSystemVersion];
float maj = osVer.majorVersion;
float min = osVer.minorVersion;
float pat = osVer.patchVersion;
_mvkOSVersion = maj + (min / 100.0f) + + (pat / 10000.0f);
}
return _mvkOSVersion;
}
static uint64_t _mvkTimestampBase;
static double _mvkTimestampPeriod;
uint64_t mvkGetTimestamp() { return mach_absolute_time() - _mvkTimestampBase; }
double mvkGetTimestampPeriod() { return _mvkTimestampPeriod; }
double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp) {
if (endTimestamp == 0) { endTimestamp = mvkGetTimestamp(); }
return (double)(endTimestamp - startTimestamp) * _mvkTimestampPeriod / 1e6;
}
#pragma mark Library initialization
/**
* Initialize timestamping capabilities on app startup.
* Called automatically when the framework is loaded and initialized.
*/
static bool _mvkTimestampsInitialized = false;
__attribute__((constructor)) static void MVKInitTimestamps() {
if (_mvkTimestampsInitialized ) { return; }
_mvkTimestampsInitialized = true;
_mvkTimestampBase = mach_absolute_time();
mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
_mvkTimestampPeriod = (double)timebase.numer / (double)timebase.denom;
MVKLogDebug("Initializing MoltenVK timestamping. Mach time: %llu. Time period: %d / %d = %.6f.", _mvkTimestampBase, timebase.numer, timebase.denom, _mvkTimestampPeriod);
}
#pragma mark -
#pragma mark MTLDevice
uint64_t mvkRecommendedMaxWorkingSetSize(id<MTLDevice> mtlDevice) {
#if MVK_MACOS
if ( [mtlDevice respondsToSelector: @selector(recommendedMaxWorkingSetSize)]) {
return mtlDevice.recommendedMaxWorkingSetSize;
}
#endif
#if MVK_IOS
// GPU and CPU use shared memory. Estimate the current free memory in the system.
mach_port_t host_port;
mach_msg_type_number_t host_size;
vm_size_t pagesize;
host_port = mach_host_self();
host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
host_page_size(host_port, &pagesize);
vm_statistics_data_t vm_stat;
if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) == KERN_SUCCESS ) {
return vm_stat.free_count * pagesize;
}
#endif
return 128 * MEBI; // Conservative minimum for macOS GPU's & iOS shared memory
}
#if MVK_MACOS
static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef propertyName) {
uint32_t value = 0;
CFTypeRef cfProp = IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
propertyName,
kCFAllocatorDefault,
kIORegistryIterateRecursively |
kIORegistryIterateParents);
if (cfProp) {
const uint32_t* pValue = reinterpret_cast<const uint32_t*>(CFDataGetBytePtr((CFDataRef)cfProp));
if (pValue) { value = *pValue; }
CFRelease(cfProp);
}
return value;
}
void mvkPopulateGPUInfo(VkPhysicalDeviceProperties& devProps, id<MTLDevice> mtlDevice) {
static const uint32_t kIntelVendorId = 0x8086;
bool isFound = false;
bool isIntegrated = mtlDevice.isLowPower;
devProps.deviceType = isIntegrated ? VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU : VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
strlcpy(devProps.deviceName, mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE);
// Iterate all GPU's, looking for a match.
// The match dictionary is consumed by IOServiceGetMatchingServices and does not need to be released
io_iterator_t entryIterator;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IOPCIDevice"),
&entryIterator) == kIOReturnSuccess) {
io_registry_entry_t entry;
while ( !isFound && (entry = IOIteratorNext(entryIterator)) ) {
if (mvkGetEntryProperty(entry, CFSTR("class-code")) == 0x30000) { // 0x30000 : DISPLAY_VGA
// The Intel GPU will always be marked as integrated.
// Return on a match of either Intel && low power, or non-Intel and non-low-power.
uint32_t vendorID = mvkGetEntryProperty(entry, CFSTR("vendor-id"));
if ( (vendorID == kIntelVendorId) == isIntegrated) {
isFound = true;
devProps.vendorID = vendorID;
devProps.deviceID = mvkGetEntryProperty(entry, CFSTR("device-id"));
}
}
}
IOObjectRelease(entryIterator);
}
}
#endif //MVK_MACOS
#if MVK_IOS
void mvkPopulateGPUInfo(VkPhysicalDeviceProperties& devProps, id<MTLDevice> mtlDevice) {
// For iOS devices, the Device ID is the SoC model (A8, A10X...), in the hex form 0xaMMX, where
//"a" is the Apple brand, MM is the SoC model number (8, 10...) and X is 1 for X version, 0 for other.
NSUInteger coreCnt = NSProcessInfo.processInfo.processorCount;
uint32_t devID = 0xa070;
if ([mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily4_v1]) {
devID = 0xa110;
} else if ([mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1]) {
devID = coreCnt > 2 ? 0xa101 : 0xa100;
} else if ([mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily2_v1]) {
devID = coreCnt > 2 ? 0xa081 : 0xa080;
}
devProps.vendorID = 0x0000106b; // Apple's PCI ID
devProps.deviceID = devID;
devProps.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
strlcpy(devProps.deviceName, mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE);
}
#endif //MVK_IOS