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);
|
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. */
|
/** Ensures the block is executed on the main thread. */
|
||||||
void mvkDispatchToMainAndWait(dispatch_block_t block);
|
void mvkDispatchToMainAndWait(dispatch_block_t block);
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ MVKOSVersion mvkOSVersion() {
|
|||||||
|
|
||||||
static uint64_t _mvkTimestampBase;
|
static uint64_t _mvkTimestampBase;
|
||||||
static double _mvkTimestampPeriod;
|
static double _mvkTimestampPeriod;
|
||||||
|
static mach_timebase_info_data_t _mvkMachTimebase;
|
||||||
|
|
||||||
uint64_t mvkGetTimestamp() { return mach_absolute_time() - _mvkTimestampBase; }
|
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;
|
return (double)(endTimestamp - startTimestamp) * _mvkTimestampPeriod / 1e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t mvkGetAbsoluteTime() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; }
|
||||||
|
|
||||||
// Initialize timestamping capabilities on app startup.
|
// Initialize timestamping capabilities on app startup.
|
||||||
//Called automatically when the framework is loaded and initialized.
|
//Called automatically when the framework is loaded and initialized.
|
||||||
static bool _mvkTimestampsInitialized = false;
|
static bool _mvkTimestampsInitialized = false;
|
||||||
@ -58,9 +61,8 @@ __attribute__((constructor)) static void MVKInitTimestamps() {
|
|||||||
_mvkTimestampsInitialized = true;
|
_mvkTimestampsInitialized = true;
|
||||||
|
|
||||||
_mvkTimestampBase = mach_absolute_time();
|
_mvkTimestampBase = mach_absolute_time();
|
||||||
mach_timebase_info_data_t timebase;
|
mach_timebase_info(&_mvkMachTimebase);
|
||||||
mach_timebase_info(&timebase);
|
_mvkTimestampPeriod = (double)_mvkMachTimebase.numer / (double)_mvkMachTimebase.denom;
|
||||||
_mvkTimestampPeriod = (double)timebase.numer / (double)timebase.denom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mvkDispatchToMainAndWait(dispatch_block_t block) {
|
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_KHR_variable_pointers`
|
||||||
- `VK_EXT_4444_formats` *(requires 16-bit formats and either native texture swizzling or manual swizzling to be enabled)*
|
- `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_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_marker`
|
||||||
- `VK_EXT_debug_report`
|
- `VK_EXT_debug_report`
|
||||||
- `VK_EXT_debug_utils`
|
- `VK_EXT_debug_utils`
|
||||||
|
@ -20,6 +20,7 @@ Released TBD
|
|||||||
|
|
||||||
- Add support for extensions:
|
- Add support for extensions:
|
||||||
- `VK_EXT_4444_formats`
|
- `VK_EXT_4444_formats`
|
||||||
|
- `VK_EXT_calibrated_timestamps`
|
||||||
- `VK_EXT_shader_demote_to_helper_invocation`
|
- `VK_EXT_shader_demote_to_helper_invocation`
|
||||||
- Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands.
|
- 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.
|
- Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero.
|
||||||
|
@ -175,6 +175,9 @@ public:
|
|||||||
void getExternalSemaphoreProperties(const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
|
void getExternalSemaphoreProperties(const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
|
||||||
VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
|
VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
|
||||||
|
|
||||||
|
/** Returns the supported time domains for calibration on this device. */
|
||||||
|
VkResult getCalibrateableTimeDomains(uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains);
|
||||||
|
|
||||||
#pragma mark Surfaces
|
#pragma mark Surfaces
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -515,6 +518,11 @@ public:
|
|||||||
const void* pHostPointer,
|
const void* pHostPointer,
|
||||||
VkMemoryHostPointerPropertiesEXT* pMemHostPtrProps);
|
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
|
#pragma mark Object lifecycle
|
||||||
|
|
||||||
|
@ -78,6 +78,8 @@ static const uint32_t kAMDRadeonRX6700DeviceId = 0x73df;
|
|||||||
static const VkExtent2D kMetalSamplePositionGridSize = { 1, 1 };
|
static const VkExtent2D kMetalSamplePositionGridSize = { 1, 1 };
|
||||||
static const VkExtent2D kMetalSamplePositionGridSizeNotSupported = { 0, 0 };
|
static const VkExtent2D kMetalSamplePositionGridSizeNotSupported = { 0, 0 };
|
||||||
|
|
||||||
|
static const uint32_t kMaxTimeDomains = 2;
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
|
||||||
@ -1120,6 +1122,22 @@ void MVKPhysicalDevice::getExternalSemaphoreProperties(const VkPhysicalDeviceExt
|
|||||||
pExternalSemaphoreProperties->pNext = next;
|
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
|
#pragma mark Surfaces
|
||||||
|
|
||||||
@ -3544,6 +3562,36 @@ VkResult MVKDevice::getMemoryHostPointerProperties(VkExternalMemoryHandleTypeFla
|
|||||||
return VK_SUCCESS;
|
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
|
#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(vkGetDeviceGroupSurfacePresentModesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP);
|
||||||
ADD_DVC_EXT2_ENTRY_POINT(vkGetPhysicalDevicePresentRectanglesKHR, 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_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(vkDebugMarkerSetObjectTagEXT, EXT_DEBUG_MARKER);
|
||||||
ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectNameEXT, EXT_DEBUG_MARKER);
|
ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectNameEXT, EXT_DEBUG_MARKER);
|
||||||
ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, 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(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_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_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_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_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0)
|
||||||
MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, 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);
|
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 -
|
||||||
#pragma mark VK_EXT_debug_report extension
|
#pragma mark VK_EXT_debug_report extension
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user