Support the VK_EXT_calibrated_timestamps
extension.
This extension has a direct Metal equivalent in the `-[MTLDevice sampleTimestamps:gpuTimestamp:]` method. However, that method returns CPU timestamps in the Mach absolute time domain, which is *not* that of `CLOCK_MONOTONIC_RAW` but of `CLOCK_UPTIME_RAW`. The function that corresponds to `CLOCK_MONOTONIC_RAW` is `mach_continuous_time()`. Therefore, this implementation uses the `mach_continuous_time()` function for the CPU timestamp. Perhaps we should lobby the WG for `VK_TIME_DOMAIN_CLOCK_UPTIME_RAW_EXT`.
This commit is contained in:
parent
591eb6bdaa
commit
4e3ac69305
@ -84,6 +84,9 @@ double mvkGetTimestampPeriod();
|
||||
*/
|
||||
double mvkGetElapsedMilliseconds(uint64_t startTimestamp = 0, uint64_t endTimestamp = 0);
|
||||
|
||||
/** Returns the current absolute time in nanoseconds. */
|
||||
uint64_t mvkGetAbsoluteTime();
|
||||
|
||||
/** Ensures the block is executed on the main thread. */
|
||||
void mvkDispatchToMainAndWait(dispatch_block_t block);
|
||||
|
||||
|
@ -40,6 +40,7 @@ MVKOSVersion mvkOSVersion() {
|
||||
|
||||
static uint64_t _mvkTimestampBase;
|
||||
static double _mvkTimestampPeriod;
|
||||
static mach_timebase_info_data_t _mvkMachTimebase;
|
||||
|
||||
uint64_t mvkGetTimestamp() { return mach_absolute_time() - _mvkTimestampBase; }
|
||||
|
||||
@ -50,6 +51,8 @@ double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp)
|
||||
return (double)(endTimestamp - startTimestamp) * _mvkTimestampPeriod / 1e6;
|
||||
}
|
||||
|
||||
uint64_t mvkGetAbsoluteTime() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; }
|
||||
|
||||
// Initialize timestamping capabilities on app startup.
|
||||
//Called automatically when the framework is loaded and initialized.
|
||||
static bool _mvkTimestampsInitialized = false;
|
||||
@ -58,9 +61,8 @@ __attribute__((constructor)) static void MVKInitTimestamps() {
|
||||
_mvkTimestampsInitialized = true;
|
||||
|
||||
_mvkTimestampBase = mach_absolute_time();
|
||||
mach_timebase_info_data_t timebase;
|
||||
mach_timebase_info(&timebase);
|
||||
_mvkTimestampPeriod = (double)timebase.numer / (double)timebase.denom;
|
||||
mach_timebase_info(&_mvkMachTimebase);
|
||||
_mvkTimestampPeriod = (double)_mvkMachTimebase.numer / (double)_mvkMachTimebase.denom;
|
||||
}
|
||||
|
||||
void mvkDispatchToMainAndWait(dispatch_block_t block) {
|
||||
|
@ -352,6 +352,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
|
||||
- `VK_KHR_variable_pointers`
|
||||
- `VK_EXT_4444_formats` *(requires 16-bit formats and either native texture swizzling or manual swizzling to be enabled)*
|
||||
- `VK_EXT_buffer_device_address` *(requires GPU Tier 2 argument buffers support)*
|
||||
- `VK_EXT_calibrated_timestamps` *(requires Metal 2.2)*
|
||||
- `VK_EXT_debug_marker`
|
||||
- `VK_EXT_debug_report`
|
||||
- `VK_EXT_debug_utils`
|
||||
|
@ -20,6 +20,7 @@ Released TBD
|
||||
|
||||
- Add support for extensions:
|
||||
- `VK_EXT_4444_formats`
|
||||
- `VK_EXT_calibrated_timestamps`
|
||||
- `VK_EXT_shader_demote_to_helper_invocation`
|
||||
- Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands.
|
||||
- Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero.
|
||||
|
@ -175,6 +175,9 @@ public:
|
||||
void getExternalSemaphoreProperties(const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
|
||||
VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
|
||||
|
||||
/** Returns the supported time domains for calibration on this device. */
|
||||
VkResult getCalibrateableTimeDomains(uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains);
|
||||
|
||||
#pragma mark Surfaces
|
||||
|
||||
/**
|
||||
@ -515,6 +518,11 @@ public:
|
||||
const void* pHostPointer,
|
||||
VkMemoryHostPointerPropertiesEXT* pMemHostPtrProps);
|
||||
|
||||
/** Samples timestamps from the specified domains and returns the sampled values. */
|
||||
void getCalibratedTimestamps(uint32_t timestampCount,
|
||||
const VkCalibratedTimestampInfoEXT* pTimestampInfos,
|
||||
uint64_t* pTimestamps,
|
||||
uint64_t* pMaxDeviation);
|
||||
|
||||
#pragma mark Object lifecycle
|
||||
|
||||
|
@ -78,6 +78,8 @@ static const uint32_t kAMDRadeonRX6700DeviceId = 0x73df;
|
||||
static const VkExtent2D kMetalSamplePositionGridSize = { 1, 1 };
|
||||
static const VkExtent2D kMetalSamplePositionGridSizeNotSupported = { 0, 0 };
|
||||
|
||||
static const uint32_t kMaxTimeDomains = 2;
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
@ -1120,6 +1122,22 @@ void MVKPhysicalDevice::getExternalSemaphoreProperties(const VkPhysicalDeviceExt
|
||||
pExternalSemaphoreProperties->pNext = next;
|
||||
}
|
||||
|
||||
VkResult MVKPhysicalDevice::getCalibrateableTimeDomains(uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains) {
|
||||
if (!pTimeDomains) {
|
||||
*pTimeDomainCount = kMaxTimeDomains;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
// XXX CLOCK_MONOTONIC_RAW is mach_continuous_time(), but
|
||||
// -[MTLDevice sampleTimestamps:gpuTimestamp:] returns the CPU
|
||||
// timestamp in the mach_absolute_time() domain, which is CLOCK_UPTIME_RAW
|
||||
// (cf. Libc/gen/clock_gettime.c).
|
||||
static const VkTimeDomainEXT domains[] = { VK_TIME_DOMAIN_DEVICE_EXT, VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT };
|
||||
std::copy_n(domains, min(*pTimeDomainCount, kMaxTimeDomains), pTimeDomains);
|
||||
if (*pTimeDomainCount < kMaxTimeDomains) { return VK_INCOMPLETE; }
|
||||
*pTimeDomainCount = kMaxTimeDomains;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Surfaces
|
||||
|
||||
@ -3544,6 +3562,36 @@ VkResult MVKDevice::getMemoryHostPointerProperties(VkExternalMemoryHandleTypeFla
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void MVKDevice::getCalibratedTimestamps(uint32_t timestampCount,
|
||||
const VkCalibratedTimestampInfoEXT* pTimestampInfos,
|
||||
uint64_t* pTimestamps,
|
||||
uint64_t* pMaxDeviation) {
|
||||
MTLTimestamp cpuStamp, gpuStamp;
|
||||
uint64_t cpuStart, cpuEnd;
|
||||
|
||||
cpuStart = mvkGetAbsoluteTime();
|
||||
[getMTLDevice() sampleTimestamps: &cpuStamp gpuTimestamp: &gpuStamp];
|
||||
// Sample again to calculate the maximum deviation. Note that the
|
||||
// -[MTLDevice sampleTimestamps:gpuTimestamp:] method guarantees that CPU
|
||||
// timestamps are in nanoseconds. We don't want to call the method again,
|
||||
// because that could result in an expensive syscall to query the GPU time-
|
||||
// stamp.
|
||||
cpuEnd = mvkGetAbsoluteTime();
|
||||
for (uint32_t tsIdx = 0; tsIdx < timestampCount; ++tsIdx) {
|
||||
switch (pTimestampInfos[tsIdx].timeDomain) {
|
||||
case VK_TIME_DOMAIN_DEVICE_EXT:
|
||||
pTimestamps[tsIdx] = gpuStamp;
|
||||
break;
|
||||
// XXX Should be VK_TIME_DOMAIN_CLOCK_UPTIME_RAW_EXT
|
||||
case VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT:
|
||||
pTimestamps[tsIdx] = cpuStart;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*pMaxDeviation = cpuEnd - cpuStart;
|
||||
}
|
||||
|
||||
#pragma mark Object lifecycle
|
||||
|
||||
|
@ -736,6 +736,8 @@ void MVKInstance::initProcAddrs() {
|
||||
ADD_DVC_EXT2_ENTRY_POINT(vkGetDeviceGroupSurfacePresentModesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP);
|
||||
ADD_DVC_EXT2_ENTRY_POINT(vkGetPhysicalDevicePresentRectanglesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP);
|
||||
ADD_DVC_EXT2_ENTRY_POINT(vkAcquireNextImage2KHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP);
|
||||
ADD_DVC_EXT_ENTRY_POINT(vkGetCalibratedTimestampsEXT, EXT_CALIBRATED_TIMESTAMPS);
|
||||
ADD_DVC_EXT_ENTRY_POINT(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, EXT_CALIBRATED_TIMESTAMPS);
|
||||
ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectTagEXT, EXT_DEBUG_MARKER);
|
||||
ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectNameEXT, EXT_DEBUG_MARKER);
|
||||
ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, EXT_DEBUG_MARKER);
|
||||
|
@ -95,6 +95,7 @@ MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS,
|
||||
MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA)
|
||||
MVK_EXTENSION(EXT_4444_formats, EXT_4444_FORMATS, DEVICE, 11.0, 13.0)
|
||||
MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0)
|
||||
MVK_EXTENSION(EXT_calibrated_timestamps, EXT_CALIBRATED_TIMESTAMPS, DEVICE, 10.15, 14.0)
|
||||
MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0)
|
||||
MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0)
|
||||
MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0)
|
||||
|
@ -3116,6 +3116,34 @@ MVK_PUBLIC_VULKAN_CORE_ALIAS(vkWaitSemaphores, KHR);
|
||||
MVK_PUBLIC_VULKAN_CORE_ALIAS(vkGetBufferDeviceAddress, EXT);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark VK_EXT_calibrated_timestamps extension
|
||||
|
||||
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
uint32_t* pTimeDomainCount,
|
||||
VkTimeDomainEXT* pTimeDomains) {
|
||||
MVKTraceVulkanCallStart();
|
||||
MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
|
||||
mvkPD->getCalibrateableTimeDomains(pTimeDomainCount, pTimeDomains);
|
||||
MVKTraceVulkanCallEnd();
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetCalibratedTimestampsEXT(
|
||||
VkDevice device,
|
||||
uint32_t timestampCount,
|
||||
const VkCalibratedTimestampInfoEXT* pTimestampInfos,
|
||||
uint64_t* pTimestamps,
|
||||
uint64_t* pMaxDeviation) {
|
||||
MVKTraceVulkanCallStart();
|
||||
MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
|
||||
mvkDev->getCalibratedTimestamps(timestampCount, pTimestampInfos, pTimestamps, pMaxDeviation);
|
||||
MVKTraceVulkanCallEnd();
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark VK_EXT_debug_report extension
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user