Merge pull request #2086 from billhollings/VK_EXT_headless_surface
Add support for extension VK_EXT_headless_surface.
This commit is contained in:
commit
e6a3886313
@ -24,6 +24,9 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Operating System versions
|
||||||
|
|
||||||
typedef float MVKOSVersion;
|
typedef float MVKOSVersion;
|
||||||
|
|
||||||
/*** Constant indicating unsupported functionality in an OS. */
|
/*** Constant indicating unsupported functionality in an OS. */
|
||||||
@ -66,20 +69,31 @@ static inline bool mvkOSVersionIsAtLeast(MVKOSVersion macOSMinVer,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Timestamps
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a monotonic timestamp value for use in Vulkan and performance timestamping.
|
* Returns a monotonic tick value for use in Vulkan and performance timestamping.
|
||||||
*
|
*
|
||||||
* The returned value corresponds to the number of CPU "ticks" since the app was initialized.
|
* The returned value corresponds to the number of CPU ticks since an arbitrary
|
||||||
*
|
* point in the past, and does not increment while the system is asleep.
|
||||||
* Calling this value twice, subtracting the first value from the second, and then multiplying
|
|
||||||
* the result by the value returned by mvkGetTimestampPeriod() will provide an indication of the
|
|
||||||
* number of nanoseconds between the two calls. The convenience function mvkGetElapsedMilliseconds()
|
|
||||||
* can be used to perform this calculation.
|
|
||||||
*/
|
*/
|
||||||
uint64_t mvkGetTimestamp();
|
uint64_t mvkGetTimestamp();
|
||||||
|
|
||||||
/** Returns the number of nanoseconds between each increment of the value returned by mvkGetTimestamp(). */
|
/**
|
||||||
double mvkGetTimestampPeriod();
|
* Returns the number of runtime nanoseconds since an arbitrary point in the past,
|
||||||
|
* excluding any time spent while the system is asleep.
|
||||||
|
*
|
||||||
|
* This value corresponds to the timestamps returned by Metal presentation timings.
|
||||||
|
*/
|
||||||
|
uint64_t mvkGetRuntimeNanoseconds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of nanoseconds since an arbitrary point in the past,
|
||||||
|
* including any time spent while the system is asleep.
|
||||||
|
*/
|
||||||
|
uint64_t mvkGetContinuousNanoseconds();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of nanoseconds elapsed between startTimestamp and endTimestamp,
|
* Returns the number of nanoseconds elapsed between startTimestamp and endTimestamp,
|
||||||
@ -97,12 +111,6 @@ uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp = 0, uint64_t endTimes
|
|||||||
*/
|
*/
|
||||||
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. */
|
|
||||||
void mvkDispatchToMainAndWait(dispatch_block_t block);
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Process environment
|
#pragma mark Process environment
|
||||||
@ -141,8 +149,12 @@ uint64_t mvkGetUsedMemorySize();
|
|||||||
/** Returns the size of a page of host memory on this platform. */
|
/** Returns the size of a page of host memory on this platform. */
|
||||||
uint64_t mvkGetHostMemoryPageSize();
|
uint64_t mvkGetHostMemoryPageSize();
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Threading
|
#pragma mark Threading
|
||||||
|
|
||||||
/** Returns the amount of avaliable CPU cores. */
|
/** Returns the amount of avaliable CPU cores. */
|
||||||
uint32_t mvkGetAvaliableCPUCores();
|
uint32_t mvkGetAvaliableCPUCores();
|
||||||
|
|
||||||
|
/** Ensures the block is executed on the main thread. */
|
||||||
|
void mvkDispatchToMainAndWait(dispatch_block_t block);
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Operating System versions
|
||||||
|
|
||||||
MVKOSVersion mvkOSVersion() {
|
MVKOSVersion mvkOSVersion() {
|
||||||
static MVKOSVersion _mvkOSVersion = 0;
|
static MVKOSVersion _mvkOSVersion = 0;
|
||||||
if ( !_mvkOSVersion ) {
|
if ( !_mvkOSVersion ) {
|
||||||
@ -38,43 +42,35 @@ MVKOSVersion mvkOSVersion() {
|
|||||||
return _mvkOSVersion;
|
return _mvkOSVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t _mvkTimestampBase;
|
|
||||||
static double _mvkTimestampPeriod;
|
#pragma mark -
|
||||||
|
#pragma mark Timestamps
|
||||||
|
|
||||||
static mach_timebase_info_data_t _mvkMachTimebase;
|
static mach_timebase_info_data_t _mvkMachTimebase;
|
||||||
|
|
||||||
uint64_t mvkGetTimestamp() { return mach_absolute_time() - _mvkTimestampBase; }
|
uint64_t mvkGetTimestamp() { return mach_absolute_time(); }
|
||||||
|
|
||||||
double mvkGetTimestampPeriod() { return _mvkTimestampPeriod; }
|
uint64_t mvkGetRuntimeNanoseconds() { return mach_absolute_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; }
|
||||||
|
|
||||||
|
uint64_t mvkGetContinuousNanoseconds() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; }
|
||||||
|
|
||||||
uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp, uint64_t endTimestamp) {
|
uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp, uint64_t endTimestamp) {
|
||||||
if (endTimestamp == 0) { endTimestamp = mvkGetTimestamp(); }
|
if (endTimestamp == 0) { endTimestamp = mvkGetTimestamp(); }
|
||||||
return (endTimestamp - startTimestamp) * _mvkTimestampPeriod;
|
return (endTimestamp - startTimestamp) * _mvkMachTimebase.numer / _mvkMachTimebase.denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp) {
|
double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp) {
|
||||||
return mvkGetElapsedNanoseconds(startTimestamp, endTimestamp) / 1e6;
|
return mvkGetElapsedNanoseconds(startTimestamp, endTimestamp) / 1e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t mvkGetAbsoluteTime() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; }
|
// Initialize timestamp capabilities on app startup.
|
||||||
|
// Called automatically when the framework is loaded and initialized.
|
||||||
// Initialize timestamping capabilities on app startup.
|
|
||||||
//Called automatically when the framework is loaded and initialized.
|
|
||||||
static bool _mvkTimestampsInitialized = false;
|
static bool _mvkTimestampsInitialized = false;
|
||||||
__attribute__((constructor)) static void MVKInitTimestamps() {
|
__attribute__((constructor)) static void MVKInitTimestamps() {
|
||||||
if (_mvkTimestampsInitialized ) { return; }
|
if (_mvkTimestampsInitialized ) { return; }
|
||||||
_mvkTimestampsInitialized = true;
|
_mvkTimestampsInitialized = true;
|
||||||
|
|
||||||
_mvkTimestampBase = mach_absolute_time();
|
|
||||||
mach_timebase_info(&_mvkMachTimebase);
|
mach_timebase_info(&_mvkMachTimebase);
|
||||||
_mvkTimestampPeriod = (double)_mvkMachTimebase.numer / (double)_mvkMachTimebase.denom;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mvkDispatchToMainAndWait(dispatch_block_t block) {
|
|
||||||
if (NSThread.isMainThread) {
|
|
||||||
block();
|
|
||||||
} else {
|
|
||||||
dispatch_sync(dispatch_get_main_queue(), block);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -145,6 +141,7 @@ uint64_t mvkGetUsedMemorySize() {
|
|||||||
|
|
||||||
uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); }
|
uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); }
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Threading
|
#pragma mark Threading
|
||||||
|
|
||||||
@ -152,3 +149,11 @@ uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); }
|
|||||||
uint32_t mvkGetAvaliableCPUCores() {
|
uint32_t mvkGetAvaliableCPUCores() {
|
||||||
return (uint32_t)[[NSProcessInfo processInfo] activeProcessorCount];
|
return (uint32_t)[[NSProcessInfo processInfo] activeProcessorCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mvkDispatchToMainAndWait(dispatch_block_t block) {
|
||||||
|
if (NSThread.isMainThread) {
|
||||||
|
block();
|
||||||
|
} else {
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -380,6 +380,9 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
|
|||||||
- `VK_EXT_external_memory_host`
|
- `VK_EXT_external_memory_host`
|
||||||
- `VK_EXT_fragment_shader_interlock`
|
- `VK_EXT_fragment_shader_interlock`
|
||||||
- *Requires Metal 2.0 and Raster Order Groups.*
|
- *Requires Metal 2.0 and Raster Order Groups.*
|
||||||
|
- `VK_EXT_hdr_metadata`
|
||||||
|
- *macOS only.*
|
||||||
|
- `VK_EXT_headless_surface`
|
||||||
- `VK_EXT_host_query_reset`
|
- `VK_EXT_host_query_reset`
|
||||||
- `VK_EXT_image_robustness`
|
- `VK_EXT_image_robustness`
|
||||||
- `VK_EXT_inline_uniform_block`
|
- `VK_EXT_inline_uniform_block`
|
||||||
|
@ -20,11 +20,13 @@ Released TBD
|
|||||||
|
|
||||||
- Add support for extensions:
|
- Add support for extensions:
|
||||||
- `VK_EXT_extended_dynamic_state3` *(Metal does not support `VK_POLYGON_MODE_POINT`)*
|
- `VK_EXT_extended_dynamic_state3` *(Metal does not support `VK_POLYGON_MODE_POINT`)*
|
||||||
|
- `VK_EXT_headless_surface`
|
||||||
- Fix regression that broke `VK_POLYGON_MODE_LINE`.
|
- Fix regression that broke `VK_POLYGON_MODE_LINE`.
|
||||||
- Fix regression in marking rendering state dirty after `vkCmdClearAttachments()`.
|
- Fix regression in marking rendering state dirty after `vkCmdClearAttachments()`.
|
||||||
- Reduce disk space consumed after running `fetchDependencies` script by removing intermediate file caches.
|
- Reduce disk space consumed after running `fetchDependencies` script by removing intermediate file caches.
|
||||||
- Fix rare deadlock during launch via `dlopen()`.
|
- Fix rare deadlock during launch via `dlopen()`.
|
||||||
- Fix initial value of `VkPhysicalDeviceLimits::timestampPeriod` on non-Apple Silicon GPUs.
|
- Fix initial value of `VkPhysicalDeviceLimits::timestampPeriod` on non-Apple Silicon GPUs.
|
||||||
|
- Fix swapchain and surface bugs when windowing system is accessed from off the main thread.
|
||||||
- Update to latest SPIRV-Cross:
|
- Update to latest SPIRV-Cross:
|
||||||
- MSL: Fix regression error in argument buffer runtime arrays.
|
- MSL: Fix regression error in argument buffer runtime arrays.
|
||||||
- MSL: Work around broken cube texture gradients on Apple Silicon.
|
- MSL: Work around broken cube texture gradients on Apple Silicon.
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
2FEA0AAF24902F9F00EEF3AD /* MVKLayers.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A11C7DFB4800632CA3 /* MVKLayers.mm */; };
|
2FEA0AAF24902F9F00EEF3AD /* MVKLayers.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A11C7DFB4800632CA3 /* MVKLayers.mm */; };
|
||||||
2FEA0AB024902F9F00EEF3AD /* MVKFramebuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */; };
|
2FEA0AB024902F9F00EEF3AD /* MVKFramebuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */; };
|
||||||
2FEA0AB124902F9F00EEF3AD /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; };
|
2FEA0AB124902F9F00EEF3AD /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; };
|
||||||
2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; };
|
2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; };
|
||||||
2FEA0AB324902F9F00EEF3AD /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
|
2FEA0AB324902F9F00EEF3AD /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
|
||||||
2FEA0AB424902F9F00EEF3AD /* MVKCmdDebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C90ED229455B300A061DA /* MVKCmdDebug.mm */; };
|
2FEA0AB424902F9F00EEF3AD /* MVKCmdDebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C90ED229455B300A061DA /* MVKCmdDebug.mm */; };
|
||||||
45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
|
45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
|
||||||
@ -360,8 +360,8 @@
|
|||||||
A9E53DE62100B197002781DD /* NSString+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD42100B197002781DD /* NSString+MoltenVK.mm */; };
|
A9E53DE62100B197002781DD /* NSString+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD42100B197002781DD /* NSString+MoltenVK.mm */; };
|
||||||
A9E53DE72100B197002781DD /* MTLTextureDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */; };
|
A9E53DE72100B197002781DD /* MTLTextureDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */; };
|
||||||
A9E53DE82100B197002781DD /* MTLTextureDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */; };
|
A9E53DE82100B197002781DD /* MTLTextureDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */; };
|
||||||
A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; };
|
A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; };
|
||||||
A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; };
|
A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; };
|
||||||
A9E53DF32100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */; };
|
A9E53DF32100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */; };
|
||||||
A9E53DF42100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */; };
|
A9E53DF42100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */; };
|
||||||
A9E53DF52100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */; };
|
A9E53DF52100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */; };
|
||||||
@ -495,7 +495,7 @@
|
|||||||
DCFD7F572A45BC6E007BBBF7 /* MVKFramebuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */; };
|
DCFD7F572A45BC6E007BBBF7 /* MVKFramebuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */; };
|
||||||
DCFD7F582A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 453638302508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m */; };
|
DCFD7F582A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 453638302508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m */; };
|
||||||
DCFD7F592A45BC6E007BBBF7 /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; };
|
DCFD7F592A45BC6E007BBBF7 /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; };
|
||||||
DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; };
|
DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; };
|
||||||
DCFD7F5B2A45BC6E007BBBF7 /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
|
DCFD7F5B2A45BC6E007BBBF7 /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
|
||||||
DCFD7F5C2A45BC6E007BBBF7 /* MVKCmdDebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C90ED229455B300A061DA /* MVKCmdDebug.mm */; };
|
DCFD7F5C2A45BC6E007BBBF7 /* MVKCmdDebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C90ED229455B300A061DA /* MVKCmdDebug.mm */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
@ -691,7 +691,7 @@
|
|||||||
A9E53DD32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLSamplerDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
|
A9E53DD32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLSamplerDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
|
||||||
A9E53DD42100B197002781DD /* NSString+MoltenVK.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSString+MoltenVK.mm"; sourceTree = "<group>"; };
|
A9E53DD42100B197002781DD /* NSString+MoltenVK.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSString+MoltenVK.mm"; sourceTree = "<group>"; };
|
||||||
A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLTextureDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
|
A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLTextureDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
|
||||||
A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CAMetalLayer+MoltenVK.m"; sourceTree = "<group>"; };
|
A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "CAMetalLayer+MoltenVK.mm"; sourceTree = "<group>"; };
|
||||||
A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPassDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
|
A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPassDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
|
||||||
A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPassDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
|
A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPassDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
|
||||||
A9E53DFA21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPipelineDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
|
A9E53DFA21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPipelineDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
|
||||||
@ -889,7 +889,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A9E53DD12100B197002781DD /* CAMetalLayer+MoltenVK.h */,
|
A9E53DD12100B197002781DD /* CAMetalLayer+MoltenVK.h */,
|
||||||
A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */,
|
A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */,
|
||||||
453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */,
|
453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */,
|
||||||
4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */,
|
4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */,
|
||||||
A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */,
|
A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */,
|
||||||
@ -1703,7 +1703,7 @@
|
|||||||
2FEA0AAF24902F9F00EEF3AD /* MVKLayers.mm in Sources */,
|
2FEA0AAF24902F9F00EEF3AD /* MVKLayers.mm in Sources */,
|
||||||
2FEA0AB024902F9F00EEF3AD /* MVKFramebuffer.mm in Sources */,
|
2FEA0AB024902F9F00EEF3AD /* MVKFramebuffer.mm in Sources */,
|
||||||
2FEA0AB124902F9F00EEF3AD /* MVKMTLBufferAllocation.mm in Sources */,
|
2FEA0AB124902F9F00EEF3AD /* MVKMTLBufferAllocation.mm in Sources */,
|
||||||
2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.m in Sources */,
|
2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.mm in Sources */,
|
||||||
2FEA0AB324902F9F00EEF3AD /* MVKCmdDispatch.mm in Sources */,
|
2FEA0AB324902F9F00EEF3AD /* MVKCmdDispatch.mm in Sources */,
|
||||||
2FEA0AB424902F9F00EEF3AD /* MVKCmdDebug.mm in Sources */,
|
2FEA0AB424902F9F00EEF3AD /* MVKCmdDebug.mm in Sources */,
|
||||||
);
|
);
|
||||||
@ -1763,7 +1763,7 @@
|
|||||||
A94FB7EE1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */,
|
A94FB7EE1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */,
|
||||||
453638382508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
|
453638382508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
|
||||||
A9C96DD21DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */,
|
A9C96DD21DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */,
|
||||||
A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */,
|
A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */,
|
||||||
A9096E5E1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */,
|
A9096E5E1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */,
|
||||||
A99C90F0229455B300A061DA /* MVKCmdDebug.mm in Sources */,
|
A99C90F0229455B300A061DA /* MVKCmdDebug.mm in Sources */,
|
||||||
);
|
);
|
||||||
@ -1823,7 +1823,7 @@
|
|||||||
A94FB7EF1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */,
|
A94FB7EF1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */,
|
||||||
4536383A2508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
|
4536383A2508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
|
||||||
A9C96DD31DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */,
|
A9C96DD31DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */,
|
||||||
A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */,
|
A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */,
|
||||||
A9096E5F1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */,
|
A9096E5F1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */,
|
||||||
A99C90F1229455B300A061DA /* MVKCmdDebug.mm in Sources */,
|
A99C90F1229455B300A061DA /* MVKCmdDebug.mm in Sources */,
|
||||||
);
|
);
|
||||||
@ -1883,7 +1883,7 @@
|
|||||||
DCFD7F572A45BC6E007BBBF7 /* MVKFramebuffer.mm in Sources */,
|
DCFD7F572A45BC6E007BBBF7 /* MVKFramebuffer.mm in Sources */,
|
||||||
DCFD7F582A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
|
DCFD7F582A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
|
||||||
DCFD7F592A45BC6E007BBBF7 /* MVKMTLBufferAllocation.mm in Sources */,
|
DCFD7F592A45BC6E007BBBF7 /* MVKMTLBufferAllocation.mm in Sources */,
|
||||||
DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.m in Sources */,
|
DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.mm in Sources */,
|
||||||
DCFD7F5B2A45BC6E007BBBF7 /* MVKCmdDispatch.mm in Sources */,
|
DCFD7F5B2A45BC6E007BBBF7 /* MVKCmdDispatch.mm in Sources */,
|
||||||
DCFD7F5C2A45BC6E007BBBF7 /* MVKCmdDebug.mm in Sources */,
|
DCFD7F5C2A45BC6E007BBBF7 /* MVKCmdDebug.mm in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -1202,8 +1202,8 @@ VkResult MVKPhysicalDevice::getSurfaceSupport(uint32_t queueFamilyIndex,
|
|||||||
isHeadless = getMTLDevice().isHeadless;
|
isHeadless = getMTLDevice().isHeadless;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If this device is headless or the surface does not have a CAMetalLayer, it is not supported.
|
// If this device is headless, the surface must be headless.
|
||||||
*pSupported = !(isHeadless || (surface->getCAMetalLayer() == nil));
|
*pSupported = isHeadless ? surface->isHeadless() : wasConfigurationSuccessful();
|
||||||
return *pSupported ? VK_SUCCESS : surface->getConfigurationResult();
|
return *pSupported ? VK_SUCCESS : surface->getConfigurationResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1262,13 +1262,12 @@ VkResult MVKPhysicalDevice::getSurfaceCapabilities( const VkPhysicalDeviceSurfac
|
|||||||
|
|
||||||
// The CAlayer underlying the surface must be a CAMetalLayer.
|
// The CAlayer underlying the surface must be a CAMetalLayer.
|
||||||
MVKSurface* surface = (MVKSurface*)pSurfaceInfo->surface;
|
MVKSurface* surface = (MVKSurface*)pSurfaceInfo->surface;
|
||||||
CAMetalLayer* mtlLayer = surface->getCAMetalLayer();
|
if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); }
|
||||||
if ( !mtlLayer ) { return surface->getConfigurationResult(); }
|
|
||||||
|
|
||||||
VkSurfaceCapabilitiesKHR& surfCaps = pSurfaceCapabilities->surfaceCapabilities;
|
VkSurfaceCapabilitiesKHR& surfCaps = pSurfaceCapabilities->surfaceCapabilities;
|
||||||
surfCaps.minImageCount = _metalFeatures.minSwapchainImageCount;
|
surfCaps.minImageCount = _metalFeatures.minSwapchainImageCount;
|
||||||
surfCaps.maxImageCount = _metalFeatures.maxSwapchainImageCount;
|
surfCaps.maxImageCount = _metalFeatures.maxSwapchainImageCount;
|
||||||
surfCaps.currentExtent = mvkGetNaturalExtent(mtlLayer);
|
surfCaps.currentExtent = surface->getNaturalExtent();
|
||||||
surfCaps.minImageExtent = { 1, 1 };
|
surfCaps.minImageExtent = { 1, 1 };
|
||||||
surfCaps.maxImageExtent = { _properties.limits.maxImageDimension2D, _properties.limits.maxImageDimension2D };
|
surfCaps.maxImageExtent = { _properties.limits.maxImageDimension2D, _properties.limits.maxImageDimension2D };
|
||||||
surfCaps.maxImageArrayLayers = 1;
|
surfCaps.maxImageArrayLayers = 1;
|
||||||
@ -1347,9 +1346,7 @@ VkResult MVKPhysicalDevice::getSurfaceFormats(MVKSurface* surface,
|
|||||||
uint32_t* pCount,
|
uint32_t* pCount,
|
||||||
VkSurfaceFormatKHR* pSurfaceFormats) {
|
VkSurfaceFormatKHR* pSurfaceFormats) {
|
||||||
|
|
||||||
// The layer underlying the surface view must be a CAMetalLayer.
|
if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); }
|
||||||
CAMetalLayer* mtlLayer = surface->getCAMetalLayer();
|
|
||||||
if ( !mtlLayer ) { return surface->getConfigurationResult(); }
|
|
||||||
|
|
||||||
#define addSurfFmt(MTL_FMT) \
|
#define addSurfFmt(MTL_FMT) \
|
||||||
do { \
|
do { \
|
||||||
@ -1472,9 +1469,7 @@ VkResult MVKPhysicalDevice::getSurfacePresentModes(MVKSurface* surface,
|
|||||||
uint32_t* pCount,
|
uint32_t* pCount,
|
||||||
VkPresentModeKHR* pPresentModes) {
|
VkPresentModeKHR* pPresentModes) {
|
||||||
|
|
||||||
// The layer underlying the surface view must be a CAMetalLayer.
|
if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); }
|
||||||
CAMetalLayer* mtlLayer = surface->getCAMetalLayer();
|
|
||||||
if ( !mtlLayer ) { return surface->getConfigurationResult(); }
|
|
||||||
|
|
||||||
#define ADD_VK_PRESENT_MODE(VK_PM) \
|
#define ADD_VK_PRESENT_MODE(VK_PM) \
|
||||||
do { \
|
do { \
|
||||||
@ -1502,9 +1497,7 @@ VkResult MVKPhysicalDevice::getPresentRectangles(MVKSurface* surface,
|
|||||||
uint32_t* pRectCount,
|
uint32_t* pRectCount,
|
||||||
VkRect2D* pRects) {
|
VkRect2D* pRects) {
|
||||||
|
|
||||||
// The layer underlying the surface view must be a CAMetalLayer.
|
if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); }
|
||||||
CAMetalLayer* mtlLayer = surface->getCAMetalLayer();
|
|
||||||
if ( !mtlLayer ) { return surface->getConfigurationResult(); }
|
|
||||||
|
|
||||||
if ( !pRects ) {
|
if ( !pRects ) {
|
||||||
*pRectCount = 1;
|
*pRectCount = 1;
|
||||||
@ -1516,7 +1509,7 @@ VkResult MVKPhysicalDevice::getPresentRectangles(MVKSurface* surface,
|
|||||||
*pRectCount = 1;
|
*pRectCount = 1;
|
||||||
|
|
||||||
pRects[0].offset = { 0, 0 };
|
pRects[0].offset = { 0, 0 };
|
||||||
pRects[0].extent = mvkGetNaturalExtent(mtlLayer);
|
pRects[0].extent = surface->getNaturalExtent();
|
||||||
|
|
||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -3672,14 +3665,14 @@ void MVKDevice::getCalibratedTimestamps(uint32_t timestampCount,
|
|||||||
MTLTimestamp cpuStamp, gpuStamp;
|
MTLTimestamp cpuStamp, gpuStamp;
|
||||||
uint64_t cpuStart, cpuEnd;
|
uint64_t cpuStart, cpuEnd;
|
||||||
|
|
||||||
cpuStart = mvkGetAbsoluteTime();
|
cpuStart = mvkGetContinuousNanoseconds();
|
||||||
[getMTLDevice() sampleTimestamps: &cpuStamp gpuTimestamp: &gpuStamp];
|
[getMTLDevice() sampleTimestamps: &cpuStamp gpuTimestamp: &gpuStamp];
|
||||||
// Sample again to calculate the maximum deviation. Note that the
|
// Sample again to calculate the maximum deviation. Note that the
|
||||||
// -[MTLDevice sampleTimestamps:gpuTimestamp:] method guarantees that CPU
|
// -[MTLDevice sampleTimestamps:gpuTimestamp:] method guarantees that CPU
|
||||||
// timestamps are in nanoseconds. We don't want to call the method again,
|
// 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-
|
// because that could result in an expensive syscall to query the GPU time-
|
||||||
// stamp.
|
// stamp.
|
||||||
cpuEnd = mvkGetAbsoluteTime();
|
cpuEnd = mvkGetContinuousNanoseconds();
|
||||||
for (uint32_t tsIdx = 0; tsIdx < timestampCount; ++tsIdx) {
|
for (uint32_t tsIdx = 0; tsIdx < timestampCount; ++tsIdx) {
|
||||||
switch (pTimestampInfos[tsIdx].timeDomain) {
|
switch (pTimestampInfos[tsIdx].timeDomain) {
|
||||||
case VK_TIME_DOMAIN_DEVICE_EXT:
|
case VK_TIME_DOMAIN_DEVICE_EXT:
|
||||||
|
@ -378,14 +378,8 @@ class MVKSwapchainImage : public MVKImage {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Binds this resource to the specified offset within the specified memory allocation. */
|
|
||||||
VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) override;
|
VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) override;
|
||||||
|
|
||||||
#pragma mark Metal
|
|
||||||
|
|
||||||
/** Returns the Metal texture used by the CAMetalDrawable underlying this image. */
|
|
||||||
id<MTLTexture> getMTLTexture(uint8_t planeIndex) override;
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Construction
|
#pragma mark Construction
|
||||||
|
|
||||||
@ -399,7 +393,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
friend class MVKPeerSwapchainImage;
|
friend class MVKPeerSwapchainImage;
|
||||||
|
|
||||||
virtual id<CAMetalDrawable> getCAMetalDrawable() = 0;
|
|
||||||
void detachSwapchain();
|
void detachSwapchain();
|
||||||
|
|
||||||
std::mutex _detachmentLock;
|
std::mutex _detachmentLock;
|
||||||
@ -445,6 +438,8 @@ public:
|
|||||||
|
|
||||||
#pragma mark Metal
|
#pragma mark Metal
|
||||||
|
|
||||||
|
id<MTLTexture> getMTLTexture(uint8_t planeIndex) override;
|
||||||
|
|
||||||
/** Presents the contained drawable to the OS. */
|
/** Presents the contained drawable to the OS. */
|
||||||
VkResult presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff, MVKImagePresentInfo presentInfo);
|
VkResult presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff, MVKImagePresentInfo presentInfo);
|
||||||
|
|
||||||
@ -468,16 +463,16 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
friend MVKSwapchain;
|
friend MVKSwapchain;
|
||||||
|
|
||||||
id<CAMetalDrawable> getCAMetalDrawable() override;
|
id<CAMetalDrawable> getCAMetalDrawable();
|
||||||
void addPresentedHandler(id<CAMetalDrawable> mtlDrawable, MVKImagePresentInfo presentInfo, MVKSwapchainSignaler signaler);
|
void addPresentedHandler(id<CAMetalDrawable> mtlDrawable, MVKImagePresentInfo presentInfo, MVKSwapchainSignaler signaler);
|
||||||
void releaseMetalDrawable();
|
void releaseMetalDrawable();
|
||||||
MVKSwapchainImageAvailability getAvailability();
|
MVKSwapchainImageAvailability getAvailability();
|
||||||
void makeAvailable(const MVKSwapchainSignaler& signaler);
|
|
||||||
void makeAvailable();
|
void makeAvailable();
|
||||||
VkResult acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence);
|
VkResult acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence);
|
||||||
MVKSwapchainSignaler getPresentationSignaler();
|
MVKSwapchainSignaler getPresentationSignaler();
|
||||||
|
|
||||||
id<CAMetalDrawable> _mtlDrawable = nil;
|
id<CAMetalDrawable> _mtlDrawable = nil;
|
||||||
|
id<MTLTexture> _mtlTextureHeadless = nil;
|
||||||
MVKSwapchainImageAvailability _availability;
|
MVKSwapchainImageAvailability _availability;
|
||||||
MVKSmallVector<MVKSwapchainSignaler, 1> _availabilitySignalers;
|
MVKSmallVector<MVKSwapchainSignaler, 1> _availabilitySignalers;
|
||||||
MVKSwapchainSignaler _preSignaler = {};
|
MVKSwapchainSignaler _preSignaler = {};
|
||||||
@ -494,7 +489,8 @@ class MVKPeerSwapchainImage : public MVKSwapchainImage {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Binds this resource according to the specified bind information. */
|
id<MTLTexture> getMTLTexture(uint8_t planeIndex) override;
|
||||||
|
|
||||||
VkResult bindDeviceMemory2(const VkBindImageMemoryInfo* pBindInfo) override;
|
VkResult bindDeviceMemory2(const VkBindImageMemoryInfo* pBindInfo) override;
|
||||||
|
|
||||||
|
|
||||||
@ -504,10 +500,6 @@ public:
|
|||||||
const VkImageCreateInfo* pCreateInfo,
|
const VkImageCreateInfo* pCreateInfo,
|
||||||
MVKSwapchain* swapchain,
|
MVKSwapchain* swapchain,
|
||||||
uint32_t swapchainIndex);
|
uint32_t swapchainIndex);
|
||||||
|
|
||||||
protected:
|
|
||||||
id<CAMetalDrawable> getCAMetalDrawable() override;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,8 +25,10 @@
|
|||||||
#include "MVKFoundation.h"
|
#include "MVKFoundation.h"
|
||||||
#include "MVKOSExtensions.h"
|
#include "MVKOSExtensions.h"
|
||||||
#include "MVKCodec.h"
|
#include "MVKCodec.h"
|
||||||
|
|
||||||
#import "MTLTextureDescriptor+MoltenVK.h"
|
#import "MTLTextureDescriptor+MoltenVK.h"
|
||||||
#import "MTLSamplerDescriptor+MoltenVK.h"
|
#import "MTLSamplerDescriptor+MoltenVK.h"
|
||||||
|
#import "CAMetalLayer+MoltenVK.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace SPIRV_CROSS_NAMESPACE;
|
using namespace SPIRV_CROSS_NAMESPACE;
|
||||||
@ -1169,12 +1171,6 @@ VkResult MVKSwapchainImage::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Metal
|
|
||||||
|
|
||||||
// Overridden to always retrieve the MTLTexture directly from the CAMetalDrawable.
|
|
||||||
id<MTLTexture> MVKSwapchainImage::getMTLTexture(uint8_t planeIndex) { return [getCAMetalDrawable() texture]; }
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Construction
|
#pragma mark Construction
|
||||||
|
|
||||||
MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
|
MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
|
||||||
@ -1212,39 +1208,33 @@ MVKSwapchainImageAvailability MVKPresentableSwapchainImage::getAvailability() {
|
|||||||
return _availability;
|
return _availability;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If present, signal the semaphore for the first waiter for the given image.
|
|
||||||
static void signalPresentationSemaphore(const MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff) {
|
|
||||||
if (signaler.semaphore) { signaler.semaphore->encodeDeferredSignal(mtlCmdBuff, signaler.semaphoreSignalToken); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal either or both of the semaphore and fence in the specified tracker pair.
|
|
||||||
static void signal(const MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff) {
|
|
||||||
if (signaler.semaphore) { signaler.semaphore->encodeDeferredSignal(mtlCmdBuff, signaler.semaphoreSignalToken); }
|
|
||||||
if (signaler.fence) { signaler.fence->signal(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the semaphore and fence that they are being tracked for future signaling.
|
// Tell the semaphore and fence that they are being tracked for future signaling.
|
||||||
static void markAsTracked(const MVKSwapchainSignaler& signaler) {
|
static void track(const MVKSwapchainSignaler& signaler) {
|
||||||
if (signaler.semaphore) { signaler.semaphore->retain(); }
|
if (signaler.semaphore) { signaler.semaphore->retain(); }
|
||||||
if (signaler.fence) { signaler.fence->retain(); }
|
if (signaler.fence) { signaler.fence->retain(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the semaphore and fence that they are no longer being tracked for future signaling.
|
static void signal(MVKSemaphore* semaphore, uint64_t semaphoreSignalToken, id<MTLCommandBuffer> mtlCmdBuff) {
|
||||||
static void unmarkAsTracked(const MVKSwapchainSignaler& signaler) {
|
if (semaphore) { semaphore->encodeDeferredSignal(mtlCmdBuff, semaphoreSignalToken); }
|
||||||
if (signaler.semaphore) { signaler.semaphore->release(); }
|
|
||||||
if (signaler.fence) { signaler.fence->release(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) {
|
static void signal(MVKFence* fence) {
|
||||||
signal(signaler, nil);
|
if (fence) { fence->signal(); }
|
||||||
unmarkAsTracked(signaler);
|
}
|
||||||
|
|
||||||
|
// Signal the semaphore and fence and tell them that they are no longer being tracked for future signaling.
|
||||||
|
static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
|
||||||
|
signal(signaler.semaphore, signaler.semaphoreSignalToken, nil);
|
||||||
|
if (signaler.semaphore) { signaler.semaphore->release(); }
|
||||||
|
|
||||||
|
signal(signaler.fence);
|
||||||
|
if (signaler.fence) { signaler.fence->release(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) {
|
VkResult MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) {
|
||||||
|
|
||||||
// Now that this image is being acquired, release the existing drawable and its texture.
|
// Now that this image is being acquired, release the existing drawable and its texture.
|
||||||
// This is not done earlier so the texture is retained for any post-processing such as screen captures, etc.
|
// This is not done earlier so the texture is retained for any post-processing such as screen captures, etc.
|
||||||
// This may trigger a delayed presentation callback, which uses the _availabilityLock, also used below.
|
|
||||||
releaseMetalDrawable();
|
releaseMetalDrawable();
|
||||||
|
|
||||||
lock_guard<mutex> lock(_availabilityLock);
|
lock_guard<mutex> lock(_availabilityLock);
|
||||||
@ -1267,7 +1257,8 @@ VkResult MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphor
|
|||||||
mtlCmdBuff = _device->getAnyQueue()->getMTLCommandBuffer(kMVKCommandUseAcquireNextImage);
|
mtlCmdBuff = _device->getAnyQueue()->getMTLCommandBuffer(kMVKCommandUseAcquireNextImage);
|
||||||
if ( !mtlCmdBuff ) { setConfigurationResult(VK_ERROR_OUT_OF_POOL_MEMORY); }
|
if ( !mtlCmdBuff ) { setConfigurationResult(VK_ERROR_OUT_OF_POOL_MEMORY); }
|
||||||
}
|
}
|
||||||
signal(signaler, mtlCmdBuff);
|
signal(signaler.semaphore, signaler.semaphoreSignalToken, mtlCmdBuff);
|
||||||
|
signal(signaler.fence);
|
||||||
[mtlCmdBuff commit];
|
[mtlCmdBuff commit];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1275,7 +1266,7 @@ VkResult MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphor
|
|||||||
} else {
|
} else {
|
||||||
_availabilitySignalers.push_back(signaler);
|
_availabilitySignalers.push_back(signaler);
|
||||||
}
|
}
|
||||||
markAsTracked(signaler);
|
track(signaler);
|
||||||
|
|
||||||
return getConfigurationResult();
|
return getConfigurationResult();
|
||||||
}
|
}
|
||||||
@ -1284,6 +1275,9 @@ VkResult MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphor
|
|||||||
// Attempt several times to retrieve a good drawable, and set an error to trigger the
|
// Attempt several times to retrieve a good drawable, and set an error to trigger the
|
||||||
// swapchain to be re-established if one cannot be retrieved.
|
// swapchain to be re-established if one cannot be retrieved.
|
||||||
id<CAMetalDrawable> MVKPresentableSwapchainImage::getCAMetalDrawable() {
|
id<CAMetalDrawable> MVKPresentableSwapchainImage::getCAMetalDrawable() {
|
||||||
|
|
||||||
|
if (_mtlTextureHeadless) { return nil; } // If headless, there is no drawable.
|
||||||
|
|
||||||
if ( !_mtlDrawable ) {
|
if ( !_mtlDrawable ) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
bool hasInvalidFormat = false;
|
bool hasInvalidFormat = false;
|
||||||
@ -1305,6 +1299,11 @@ id<CAMetalDrawable> MVKPresentableSwapchainImage::getCAMetalDrawable() {
|
|||||||
return _mtlDrawable;
|
return _mtlDrawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not headless, retrieve the MTLTexture directly from the CAMetalDrawable.
|
||||||
|
id<MTLTexture> MVKPresentableSwapchainImage::getMTLTexture(uint8_t planeIndex) {
|
||||||
|
return _mtlTextureHeadless ? _mtlTextureHeadless : getCAMetalDrawable().texture;
|
||||||
|
}
|
||||||
|
|
||||||
// Present the drawable and make myself available only once the command buffer has completed.
|
// Present the drawable and make myself available only once the command buffer has completed.
|
||||||
// Pass MVKImagePresentInfo by value because it may not exist when the callback runs.
|
// Pass MVKImagePresentInfo by value because it may not exist when the callback runs.
|
||||||
VkResult MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff,
|
VkResult MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff,
|
||||||
@ -1343,15 +1342,13 @@ VkResult MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffe
|
|||||||
auto* fence = presentInfo.fence;
|
auto* fence = presentInfo.fence;
|
||||||
if (fence) { fence->retain(); }
|
if (fence) { fence->retain(); }
|
||||||
[mtlCmdBuff addCompletedHandler: ^(id<MTLCommandBuffer> mcb) {
|
[mtlCmdBuff addCompletedHandler: ^(id<MTLCommandBuffer> mcb) {
|
||||||
if (fence) {
|
signal(fence);
|
||||||
fence->signal();
|
if (fence) { fence->release(); }
|
||||||
fence->release();
|
|
||||||
}
|
|
||||||
[mtlDrwbl release];
|
[mtlDrwbl release];
|
||||||
release();
|
release();
|
||||||
}];
|
}];
|
||||||
|
|
||||||
signalPresentationSemaphore(signaler, mtlCmdBuff);
|
signal(signaler.semaphore, signaler.semaphoreSignalToken, mtlCmdBuff);
|
||||||
|
|
||||||
return getConfigurationResult();
|
return getConfigurationResult();
|
||||||
}
|
}
|
||||||
@ -1408,6 +1405,13 @@ void MVKPresentableSwapchainImage::beginPresentation(const MVKImagePresentInfo&
|
|||||||
void MVKPresentableSwapchainImage::endPresentation(const MVKImagePresentInfo& presentInfo,
|
void MVKPresentableSwapchainImage::endPresentation(const MVKImagePresentInfo& presentInfo,
|
||||||
const MVKSwapchainSignaler& signaler,
|
const MVKSwapchainSignaler& signaler,
|
||||||
uint64_t actualPresentTime) {
|
uint64_t actualPresentTime) {
|
||||||
|
|
||||||
|
// If the presentation time is not available, use the current nanosecond runtime clock,
|
||||||
|
// which should be reasonably accurate (sub-ms) to the presentation time. The presentation
|
||||||
|
// time will not be available if the presentation did not actually happen, such as when
|
||||||
|
// running headless, or on a test harness that is not attached to the windowing system.
|
||||||
|
if (actualPresentTime == 0) { actualPresentTime = mvkGetRuntimeNanoseconds(); }
|
||||||
|
|
||||||
{ // Scope to avoid deadlock if release() is run within detachment lock
|
{ // Scope to avoid deadlock if release() is run within detachment lock
|
||||||
// If I have become detached from the swapchain, it means the swapchain, and possibly the
|
// If I have become detached from the swapchain, it means the swapchain, and possibly the
|
||||||
// VkDevice, have been destroyed by the time of this callback, so do not reference them.
|
// VkDevice, have been destroyed by the time of this callback, so do not reference them.
|
||||||
@ -1415,7 +1419,11 @@ void MVKPresentableSwapchainImage::endPresentation(const MVKImagePresentInfo& pr
|
|||||||
if (_device) { _device->addPerformanceInterval(_device->_performanceStatistics.queue.presentSwapchains, _presentationStartTime); }
|
if (_device) { _device->addPerformanceInterval(_device->_performanceStatistics.queue.presentSwapchains, _presentationStartTime); }
|
||||||
if (_swapchain) { _swapchain->endPresentation(presentInfo, actualPresentTime); }
|
if (_swapchain) { _swapchain->endPresentation(presentInfo, actualPresentTime); }
|
||||||
}
|
}
|
||||||
makeAvailable(signaler);
|
|
||||||
|
// Makes an image available for acquisition by the app.
|
||||||
|
// If any semaphores are waiting to be signaled when this image becomes available, the
|
||||||
|
// earliest semaphore is signaled, and this image remains unavailable for other uses.
|
||||||
|
signalAndUntrack(signaler);
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1425,15 +1433,6 @@ void MVKPresentableSwapchainImage::releaseMetalDrawable() {
|
|||||||
_mtlDrawable = nil;
|
_mtlDrawable = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Makes an image available for acquisition by the app.
|
|
||||||
// If any semaphores are waiting to be signaled when this image becomes available, the
|
|
||||||
// earliest semaphore is signaled, and this image remains unavailable for other uses.
|
|
||||||
void MVKPresentableSwapchainImage::makeAvailable(const MVKSwapchainSignaler& signaler) {
|
|
||||||
lock_guard<mutex> lock(_availabilityLock);
|
|
||||||
|
|
||||||
signalAndUnmarkAsTracked(signaler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal, untrack, and release any signalers that are tracking.
|
// Signal, untrack, and release any signalers that are tracking.
|
||||||
// Release the drawable before the lock, as it may trigger completion callback.
|
// Release the drawable before the lock, as it may trigger completion callback.
|
||||||
void MVKPresentableSwapchainImage::makeAvailable() {
|
void MVKPresentableSwapchainImage::makeAvailable() {
|
||||||
@ -1441,9 +1440,9 @@ void MVKPresentableSwapchainImage::makeAvailable() {
|
|||||||
lock_guard<mutex> lock(_availabilityLock);
|
lock_guard<mutex> lock(_availabilityLock);
|
||||||
|
|
||||||
if ( !_availability.isAvailable ) {
|
if ( !_availability.isAvailable ) {
|
||||||
signalAndUnmarkAsTracked(_preSignaler);
|
signalAndUntrack(_preSignaler);
|
||||||
for (auto& sig : _availabilitySignalers) {
|
for (auto& sig : _availabilitySignalers) {
|
||||||
signalAndUnmarkAsTracked(sig);
|
signalAndUntrack(sig);
|
||||||
}
|
}
|
||||||
_availabilitySignalers.clear();
|
_availabilitySignalers.clear();
|
||||||
_availability.isAvailable = true;
|
_availability.isAvailable = true;
|
||||||
@ -1460,11 +1459,26 @@ MVKPresentableSwapchainImage::MVKPresentableSwapchainImage(MVKDevice* device,
|
|||||||
|
|
||||||
_availability.acquisitionID = _swapchain->getNextAcquisitionID();
|
_availability.acquisitionID = _swapchain->getNextAcquisitionID();
|
||||||
_availability.isAvailable = true;
|
_availability.isAvailable = true;
|
||||||
|
|
||||||
|
if (swapchain->isHeadless()) {
|
||||||
|
@autoreleasepool {
|
||||||
|
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: getMTLPixelFormat()
|
||||||
|
width: pCreateInfo->extent.width
|
||||||
|
height: pCreateInfo->extent.height
|
||||||
|
mipmapped: NO];
|
||||||
|
mtlTexDesc.usageMVK = MTLTextureUsageRenderTarget;
|
||||||
|
mtlTexDesc.storageModeMVK = MTLStorageModePrivate;
|
||||||
|
|
||||||
|
_mtlTextureHeadless = [[getMTLDevice() newTextureWithDescriptor: mtlTexDesc] retain]; // retained
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MVKPresentableSwapchainImage::destroy() {
|
void MVKPresentableSwapchainImage::destroy() {
|
||||||
releaseMetalDrawable();
|
releaseMetalDrawable();
|
||||||
|
[_mtlTextureHeadless release];
|
||||||
|
_mtlTextureHeadless = nil;
|
||||||
MVKSwapchainImage::destroy();
|
MVKSwapchainImage::destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1498,8 +1512,8 @@ VkResult MVKPeerSwapchainImage::bindDeviceMemory2(const VkBindImageMemoryInfo* p
|
|||||||
|
|
||||||
#pragma mark Metal
|
#pragma mark Metal
|
||||||
|
|
||||||
id<CAMetalDrawable> MVKPeerSwapchainImage::getCAMetalDrawable() {
|
id<MTLTexture> MVKPeerSwapchainImage::getMTLTexture(uint8_t planeIndex) {
|
||||||
return ((MVKSwapchainImage*)_swapchain->getPresentableImage(_swapchainIndex))->getCAMetalDrawable();
|
return ((MVKSwapchainImage*)_swapchain->getPresentableImage(_swapchainIndex))->getMTLTexture(planeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,6 +117,9 @@ public:
|
|||||||
MVKSurface* createSurface(const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
|
MVKSurface* createSurface(const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
|
MVKSurface* createSurface(const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
MVKSurface* createSurface(const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
MVKSurface* createSurface(const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
|
@ -102,6 +102,11 @@ MVKSurface* MVKInstance::createSurface(const VkMetalSurfaceCreateInfoEXT* pCreat
|
|||||||
return new MVKSurface(this, pCreateInfo, pAllocator);
|
return new MVKSurface(this, pCreateInfo, pAllocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MVKSurface* MVKInstance::createSurface(const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator) {
|
||||||
|
return new MVKSurface(this, pCreateInfo, pAllocator);
|
||||||
|
}
|
||||||
|
|
||||||
MVKSurface* MVKInstance::createSurface(const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
MVKSurface* MVKInstance::createSurface(const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator) {
|
const VkAllocationCallbacks* pAllocator) {
|
||||||
return new MVKSurface(this, pCreateInfo, pAllocator);
|
return new MVKSurface(this, pCreateInfo, pAllocator);
|
||||||
@ -426,6 +431,8 @@ void MVKInstance::initProcAddrs() {
|
|||||||
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfacePresentModesKHR, KHR_SURFACE);
|
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfacePresentModesKHR, KHR_SURFACE);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilities2KHR, KHR_GET_SURFACE_CAPABILITIES_2);
|
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilities2KHR, KHR_GET_SURFACE_CAPABILITIES_2);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormats2KHR, KHR_GET_SURFACE_CAPABILITIES_2);
|
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormats2KHR, KHR_GET_SURFACE_CAPABILITIES_2);
|
||||||
|
ADD_INST_EXT_ENTRY_POINT(vkCreateHeadlessSurfaceEXT, EXT_HEADLESS_SURFACE);
|
||||||
|
ADD_INST_EXT_ENTRY_POINT(vkCreateMetalSurfaceEXT, EXT_METAL_SURFACE);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkCreateDebugReportCallbackEXT, EXT_DEBUG_REPORT);
|
ADD_INST_EXT_ENTRY_POINT(vkCreateDebugReportCallbackEXT, EXT_DEBUG_REPORT);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugReportCallbackEXT, EXT_DEBUG_REPORT);
|
ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugReportCallbackEXT, EXT_DEBUG_REPORT);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkDebugReportMessageEXT, EXT_DEBUG_REPORT);
|
ADD_INST_EXT_ENTRY_POINT(vkDebugReportMessageEXT, EXT_DEBUG_REPORT);
|
||||||
@ -441,7 +448,6 @@ void MVKInstance::initProcAddrs() {
|
|||||||
ADD_INST_EXT_ENTRY_POINT(vkCreateDebugUtilsMessengerEXT, EXT_DEBUG_UTILS);
|
ADD_INST_EXT_ENTRY_POINT(vkCreateDebugUtilsMessengerEXT, EXT_DEBUG_UTILS);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugUtilsMessengerEXT, EXT_DEBUG_UTILS);
|
ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugUtilsMessengerEXT, EXT_DEBUG_UTILS);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkSubmitDebugUtilsMessageEXT, EXT_DEBUG_UTILS);
|
ADD_INST_EXT_ENTRY_POINT(vkSubmitDebugUtilsMessageEXT, EXT_DEBUG_UTILS);
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkCreateMetalSurfaceEXT, EXT_METAL_SURFACE);
|
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_IOS_MVK
|
#ifdef VK_USE_PLATFORM_IOS_MVK
|
||||||
ADD_INST_EXT_ENTRY_POINT(vkCreateIOSSurfaceMVK, MVK_IOS_SURFACE);
|
ADD_INST_EXT_ENTRY_POINT(vkCreateIOSSurfaceMVK, MVK_IOS_SURFACE);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include "MVKBaseObject.h"
|
#include "MVKBaseObject.h"
|
||||||
#include "MVKOSExtensions.h"
|
#include "MVKOSExtensions.h"
|
||||||
#include "mvk_datatypes.h"
|
#include "mvk_datatypes.hpp"
|
||||||
#include <spirv_msl.hpp>
|
#include <spirv_msl.hpp>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
@ -24,16 +24,6 @@
|
|||||||
#import <Metal/Metal.h>
|
#import <Metal/Metal.h>
|
||||||
#import <QuartzCore/CAMetalLayer.h>
|
#import <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_IOS_MVK
|
|
||||||
# define PLATFORM_VIEW_CLASS UIView
|
|
||||||
# import <UIKit/UIView.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_MACOS_MVK
|
|
||||||
# define PLATFORM_VIEW_CLASS NSView
|
|
||||||
# import <AppKit/NSView.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class MVKInstance;
|
class MVKInstance;
|
||||||
class MVKSwapchain;
|
class MVKSwapchain;
|
||||||
|
|
||||||
@ -59,6 +49,14 @@ public:
|
|||||||
/** Returns the CAMetalLayer underlying this surface. */
|
/** Returns the CAMetalLayer underlying this surface. */
|
||||||
CAMetalLayer* getCAMetalLayer();
|
CAMetalLayer* getCAMetalLayer();
|
||||||
|
|
||||||
|
/** Returns the extent of this surface. */
|
||||||
|
VkExtent2D getExtent();
|
||||||
|
|
||||||
|
/** Returns the extent for which the underlying CAMetalLayer will not need to be scaled when composited. */
|
||||||
|
VkExtent2D getNaturalExtent();
|
||||||
|
|
||||||
|
/** Returns whether this surface is headless. */
|
||||||
|
bool isHeadless() { return !_mtlCAMetalLayer && wasConfigurationSuccessful(); }
|
||||||
|
|
||||||
#pragma mark Construction
|
#pragma mark Construction
|
||||||
|
|
||||||
@ -66,6 +64,10 @@ public:
|
|||||||
const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
|
const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
|
MVKSurface(MVKInstance* mvkInstance,
|
||||||
|
const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
MVKSurface(MVKInstance* mvkInstance,
|
MVKSurface(MVKInstance* mvkInstance,
|
||||||
const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
@ -76,7 +78,8 @@ protected:
|
|||||||
friend class MVKSwapchain;
|
friend class MVKSwapchain;
|
||||||
|
|
||||||
void propagateDebugName() override {}
|
void propagateDebugName() override {}
|
||||||
void initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName);
|
void setActiveSwapchain(MVKSwapchain* swapchain);
|
||||||
|
void initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName, bool isHeadless);
|
||||||
void releaseLayer();
|
void releaseLayer();
|
||||||
|
|
||||||
std::mutex _layerLock;
|
std::mutex _layerLock;
|
||||||
@ -84,5 +87,6 @@ protected:
|
|||||||
CAMetalLayer* _mtlCAMetalLayer = nil;
|
CAMetalLayer* _mtlCAMetalLayer = nil;
|
||||||
MVKBlockObserver* _layerObserver = nil;
|
MVKBlockObserver* _layerObserver = nil;
|
||||||
MVKSwapchain* _activeSwapchain = nullptr;
|
MVKSwapchain* _activeSwapchain = nullptr;
|
||||||
|
VkExtent2D _headlessExtent = {0xFFFFFFFF, 0xFFFFFFFF};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,11 +17,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MVKSurface.h"
|
#include "MVKSurface.h"
|
||||||
|
#include "MVKSwapchain.h"
|
||||||
#include "MVKInstance.h"
|
#include "MVKInstance.h"
|
||||||
#include "MVKFoundation.h"
|
#include "MVKFoundation.h"
|
||||||
#include "MVKOSExtensions.h"
|
#include "MVKOSExtensions.h"
|
||||||
|
#include "mvk_datatypes.hpp"
|
||||||
|
|
||||||
|
#import "CAMetalLayer+MoltenVK.h"
|
||||||
#import "MVKBlockObserver.h"
|
#import "MVKBlockObserver.h"
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_IOS_MVK
|
||||||
|
# define PLATFORM_VIEW_CLASS UIView
|
||||||
|
# import <UIKit/UIView.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_MACOS_MVK
|
||||||
|
# define PLATFORM_VIEW_CLASS NSView
|
||||||
|
# import <AppKit/NSView.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// We need to double-dereference the name to first convert to the platform symbol, then to a string.
|
// We need to double-dereference the name to first convert to the platform symbol, then to a string.
|
||||||
#define STR_PLATFORM(NAME) #NAME
|
#define STR_PLATFORM(NAME) #NAME
|
||||||
#define STR(NAME) STR_PLATFORM(NAME)
|
#define STR(NAME) STR_PLATFORM(NAME)
|
||||||
@ -34,38 +49,55 @@ CAMetalLayer* MVKSurface::getCAMetalLayer() {
|
|||||||
return _mtlCAMetalLayer;
|
return _mtlCAMetalLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkExtent2D MVKSurface::getExtent() {
|
||||||
|
return _mtlCAMetalLayer ? mvkVkExtent2DFromCGSize(_mtlCAMetalLayer.drawableSize) : _headlessExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D MVKSurface::getNaturalExtent() {
|
||||||
|
return _mtlCAMetalLayer ? mvkVkExtent2DFromCGSize(_mtlCAMetalLayer.naturalDrawableSizeMVK) : _headlessExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per spec, headless surface extent is set from the swapchain.
|
||||||
|
void MVKSurface::setActiveSwapchain(MVKSwapchain* swapchain) {
|
||||||
|
_activeSwapchain = swapchain;
|
||||||
|
_headlessExtent = swapchain->getImageExtent();
|
||||||
|
}
|
||||||
|
|
||||||
MVKSurface::MVKSurface(MVKInstance* mvkInstance,
|
MVKSurface::MVKSurface(MVKInstance* mvkInstance,
|
||||||
const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
|
const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) {
|
const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) {
|
||||||
initLayer((CAMetalLayer*)pCreateInfo->pLayer, "vkCreateMetalSurfaceEXT");
|
initLayer((CAMetalLayer*)pCreateInfo->pLayer, "vkCreateMetalSurfaceEXT", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
MVKSurface::MVKSurface(MVKInstance* mvkInstance,
|
||||||
|
const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) {
|
||||||
|
initLayer(nil, "vkCreateHeadlessSurfaceEXT", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pCreateInfo->pView can be either a CAMetalLayer or a view (NSView/UIView).
|
// pCreateInfo->pView can be either a CAMetalLayer or a view (NSView/UIView).
|
||||||
MVKSurface::MVKSurface(MVKInstance* mvkInstance,
|
MVKSurface::MVKSurface(MVKInstance* mvkInstance,
|
||||||
const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) {
|
const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) {
|
||||||
|
MVKLogWarn("%s() is deprecated. Use vkCreateMetalSurfaceEXT() from the VK_EXT_metal_surface extension.", STR(vkCreate_PLATFORM_SurfaceMVK));
|
||||||
|
|
||||||
// Get the platform object contained in pView
|
// Get the platform object contained in pView
|
||||||
id<NSObject> obj = (id<NSObject>)pCreateInfo->pView;
|
|
||||||
|
|
||||||
// If it's a view (NSView/UIView), extract the layer, otherwise assume it's already a CAMetalLayer.
|
// If it's a view (NSView/UIView), extract the layer, otherwise assume it's already a CAMetalLayer.
|
||||||
|
id<NSObject> obj = (id<NSObject>)pCreateInfo->pView;
|
||||||
if ([obj isKindOfClass: [PLATFORM_VIEW_CLASS class]]) {
|
if ([obj isKindOfClass: [PLATFORM_VIEW_CLASS class]]) {
|
||||||
obj = ((PLATFORM_VIEW_CLASS*)obj).layer;
|
__block id<NSObject> layer;
|
||||||
if ( !NSThread.isMainThread ) {
|
mvkDispatchToMainAndWait(^{ layer = ((PLATFORM_VIEW_CLASS*)obj).layer; });
|
||||||
MVKLogWarn("%s(): You are not calling this function from the main thread. %s should only be accessed from the main thread. When using this function outside the main thread, consider passing the CAMetalLayer itself in %s::pView, instead of the %s.",
|
obj = layer;
|
||||||
STR(vkCreate_PLATFORM_SurfaceMVK), STR(PLATFORM_VIEW_CLASS), STR(Vk_PLATFORM_SurfaceCreateInfoMVK), STR(PLATFORM_VIEW_CLASS));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm that we were provided with a CAMetalLayer
|
// Confirm that we were provided with a CAMetalLayer
|
||||||
initLayer([obj isKindOfClass: CAMetalLayer.class] ? (CAMetalLayer*)obj : nil,
|
initLayer([obj isKindOfClass: CAMetalLayer.class] ? (CAMetalLayer*)obj : nil, STR(vkCreate_PLATFORM_SurfaceMVK), false);
|
||||||
STR(vkCreate_PLATFORM_SurfaceMVK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKSurface::initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName) {
|
void MVKSurface::initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName, bool isHeadless) {
|
||||||
|
|
||||||
_mtlCAMetalLayer = [mtlLayer retain]; // retained
|
_mtlCAMetalLayer = [mtlLayer retain]; // retained
|
||||||
if ( !_mtlCAMetalLayer ) { setConfigurationResult(reportError(VK_ERROR_SURFACE_LOST_KHR, "%s(): On-screen rendering requires a layer of type CAMetalLayer.", vkFuncName)); }
|
if ( !_mtlCAMetalLayer && !isHeadless ) { setConfigurationResult(reportError(VK_ERROR_SURFACE_LOST_KHR, "%s(): On-screen rendering requires a layer of type CAMetalLayer.", vkFuncName)); }
|
||||||
|
|
||||||
// Sometimes, the owning view can replace its CAMetalLayer.
|
// Sometimes, the owning view can replace its CAMetalLayer.
|
||||||
// When that happens, the app needs to recreate the surface.
|
// When that happens, the app needs to recreate the surface.
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "MVKSmallVector.h"
|
#include "MVKSmallVector.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#import "CAMetalLayer+MoltenVK.h"
|
|
||||||
#import <Metal/Metal.h>
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
class MVKWatermark;
|
class MVKWatermark;
|
||||||
@ -46,9 +45,15 @@ public:
|
|||||||
/** Returns the CAMetalLayer underlying the surface used by this swapchain. */
|
/** Returns the CAMetalLayer underlying the surface used by this swapchain. */
|
||||||
CAMetalLayer* getCAMetalLayer();
|
CAMetalLayer* getCAMetalLayer();
|
||||||
|
|
||||||
|
/** Returns whether the surface is headless. */
|
||||||
|
bool isHeadless();
|
||||||
|
|
||||||
/** Returns the number of images in this swapchain. */
|
/** Returns the number of images in this swapchain. */
|
||||||
uint32_t getImageCount() { return (uint32_t)_presentableImages.size(); }
|
uint32_t getImageCount() { return (uint32_t)_presentableImages.size(); }
|
||||||
|
|
||||||
|
/** Returns the size of the images in this swapchain. */
|
||||||
|
VkExtent2D getImageExtent() { return _imageExtent; }
|
||||||
|
|
||||||
/** Returns the image at the specified index. */
|
/** Returns the image at the specified index. */
|
||||||
MVKPresentableSwapchainImage* getPresentableImage(uint32_t index) { return _presentableImages[index]; }
|
MVKPresentableSwapchainImage* getPresentableImage(uint32_t index) { return _presentableImages[index]; }
|
||||||
|
|
||||||
@ -126,7 +131,7 @@ protected:
|
|||||||
std::atomic<uint64_t> _currentAcquisitionID = 0;
|
std::atomic<uint64_t> _currentAcquisitionID = 0;
|
||||||
std::mutex _presentHistoryLock;
|
std::mutex _presentHistoryLock;
|
||||||
uint64_t _lastFrameTime = 0;
|
uint64_t _lastFrameTime = 0;
|
||||||
VkExtent2D _mtlLayerDrawableExtent = {0, 0};
|
VkExtent2D _imageExtent = {0, 0};
|
||||||
std::atomic<uint32_t> _unpresentedImageCount = 0;
|
std::atomic<uint32_t> _unpresentedImageCount = 0;
|
||||||
uint32_t _currentPerfLogFrameCount = 0;
|
uint32_t _currentPerfLogFrameCount = 0;
|
||||||
uint32_t _presentHistoryCount = 0;
|
uint32_t _presentHistoryCount = 0;
|
||||||
@ -134,18 +139,3 @@ protected:
|
|||||||
uint32_t _presentHistoryHeadIndex = 0;
|
uint32_t _presentHistoryHeadIndex = 0;
|
||||||
bool _isDeliberatelyScaled = false;
|
bool _isDeliberatelyScaled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Support functions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the natural extent of the CAMetalLayer.
|
|
||||||
*
|
|
||||||
* The natural extent is the size of the bounds property of the layer,
|
|
||||||
* multiplied by the contentsScale property of the layer, rounded
|
|
||||||
* to nearest integer using half-to-even rounding.
|
|
||||||
*/
|
|
||||||
static inline VkExtent2D mvkGetNaturalExtent(CAMetalLayer* mtlLayer) {
|
|
||||||
return mvkVkExtent2DFromCGSize(mtlLayer.naturalDrawableSizeMVK);
|
|
||||||
}
|
|
||||||
|
@ -26,9 +26,11 @@
|
|||||||
#include "MVKWatermarkTextureContent.h"
|
#include "MVKWatermarkTextureContent.h"
|
||||||
#include "MVKWatermarkShaderSource.h"
|
#include "MVKWatermarkShaderSource.h"
|
||||||
#include "mvk_datatypes.hpp"
|
#include "mvk_datatypes.hpp"
|
||||||
|
#include <libkern/OSByteOrder.h>
|
||||||
|
|
||||||
|
#import "CAMetalLayer+MoltenVK.h"
|
||||||
#import "MVKBlockObserver.h"
|
#import "MVKBlockObserver.h"
|
||||||
|
|
||||||
#include <libkern/OSByteOrder.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -49,6 +51,8 @@ void MVKSwapchain::propagateDebugName() {
|
|||||||
|
|
||||||
CAMetalLayer* MVKSwapchain::getCAMetalLayer() { return _surface->getCAMetalLayer(); }
|
CAMetalLayer* MVKSwapchain::getCAMetalLayer() { return _surface->getCAMetalLayer(); }
|
||||||
|
|
||||||
|
bool MVKSwapchain::isHeadless() { return _surface->isHeadless(); }
|
||||||
|
|
||||||
VkResult MVKSwapchain::getImages(uint32_t* pCount, VkImage* pSwapchainImages) {
|
VkResult MVKSwapchain::getImages(uint32_t* pCount, VkImage* pSwapchainImages) {
|
||||||
|
|
||||||
// Get the number of surface images
|
// Get the number of surface images
|
||||||
@ -124,16 +128,15 @@ VkResult MVKSwapchain::getSurfaceStatus() {
|
|||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This swapchain is optimally sized for the surface if the app has specified deliberate
|
// This swapchain is optimally sized for the surface if the app has specified
|
||||||
// swapchain scaling, or the CAMetalLayer drawableSize has not changed since the swapchain
|
// deliberate swapchain scaling, or the surface extent has not changed since the
|
||||||
// was created, and the CAMetalLayer will not need to be scaled when composited.
|
// swapchain was created, and the surface will not need to be scaled when composited.
|
||||||
bool MVKSwapchain::hasOptimalSurface() {
|
bool MVKSwapchain::hasOptimalSurface() {
|
||||||
if (_isDeliberatelyScaled) { return true; }
|
if (_isDeliberatelyScaled) { return true; }
|
||||||
|
|
||||||
auto* mtlLayer = getCAMetalLayer();
|
VkExtent2D surfExtent = _surface->getExtent();
|
||||||
VkExtent2D drawExtent = mvkVkExtent2DFromCGSize(mtlLayer.drawableSize);
|
return (mvkVkExtent2DsAreEqual(surfExtent, _imageExtent) &&
|
||||||
return (mvkVkExtent2DsAreEqual(drawExtent, _mtlLayerDrawableExtent) &&
|
mvkVkExtent2DsAreEqual(surfExtent, _surface->getNaturalExtent()));
|
||||||
mvkVkExtent2DsAreEqual(drawExtent, mvkGetNaturalExtent(mtlLayer)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -187,30 +190,29 @@ void MVKSwapchain::markFrameInterval() {
|
|||||||
VkResult MVKSwapchain::getRefreshCycleDuration(VkRefreshCycleDurationGOOGLE *pRefreshCycleDuration) {
|
VkResult MVKSwapchain::getRefreshCycleDuration(VkRefreshCycleDurationGOOGLE *pRefreshCycleDuration) {
|
||||||
if (_device->getConfigurationResult() != VK_SUCCESS) { return _device->getConfigurationResult(); }
|
if (_device->getConfigurationResult() != VK_SUCCESS) { return _device->getConfigurationResult(); }
|
||||||
|
|
||||||
auto* mtlLayer = getCAMetalLayer();
|
auto* screen = getCAMetalLayer().screenMVK; // Will be nil if headless
|
||||||
#if MVK_VISIONOS
|
#if MVK_MACOS && !MVK_MACCAT
|
||||||
// TODO: See if this can be obtained from OS instead
|
double framesPerSecond = 60;
|
||||||
NSInteger framesPerSecond = 90;
|
if (screen) {
|
||||||
|
CGDirectDisplayID displayId = [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
|
||||||
|
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
|
||||||
|
framesPerSecond = CGDisplayModeGetRefreshRate(mode);
|
||||||
|
CGDisplayModeRelease(mode);
|
||||||
|
#if MVK_XCODE_13
|
||||||
|
if (framesPerSecond == 0 && [screen respondsToSelector: @selector(maximumFramesPerSecond)])
|
||||||
|
framesPerSecond = [screen maximumFramesPerSecond];
|
||||||
|
#endif
|
||||||
|
// Builtin panels, e.g., on MacBook, report a zero refresh rate.
|
||||||
|
if (framesPerSecond == 0)
|
||||||
|
framesPerSecond = 60.0;
|
||||||
|
}
|
||||||
#elif MVK_IOS_OR_TVOS || MVK_MACCAT
|
#elif MVK_IOS_OR_TVOS || MVK_MACCAT
|
||||||
NSInteger framesPerSecond = 60;
|
NSInteger framesPerSecond = 60;
|
||||||
UIScreen* screen = mtlLayer.screenMVK;
|
|
||||||
if ([screen respondsToSelector: @selector(maximumFramesPerSecond)]) {
|
if ([screen respondsToSelector: @selector(maximumFramesPerSecond)]) {
|
||||||
framesPerSecond = screen.maximumFramesPerSecond;
|
framesPerSecond = screen.maximumFramesPerSecond;
|
||||||
}
|
}
|
||||||
#elif MVK_MACOS && !MVK_MACCAT
|
#elif MVK_VISIONOS
|
||||||
NSScreen* screen = mtlLayer.screenMVK;
|
NSInteger framesPerSecond = 90; // TODO: See if this can be obtained from OS instead
|
||||||
CGDirectDisplayID displayId = [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
|
|
||||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
|
|
||||||
double framesPerSecond = CGDisplayModeGetRefreshRate(mode);
|
|
||||||
CGDisplayModeRelease(mode);
|
|
||||||
#if MVK_XCODE_13
|
|
||||||
if (framesPerSecond == 0 && [screen respondsToSelector: @selector(maximumFramesPerSecond)])
|
|
||||||
framesPerSecond = [screen maximumFramesPerSecond];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Builtin panels, e.g., on MacBook, report a zero refresh rate.
|
|
||||||
if (framesPerSecond == 0)
|
|
||||||
framesPerSecond = 60.0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pRefreshCycleDuration->refreshDuration = (uint64_t)1e9 / framesPerSecond;
|
pRefreshCycleDuration->refreshDuration = (uint64_t)1e9 / framesPerSecond;
|
||||||
@ -260,12 +262,6 @@ void MVKSwapchain::endPresentation(const MVKImagePresentInfo& presentInfo, uint6
|
|||||||
_presentHistoryHeadIndex = (_presentHistoryHeadIndex + 1) % kMaxPresentationHistory;
|
_presentHistoryHeadIndex = (_presentHistoryHeadIndex + 1) % kMaxPresentationHistory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If actual present time is not available, use desired time instead, and if that
|
|
||||||
// hasn't been set, use the current time, which should be reasonably accurate (sub-ms),
|
|
||||||
// since we are here as part of the addPresentedHandler: callback.
|
|
||||||
if (actualPresentTime == 0) { actualPresentTime = presentInfo.desiredPresentTime; }
|
|
||||||
if (actualPresentTime == 0) { actualPresentTime = CACurrentMediaTime() * 1.0e9; }
|
|
||||||
|
|
||||||
_presentTimingHistory[_presentHistoryIndex].presentID = presentInfo.presentID;
|
_presentTimingHistory[_presentHistoryIndex].presentID = presentInfo.presentID;
|
||||||
_presentTimingHistory[_presentHistoryIndex].desiredPresentTime = presentInfo.desiredPresentTime;
|
_presentTimingHistory[_presentHistoryIndex].desiredPresentTime = presentInfo.desiredPresentTime;
|
||||||
_presentTimingHistory[_presentHistoryIndex].actualPresentTime = actualPresentTime;
|
_presentTimingHistory[_presentHistoryIndex].actualPresentTime = actualPresentTime;
|
||||||
@ -380,12 +376,13 @@ void MVKSwapchain::setHDRMetadataEXT(const VkHdrMetadataEXT& metadata) {
|
|||||||
|
|
||||||
MVKSwapchain::MVKSwapchain(MVKDevice* device, const VkSwapchainCreateInfoKHR* pCreateInfo)
|
MVKSwapchain::MVKSwapchain(MVKDevice* device, const VkSwapchainCreateInfoKHR* pCreateInfo)
|
||||||
: MVKVulkanAPIDeviceObject(device),
|
: MVKVulkanAPIDeviceObject(device),
|
||||||
_surface((MVKSurface*)pCreateInfo->surface) {
|
_surface((MVKSurface*)pCreateInfo->surface),
|
||||||
|
_imageExtent(pCreateInfo->imageExtent) {
|
||||||
|
|
||||||
// Check if oldSwapchain is properly set
|
// Check if oldSwapchain is properly set
|
||||||
auto* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain;
|
auto* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain;
|
||||||
if (oldSwapchain == _surface->_activeSwapchain) {
|
if (oldSwapchain == _surface->_activeSwapchain) {
|
||||||
_surface->_activeSwapchain = this;
|
_surface->setActiveSwapchain(this);
|
||||||
} else {
|
} else {
|
||||||
setConfigurationResult(reportError(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR, "vkCreateSwapchainKHR(): pCreateInfo->oldSwapchain does not match the VkSwapchain that is in use by the surface"));
|
setConfigurationResult(reportError(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR, "vkCreateSwapchainKHR(): pCreateInfo->oldSwapchain does not match the VkSwapchain that is in use by the surface"));
|
||||||
return;
|
return;
|
||||||
@ -470,10 +467,11 @@ void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo,
|
|||||||
VkSwapchainPresentScalingCreateInfoEXT* pScalingInfo,
|
VkSwapchainPresentScalingCreateInfoEXT* pScalingInfo,
|
||||||
uint32_t imgCnt) {
|
uint32_t imgCnt) {
|
||||||
|
|
||||||
if ( getIsSurfaceLost() ) { return; }
|
|
||||||
|
|
||||||
auto* mtlLayer = getCAMetalLayer();
|
auto* mtlLayer = getCAMetalLayer();
|
||||||
|
if ( !mtlLayer || getIsSurfaceLost() ) { return; }
|
||||||
|
|
||||||
auto minMagFilter = mvkConfig().swapchainMinMagFilterUseNearest ? kCAFilterNearest : kCAFilterLinear;
|
auto minMagFilter = mvkConfig().swapchainMinMagFilterUseNearest ? kCAFilterNearest : kCAFilterLinear;
|
||||||
|
mtlLayer.drawableSize = mvkCGSizeFromVkExtent2D(_imageExtent);
|
||||||
mtlLayer.device = getMTLDevice();
|
mtlLayer.device = getMTLDevice();
|
||||||
mtlLayer.pixelFormat = getPixelFormats()->getMTLPixelFormat(pCreateInfo->imageFormat);
|
mtlLayer.pixelFormat = getPixelFormats()->getMTLPixelFormat(pCreateInfo->imageFormat);
|
||||||
mtlLayer.maximumDrawableCountMVK = imgCnt;
|
mtlLayer.maximumDrawableCountMVK = imgCnt;
|
||||||
@ -491,15 +489,10 @@ void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo,
|
|||||||
// presentations on the oldSwapchain to complete and call back, but if the drawableSize
|
// presentations on the oldSwapchain to complete and call back, but if the drawableSize
|
||||||
// is not changing from the previous, we force those completions first.
|
// is not changing from the previous, we force those completions first.
|
||||||
auto* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain;
|
auto* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain;
|
||||||
if (oldSwapchain && mvkVkExtent2DsAreEqual(pCreateInfo->imageExtent, mvkVkExtent2DFromCGSize(mtlLayer.drawableSize))) {
|
if (oldSwapchain && mvkVkExtent2DsAreEqual(pCreateInfo->imageExtent, _surface->getExtent())) {
|
||||||
oldSwapchain->forceUnpresentedImageCompletion();
|
oldSwapchain->forceUnpresentedImageCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember the extent to later detect if it has changed under the covers,
|
|
||||||
// and set the drawable size of the CAMetalLayer from the extent.
|
|
||||||
_mtlLayerDrawableExtent = pCreateInfo->imageExtent;
|
|
||||||
mtlLayer.drawableSize = mvkCGSizeFromVkExtent2D(_mtlLayerDrawableExtent);
|
|
||||||
|
|
||||||
if (pCreateInfo->compositeAlpha != VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
|
if (pCreateInfo->compositeAlpha != VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
|
||||||
mtlLayer.opaque = pCreateInfo->compositeAlpha == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
mtlLayer.opaque = pCreateInfo->compositeAlpha == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
}
|
}
|
||||||
@ -585,14 +578,13 @@ void MVKSwapchain::initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* mtlLayer = getCAMetalLayer();
|
|
||||||
VkExtent2D imgExtent = pCreateInfo->imageExtent;
|
VkExtent2D imgExtent = pCreateInfo->imageExtent;
|
||||||
VkImageCreateInfo imgInfo = {
|
VkImageCreateInfo imgInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||||
.pNext = VK_NULL_HANDLE,
|
.pNext = VK_NULL_HANDLE,
|
||||||
.imageType = VK_IMAGE_TYPE_2D,
|
.imageType = VK_IMAGE_TYPE_2D,
|
||||||
.format = getPixelFormats()->getVkFormat(mtlLayer.pixelFormat),
|
.format = pCreateInfo->imageFormat,
|
||||||
.extent = { imgExtent.width, imgExtent.height, 1 },
|
.extent = mvkVkExtent3DFromVkExtent2D(imgExtent),
|
||||||
.mipLevels = 1,
|
.mipLevels = 1,
|
||||||
.arrayLayers = 1,
|
.arrayLayers = 1,
|
||||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
@ -618,14 +610,20 @@ void MVKSwapchain::initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo
|
|||||||
_presentableImages.push_back(_device->createPresentableSwapchainImage(&imgInfo, this, imgIdx, nullptr));
|
_presentableImages.push_back(_device->createPresentableSwapchainImage(&imgInfo, this, imgIdx, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* screenName = @"Main Screen";
|
auto* mtlLayer = getCAMetalLayer();
|
||||||
|
if (mtlLayer) {
|
||||||
|
NSString* screenName = @"Main Screen";
|
||||||
#if MVK_MACOS && !MVK_MACCAT
|
#if MVK_MACOS && !MVK_MACCAT
|
||||||
if ([mtlLayer.screenMVK respondsToSelector:@selector(localizedName)]) {
|
auto* screen = mtlLayer.screenMVK;
|
||||||
screenName = mtlLayer.screenMVK.localizedName;
|
if ([screen respondsToSelector:@selector(localizedName)]) {
|
||||||
}
|
screenName = screen.localizedName;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
MVKLogInfo("Created %d swapchain images with size (%d, %d) and contents scale %.1f in layer %s (%p) on screen %s.",
|
MVKLogInfo("Created %d swapchain images with size (%d, %d) and contents scale %.1f in layer %s (%p) on screen %s.",
|
||||||
imgCnt, imgExtent.width, imgExtent.height, mtlLayer.contentsScale, mtlLayer.name.UTF8String, mtlLayer, screenName.UTF8String);
|
imgCnt, imgExtent.width, imgExtent.height, mtlLayer.contentsScale, mtlLayer.name.UTF8String, mtlLayer, screenName.UTF8String);
|
||||||
|
} else {
|
||||||
|
MVKLogInfo("Created %d swapchain images with size (%d, %d) on headless surface.", imgCnt, imgExtent.width, imgExtent.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKSwapchain::destroy() {
|
void MVKSwapchain::destroy() {
|
||||||
|
@ -128,7 +128,7 @@ uint64_t MVKSemaphoreMTLEvent::deferSignal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MVKSemaphoreMTLEvent::encodeDeferredSignal(id<MTLCommandBuffer> mtlCmdBuff, uint64_t deferToken) {
|
void MVKSemaphoreMTLEvent::encodeDeferredSignal(id<MTLCommandBuffer> mtlCmdBuff, uint64_t deferToken) {
|
||||||
if (mtlCmdBuff) { [mtlCmdBuff encodeSignalEvent: _mtlEvent value: deferToken]; }
|
[mtlCmdBuff encodeSignalEvent: _mtlEvent value: deferToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
MVKSemaphoreMTLEvent::MVKSemaphoreMTLEvent(MVKDevice* device,
|
MVKSemaphoreMTLEvent::MVKSemaphoreMTLEvent(MVKDevice* device,
|
||||||
|
@ -109,6 +109,7 @@ MVK_EXTENSION(EXT_extended_dynamic_state3, EXT_EXTENDED_DYNAMIC_STATE
|
|||||||
MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0, 1.0)
|
MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA, MVK_NA)
|
MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA, MVK_NA)
|
||||||
|
MVK_EXTENSION(EXT_headless_surface, EXT_HEADLESS_SURFACE, INSTANCE, 10.11, 8.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0, 1.0)
|
||||||
|
@ -23,12 +23,10 @@
|
|||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
#if MVK_IOS_OR_TVOS || MVK_MACCAT
|
#if MVK_IOS_OR_TVOS || MVK_MACCAT
|
||||||
# define PLATFORM_SCREEN_CLASS UIScreen
|
|
||||||
# include <UIKit/UIScreen.h>
|
# include <UIKit/UIScreen.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MVK_MACOS && !MVK_MACCAT
|
#if MVK_MACOS && !MVK_MACCAT
|
||||||
# define PLATFORM_SCREEN_CLASS NSScreen
|
|
||||||
# include <AppKit/NSScreen.h>
|
# include <AppKit/NSScreen.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -76,9 +74,16 @@
|
|||||||
*/
|
*/
|
||||||
@property(nonatomic, readwrite) CFStringRef colorspaceNameMVK;
|
@property(nonatomic, readwrite) CFStringRef colorspaceNameMVK;
|
||||||
|
|
||||||
#if !MVK_VISIONOS
|
#if MVK_IOS_OR_TVOS || MVK_MACCAT
|
||||||
/** Returns the screen on which this layer is rendering. */
|
/** Returns the screen on which this layer is rendering. */
|
||||||
@property(nonatomic, readonly) PLATFORM_SCREEN_CLASS* screenMVK;
|
@property(nonatomic, readonly) UIScreen* screenMVK;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MVK_MACOS && !MVK_MACCAT
|
||||||
|
/** Returns the screen on which this layer is rendering. */
|
||||||
|
@property(nonatomic, readonly) NSScreen* screenMVK;
|
||||||
|
|
||||||
|
@property(nonatomic, readonly) NSScreen* privateScreenMVKImpl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "CAMetalLayer+MoltenVK.h"
|
#include "CAMetalLayer+MoltenVK.h"
|
||||||
|
#include "MVKOSExtensions.h"
|
||||||
|
|
||||||
#if MVK_MACOS && !MVK_MACCAT
|
#if MVK_MACOS && !MVK_MACCAT
|
||||||
# include <AppKit/NSApplication.h>
|
# include <AppKit/NSApplication.h>
|
||||||
@ -88,6 +89,13 @@
|
|||||||
|
|
||||||
#if MVK_MACOS && !MVK_MACCAT
|
#if MVK_MACOS && !MVK_MACCAT
|
||||||
-(NSScreen*) screenMVK {
|
-(NSScreen*) screenMVK {
|
||||||
|
__block NSScreen* screen;
|
||||||
|
mvkDispatchToMainAndWait(^{ screen = self.privateScreenMVKImpl; });
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for the screen currently displaying the layer, and default to the main screen if it can't be found.
|
||||||
|
-(NSScreen*) privateScreenMVKImpl {
|
||||||
// If this layer has a delegate that is an NSView, and the view is in a window, retrieve the screen from the window.
|
// If this layer has a delegate that is an NSView, and the view is in a window, retrieve the screen from the window.
|
||||||
if ([self.delegate isKindOfClass: NSView.class]) {
|
if ([self.delegate isKindOfClass: NSView.class]) {
|
||||||
NSWindow* window = ((NSView*)self.delegate).window;
|
NSWindow* window = ((NSView*)self.delegate).window;
|
@ -3869,6 +3869,26 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkSetHdrMetadataEXT(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark VK_EXT_headless_surface extension
|
||||||
|
|
||||||
|
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCreateHeadlessSurfaceEXT(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface) {
|
||||||
|
|
||||||
|
MVKTraceVulkanCallStart();
|
||||||
|
MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
|
||||||
|
MVKSurface* mvkSrfc = mvkInst->createSurface(pCreateInfo, pAllocator);
|
||||||
|
*pSurface = (VkSurfaceKHR)mvkSrfc;
|
||||||
|
VkResult rslt = mvkSrfc->getConfigurationResult();
|
||||||
|
if (rslt < 0) { *pSurface = VK_NULL_HANDLE; mvkInst->destroySurface(mvkSrfc, pAllocator); }
|
||||||
|
MVKTraceVulkanCallEnd();
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark VK_EXT_host_query_reset extension
|
#pragma mark VK_EXT_host_query_reset extension
|
||||||
|
|
||||||
|
20
README.md
20
README.md
@ -149,21 +149,14 @@ for which to build the external libraries. The platform choices include:
|
|||||||
--maccat
|
--maccat
|
||||||
--tvos
|
--tvos
|
||||||
--tvossim
|
--tvossim
|
||||||
--visionos
|
|
||||||
--visionossim
|
|
||||||
|
|
||||||
The `visionos` and `visionossim` selections require Xcode 15+.
|
|
||||||
|
|
||||||
You can specify multiple of these selections. The result is a single `XCFramework`
|
You can specify multiple of these selections. The result is a single `XCFramework`
|
||||||
for each external dependency library, with each `XCFramework` containing binaries for
|
for each external dependency library, with each `XCFramework` containing binaries for
|
||||||
each of the requested platforms.
|
each of the requested platforms.
|
||||||
|
|
||||||
The `--all` selection is the same as entering all of the other platform choices, except
|
The `--all` selection is the same as entering all of the other platform choices,
|
||||||
`--visionos` and `--visionossim`, and will result in a single `XCFramework` for each
|
and will result in a single `XCFramework` for each external dependency library,
|
||||||
external dependency library, with each `XCFramework` containing binaries for all supported
|
with each `XCFramework` containing binaries for all supported platforms and simulators.
|
||||||
platforms and simulators. The `--visionos` and `--visionossim` selections must be invoked
|
|
||||||
with a separate invocation of `fetchDependencies`, because those selections require
|
|
||||||
Xcode 15+, and will cause a multi-platform build on older versions of Xcode to abort.
|
|
||||||
|
|
||||||
Running `fetchDependencies` repeatedly with different platforms will accumulate targets
|
Running `fetchDependencies` repeatedly with different platforms will accumulate targets
|
||||||
in the `XCFramework`, if the `--keep-cache` option is used on each invocation.
|
in the `XCFramework`, if the `--keep-cache` option is used on each invocation.
|
||||||
@ -263,8 +256,6 @@ from the command line. The following `make` targets are provided:
|
|||||||
make maccat
|
make maccat
|
||||||
make tvos
|
make tvos
|
||||||
make tvossim
|
make tvossim
|
||||||
make visionos
|
|
||||||
make visionossim
|
|
||||||
|
|
||||||
make all-debug
|
make all-debug
|
||||||
make macos-debug
|
make macos-debug
|
||||||
@ -273,15 +264,12 @@ from the command line. The following `make` targets are provided:
|
|||||||
make maccat-debug
|
make maccat-debug
|
||||||
make tvos-debug
|
make tvos-debug
|
||||||
make tvossim-debug
|
make tvossim-debug
|
||||||
make visionos-debug
|
|
||||||
make visionossim-debug
|
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
make install
|
make install
|
||||||
|
|
||||||
- Running `make` repeatedly with different targets will accumulate binaries for these different targets.
|
- Running `make` repeatedly with different targets will accumulate binaries for these different targets.
|
||||||
- The `all` target executes all platform targets, except `visionos` and `visionossim`, as these require
|
- The `all` target executes all platform targets.
|
||||||
Xcode 15+, and will abort a multi-platform build on older versions of Xcode.
|
|
||||||
- The `all` target is the default target. Running `make` with no arguments is the same as running `make all`.
|
- The `all` target is the default target. Running `make` with no arguments is the same as running `make all`.
|
||||||
- The `*-debug` targets build the binaries using the **_Debug_** configuration.
|
- The `*-debug` targets build the binaries using the **_Debug_** configuration.
|
||||||
- The `install` target will copy the most recently built `MoltenVK.xcframework` into the
|
- The `install` target will copy the most recently built `MoltenVK.xcframework` into the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user