2019-04-11 14:26:35 -04:00
|
|
|
/*
|
|
|
|
* MVKOSExtensions.mm
|
|
|
|
*
|
2024-01-04 14:51:53 -05:00
|
|
|
* Copyright (c) 2015-2024 The Brenwill Workshop Ltd. (http://www.brenwill.com)
|
2019-04-11 14:26:35 -04:00
|
|
|
*
|
|
|
|
* 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"
|
2020-04-02 18:54:22 -04:00
|
|
|
#include "MVKCommonEnvironment.h"
|
2019-08-08 14:53:19 -05:00
|
|
|
#include <mach/mach_host.h>
|
2019-04-11 14:26:35 -04:00
|
|
|
#include <mach/mach_time.h>
|
2019-08-08 14:53:19 -05:00
|
|
|
#include <mach/task.h>
|
2020-04-02 18:54:22 -04:00
|
|
|
#include <os/proc.h>
|
2023-12-16 14:33:44 +08:00
|
|
|
#include <sys/sysctl.h>
|
2019-04-11 14:26:35 -04:00
|
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2023-12-02 19:20:31 -05:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark Operating System versions
|
|
|
|
|
2019-04-11 14:26:35 -04:00
|
|
|
MVKOSVersion mvkOSVersion() {
|
2020-06-11 12:43:38 -04:00
|
|
|
static MVKOSVersion _mvkOSVersion = 0;
|
|
|
|
if ( !_mvkOSVersion ) {
|
|
|
|
NSOperatingSystemVersion osVer = [[NSProcessInfo processInfo] operatingSystemVersion];
|
|
|
|
_mvkOSVersion = mvkMakeOSVersion((uint32_t)osVer.majorVersion, (uint32_t)osVer.minorVersion, (uint32_t)osVer.patchVersion);
|
|
|
|
}
|
|
|
|
return _mvkOSVersion;
|
2019-04-11 14:26:35 -04:00
|
|
|
}
|
|
|
|
|
2023-12-02 19:20:31 -05:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark Timestamps
|
|
|
|
|
2023-06-23 01:15:32 -07:00
|
|
|
static mach_timebase_info_data_t _mvkMachTimebase;
|
2019-04-11 14:26:35 -04:00
|
|
|
|
2023-12-02 19:20:31 -05:00
|
|
|
uint64_t mvkGetTimestamp() { return mach_absolute_time(); }
|
|
|
|
|
|
|
|
uint64_t mvkGetRuntimeNanoseconds() { return mach_absolute_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; }
|
2019-04-11 14:26:35 -04:00
|
|
|
|
2023-12-02 19:20:31 -05:00
|
|
|
uint64_t mvkGetContinuousNanoseconds() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; }
|
2019-04-11 14:26:35 -04:00
|
|
|
|
Support the `VK_EXT_pipeline_creation_feedback` extension.
This provides feedback that indicates:
* how long it took to compile each shader stage and the pipeline as a
whole;
* whether or not the pipeline or any shader stage were found in any
supplied pipeline cache; and
* whether or not any supplied base pipeline were used to accelerate
pipeline creation.
This is similar to the performance statistics that MoltenVK already
collects.
Since we don't use any supplied base pipeline at all, this
implementation never sets
`VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT`. However,
I've identified several places where we could probably use the base
pipeline to accelerate pipeline creation. One day, I should probably
implement that.
Likewise, because we don't yet support using `MTLBinaryArchive`s,
`VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT` is
never set on the whole pipeline, though it *is* set for individual
stages, on the assumption that any shader found in a cache is likely to
be found in Metal's own implicit cache.
In this implementation, shader stage compilation time includes any time
needed to build the `MTLComputePipelineState`s needed for vertex and
tessellation control shaders in tessellated pipelines.
This patch also changes compilation of the vertex stage
`MTLComputePipelineState`s in tessellated pipelines to be eager instead
of lazy. We really ought to have been doing this anyway, in order to
report pipeline failures at creation time instead of draw time. I'm not
happy, though, that we now pay the cost of all three pipeline states all
the time, instead of just the ones that are used.
This also gets rid of some fields of `MVKGraphicsPipeline` that were
only used during pipeline construction, which should save some memory,
particularly for apps that create lots of pipelines.
2023-07-07 00:25:37 -07:00
|
|
|
uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp, uint64_t endTimestamp) {
|
2019-04-11 14:26:35 -04:00
|
|
|
if (endTimestamp == 0) { endTimestamp = mvkGetTimestamp(); }
|
2023-12-02 19:20:31 -05:00
|
|
|
return (endTimestamp - startTimestamp) * _mvkMachTimebase.numer / _mvkMachTimebase.denom;
|
Support the `VK_EXT_pipeline_creation_feedback` extension.
This provides feedback that indicates:
* how long it took to compile each shader stage and the pipeline as a
whole;
* whether or not the pipeline or any shader stage were found in any
supplied pipeline cache; and
* whether or not any supplied base pipeline were used to accelerate
pipeline creation.
This is similar to the performance statistics that MoltenVK already
collects.
Since we don't use any supplied base pipeline at all, this
implementation never sets
`VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT`. However,
I've identified several places where we could probably use the base
pipeline to accelerate pipeline creation. One day, I should probably
implement that.
Likewise, because we don't yet support using `MTLBinaryArchive`s,
`VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT` is
never set on the whole pipeline, though it *is* set for individual
stages, on the assumption that any shader found in a cache is likely to
be found in Metal's own implicit cache.
In this implementation, shader stage compilation time includes any time
needed to build the `MTLComputePipelineState`s needed for vertex and
tessellation control shaders in tessellated pipelines.
This patch also changes compilation of the vertex stage
`MTLComputePipelineState`s in tessellated pipelines to be eager instead
of lazy. We really ought to have been doing this anyway, in order to
report pipeline failures at creation time instead of draw time. I'm not
happy, though, that we now pay the cost of all three pipeline states all
the time, instead of just the ones that are used.
This also gets rid of some fields of `MVKGraphicsPipeline` that were
only used during pipeline construction, which should save some memory,
particularly for apps that create lots of pipelines.
2023-07-07 00:25:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp) {
|
|
|
|
return mvkGetElapsedNanoseconds(startTimestamp, endTimestamp) / 1e6;
|
2019-04-11 14:26:35 -04:00
|
|
|
}
|
|
|
|
|
2023-12-02 19:20:31 -05:00
|
|
|
// Initialize timestamp capabilities on app startup.
|
|
|
|
// Called automatically when the framework is loaded and initialized.
|
2019-04-11 14:26:35 -04:00
|
|
|
static bool _mvkTimestampsInitialized = false;
|
|
|
|
__attribute__((constructor)) static void MVKInitTimestamps() {
|
|
|
|
if (_mvkTimestampsInitialized ) { return; }
|
|
|
|
_mvkTimestampsInitialized = true;
|
|
|
|
|
2023-06-23 01:15:32 -07:00
|
|
|
mach_timebase_info(&_mvkMachTimebase);
|
2019-04-11 14:26:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark Process environment
|
|
|
|
|
2023-09-11 20:14:23 -04:00
|
|
|
bool mvkGetEnvVar(const char* varName, string& evStr) {
|
2019-07-15 18:59:52 -04:00
|
|
|
@autoreleasepool {
|
2019-09-25 15:41:40 -05:00
|
|
|
NSDictionary* nsEnv = [[NSProcessInfo processInfo] environment];
|
2023-09-11 20:14:23 -04:00
|
|
|
NSString* nsStr = nsEnv[@(varName)];
|
|
|
|
if (nsStr) { evStr = nsStr.UTF8String; }
|
|
|
|
return nsStr != nil;
|
2019-07-15 18:59:52 -04:00
|
|
|
}
|
2019-04-11 14:26:35 -04:00
|
|
|
}
|
|
|
|
|
2023-09-11 20:14:23 -04:00
|
|
|
const char* mvkGetEnvVarString(const char* varName, string& evStr, const char* defaultValue) {
|
|
|
|
return mvkGetEnvVar(varName, evStr) ? evStr.c_str() : defaultValue;
|
2019-04-11 14:26:35 -04:00
|
|
|
}
|
|
|
|
|
2023-09-11 20:14:23 -04:00
|
|
|
double mvkGetEnvVarNumber(const char* varName, double defaultValue) {
|
|
|
|
string evStr;
|
|
|
|
return mvkGetEnvVar(varName, evStr) ? strtod(evStr.c_str(), nullptr) : defaultValue;
|
2019-04-11 14:26:35 -04:00
|
|
|
}
|
2019-08-08 14:53:19 -05:00
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark System memory
|
|
|
|
|
|
|
|
uint64_t mvkGetSystemMemorySize() {
|
2023-12-16 14:33:44 +08:00
|
|
|
uint64_t host_memsize = 0;
|
|
|
|
size_t size = sizeof(host_memsize);
|
|
|
|
if (sysctlbyname("hw.memsize", &host_memsize, &size, NULL, 0) == KERN_SUCCESS) {
|
|
|
|
return host_memsize;
|
2019-08-08 14:53:19 -05:00
|
|
|
}
|
2020-06-18 16:36:45 -07:00
|
|
|
return 0;
|
2019-08-08 14:53:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t mvkGetAvailableMemorySize() {
|
2020-06-15 16:33:51 -07:00
|
|
|
#if MVK_IOS_OR_TVOS
|
2020-03-28 20:11:21 -04:00
|
|
|
if (mvkOSVersionIsAtLeast(13.0)) { return os_proc_available_memory(); }
|
2019-08-08 14:53:19 -05:00
|
|
|
#endif
|
|
|
|
mach_port_t host_port;
|
|
|
|
mach_msg_type_number_t host_size;
|
|
|
|
vm_size_t pagesize;
|
|
|
|
host_port = mach_host_self();
|
|
|
|
host_size = HOST_VM_INFO_COUNT;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t mvkGetUsedMemorySize() {
|
|
|
|
task_vm_info_data_t task_vm_info;
|
|
|
|
mach_msg_type_number_t task_size = TASK_VM_INFO_COUNT;
|
|
|
|
if (task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&task_vm_info, &task_size) == KERN_SUCCESS) {
|
2023-12-15 18:09:39 -05:00
|
|
|
#ifdef TASK_VM_INFO_REV3_COUNT // check for rev3 version of task_vm_info
|
2023-12-15 22:15:53 -05:00
|
|
|
if (task_size >= TASK_VM_INFO_REV3_COUNT) {
|
|
|
|
return task_vm_info.ledger_tag_graphics_footprint;
|
|
|
|
}
|
|
|
|
else
|
2023-12-15 18:09:39 -05:00
|
|
|
#endif
|
2023-12-15 22:15:53 -05:00
|
|
|
return task_vm_info.phys_footprint;
|
2019-08-08 14:53:19 -05:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-03-19 22:53:36 -04:00
|
|
|
uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); }
|
|
|
|
|
2023-12-02 19:20:31 -05:00
|
|
|
|
2023-06-20 10:19:29 -04:00
|
|
|
#pragma mark -
|
|
|
|
#pragma mark Threading
|
|
|
|
|
|
|
|
/** Returns the amount of avaliable CPU cores. */
|
|
|
|
uint32_t mvkGetAvaliableCPUCores() {
|
|
|
|
return (uint32_t)[[NSProcessInfo processInfo] activeProcessorCount];
|
|
|
|
}
|
2023-12-02 19:20:31 -05:00
|
|
|
|
|
|
|
void mvkDispatchToMainAndWait(dispatch_block_t block) {
|
|
|
|
if (NSThread.isMainThread) {
|
|
|
|
block();
|
|
|
|
} else {
|
|
|
|
dispatch_sync(dispatch_get_main_queue(), block);
|
|
|
|
}
|
|
|
|
}
|