Merge pull request #852 from billhollings/master
Various fixes resulting from testing for SDK release.
This commit is contained in:
commit
1a25de5500
3
Demos/Demos.xcworkspace/contents.xcworkspacedata
generated
3
Demos/Demos.xcworkspace/contents.xcworkspacedata
generated
@ -7,9 +7,6 @@
|
|||||||
<Group
|
<Group
|
||||||
location = "container:"
|
location = "container:"
|
||||||
name = "LunarG-VulkanSamples">
|
name = "LunarG-VulkanSamples">
|
||||||
<FileRef
|
|
||||||
location = "group:LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:LunarG-VulkanSamples/Cube/Cube.xcodeproj">
|
location = "group:LunarG-VulkanSamples/Cube/Cube.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
@ -64,7 +64,12 @@ as a system library instead.
|
|||||||
<a name="lunarg-vulkan-samples-api"></a>
|
<a name="lunarg-vulkan-samples-api"></a>
|
||||||
### *API-Samples*
|
### *API-Samples*
|
||||||
|
|
||||||
This *Xcode* project actually contains a large number of modular demos, with each demo
|
> **_Note:_** The `Vulkan-Samples API-Samples` have recently changed to use a different build
|
||||||
|
process that involves converting GLSL to SPIR-V via scripts. This upgrade has not yet been
|
||||||
|
integrated into the *Xcode*-based build environment used to build these demos here.
|
||||||
|
As a result, the `API-Samples` demos have been disabled here until this can be corrected.
|
||||||
|
|
||||||
|
This *Xcode* project contains a large number of modular demos, with each demo
|
||||||
demonstrating a particular *Vulkan* feature, or suite of calls.
|
demonstrating a particular *Vulkan* feature, or suite of calls.
|
||||||
|
|
||||||
This demo can be found in the `LunarG-VulkanSamples/API-Samples` folder, and in the
|
This demo can be found in the `LunarG-VulkanSamples/API-Samples` folder, and in the
|
||||||
@ -77,7 +82,7 @@ To specify which of the many modular demos to run, open the `Samples.h` in the `
|
|||||||
project in the *Xcode Project Navigator* in the `Demos.xcworkspace` *Xcode* workspace, and
|
project in the *Xcode Project Navigator* in the `Demos.xcworkspace` *Xcode* workspace, and
|
||||||
follow the instructions in the comments within that file.
|
follow the instructions in the comments within that file.
|
||||||
|
|
||||||
> **Note:** For simplicity, the `API-Samples` demos are bare-bones. Each of the `API-Samples`
|
> **_Note:_** For simplicity, the `API-Samples` demos are bare-bones. Each of the `API-Samples`
|
||||||
> demos renders a single frame during app startup, and then leaves the rendered image static.
|
> demos renders a single frame during app startup, and then leaves the rendered image static.
|
||||||
> There is no display loop or motion in any of these demos.
|
> There is no display loop or motion in any of these demos.
|
||||||
> **This is normal for these demos, and the demo has not "hung" or "crashed" when this occurs.**
|
> **This is normal for these demos, and the demo has not "hung" or "crashed" when this occurs.**
|
||||||
@ -91,7 +96,7 @@ The `API-Samples` demo is a simple example of installing **MoltenVK** as a *stat
|
|||||||
<a name="lunarg-vulkan-samples-hologram"></a>
|
<a name="lunarg-vulkan-samples-hologram"></a>
|
||||||
### *Hologram*
|
### *Hologram*
|
||||||
|
|
||||||
> **Note:** In order to build the `Hologram` demo, you must have *Python3* installed
|
> **_Note:_** In order to build the `Hologram` demo, you must have *Python3* installed
|
||||||
> on your build computer.
|
> on your build computer.
|
||||||
|
|
||||||
This is a sophisticated particle demo that populates command buffers from multiple threads.
|
This is a sophisticated particle demo that populates command buffers from multiple threads.
|
||||||
|
@ -32,11 +32,13 @@ Released 2020/04/05
|
|||||||
- Fix issue causing screen captures from swapchain image to deadlock.
|
- Fix issue causing screen captures from swapchain image to deadlock.
|
||||||
- Fix memory estimates for iOS 13+.
|
- Fix memory estimates for iOS 13+.
|
||||||
- Broaden conditions for host read sync for image memory barriers on macOS.
|
- Broaden conditions for host read sync for image memory barriers on macOS.
|
||||||
|
- Fix issue of reseting `CAMetalDrawable` and `MTLTexture` of peer swapchain images.
|
||||||
- Fix the `make install` build command to overwrite the existing framework in the system
|
- Fix the `make install` build command to overwrite the existing framework in the system
|
||||||
framework library, and update `README.md` to clarify the instructions for using `make install`.
|
framework library, and update `README.md` to clarify the instructions for using `make install`.
|
||||||
- Update the `README.md` and `MoltenVK_Runtime_UserGuide.md` documents to clarify that
|
- Update the `README.md` and `MoltenVK_Runtime_UserGuide.md` documents to clarify that
|
||||||
**MoltenVK** is not a fully-compliant implementation of *Vulkan*.
|
**MoltenVK** is not a fully-compliant implementation of *Vulkan*.
|
||||||
- Support Xcode 11.4.
|
- Support Xcode 11.4.
|
||||||
|
- Disable `API-Samples` demos and document in `Demos/README.md`.
|
||||||
- Update dependency libraries to match *Vulkan SDK 1.2.135*.
|
- Update dependency libraries to match *Vulkan SDK 1.2.135*.
|
||||||
- Update to latest SPIRV-Cross version:
|
- Update to latest SPIRV-Cross version:
|
||||||
- MSL: Support inline uniform blocks in argument buffers.
|
- MSL: Support inline uniform blocks in argument buffers.
|
||||||
|
@ -503,8 +503,6 @@
|
|||||||
A94FB7841C7DFB4800632CA3 /* MVKDevice.mm */,
|
A94FB7841C7DFB4800632CA3 /* MVKDevice.mm */,
|
||||||
A94FB7851C7DFB4800632CA3 /* MVKDeviceMemory.h */,
|
A94FB7851C7DFB4800632CA3 /* MVKDeviceMemory.h */,
|
||||||
A94FB7861C7DFB4800632CA3 /* MVKDeviceMemory.mm */,
|
A94FB7861C7DFB4800632CA3 /* MVKDeviceMemory.mm */,
|
||||||
A9653FB724129C84005999D7 /* MVKPixelFormats.h */,
|
|
||||||
A9653FB924129C84005999D7 /* MVKPixelFormats.mm */,
|
|
||||||
A94FB7871C7DFB4800632CA3 /* MVKFramebuffer.h */,
|
A94FB7871C7DFB4800632CA3 /* MVKFramebuffer.h */,
|
||||||
A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */,
|
A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */,
|
||||||
A94FB7891C7DFB4800632CA3 /* MVKImage.h */,
|
A94FB7891C7DFB4800632CA3 /* MVKImage.h */,
|
||||||
@ -513,6 +511,8 @@
|
|||||||
A94FB78C1C7DFB4800632CA3 /* MVKInstance.mm */,
|
A94FB78C1C7DFB4800632CA3 /* MVKInstance.mm */,
|
||||||
A94FB78D1C7DFB4800632CA3 /* MVKPipeline.h */,
|
A94FB78D1C7DFB4800632CA3 /* MVKPipeline.h */,
|
||||||
A94FB78E1C7DFB4800632CA3 /* MVKPipeline.mm */,
|
A94FB78E1C7DFB4800632CA3 /* MVKPipeline.mm */,
|
||||||
|
A9653FB724129C84005999D7 /* MVKPixelFormats.h */,
|
||||||
|
A9653FB924129C84005999D7 /* MVKPixelFormats.mm */,
|
||||||
A94FB78F1C7DFB4800632CA3 /* MVKQueryPool.h */,
|
A94FB78F1C7DFB4800632CA3 /* MVKQueryPool.h */,
|
||||||
A94FB7901C7DFB4800632CA3 /* MVKQueryPool.mm */,
|
A94FB7901C7DFB4800632CA3 /* MVKQueryPool.mm */,
|
||||||
A94FB7911C7DFB4800632CA3 /* MVKQueue.h */,
|
A94FB7911C7DFB4800632CA3 /* MVKQueue.h */,
|
||||||
|
@ -163,6 +163,18 @@ typedef unsigned long MTLLanguageVersion;
|
|||||||
* a command is executed. This is a classic time-space trade off. When command pooling is
|
* a command is executed. This is a classic time-space trade off. When command pooling is
|
||||||
* active, the memory in the pool can be cleared via a call to the vkTrimCommandPoolKHR()
|
* active, the memory in the pool can be cleared via a call to the vkTrimCommandPoolKHR()
|
||||||
* command. This setting is enabled by default, and MoltenVK will pool command memory.
|
* command. This setting is enabled by default, and MoltenVK will pool command memory.
|
||||||
|
*
|
||||||
|
* 9. The MVK_CONFIG_USE_MTLHEAP runtime environment variable or MoltenVK compile-time build
|
||||||
|
* setting controls whether MoltenVK should use MTLHeaps for allocating textures and buffers
|
||||||
|
* from device memory. If this environment variable is enabled, and placement MTLHeaps are
|
||||||
|
* available on the platform, MoltenVK will allocate a placement MTLHeap for each VkDeviceMemory
|
||||||
|
* instance, and allocate textures and buffers from that placement heap. If this environment
|
||||||
|
* variable is disabled, MoltenVK will allocate textures and buffers from general device memory.
|
||||||
|
* Apple recommends that MTLHeaps should only be used for specific requirements such as aliasing
|
||||||
|
* or hazard tracking, and MoltenVK testing has shown that allocating multiple textures of
|
||||||
|
* different types or usages from one MTLHeap can occassionally cause corruption issues under
|
||||||
|
* certain circumstances. Because of this, this setting is disabled by default, and MoltenVK
|
||||||
|
* will allocate texures and buffers from general device memory.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class MVKResource;
|
|||||||
class MVKBuffer;
|
class MVKBuffer;
|
||||||
class MVKBufferView;
|
class MVKBufferView;
|
||||||
class MVKImage;
|
class MVKImage;
|
||||||
class MVKSwapchainImage;
|
class MVKPresentableSwapchainImage;
|
||||||
class MVKImageView;
|
class MVKImageView;
|
||||||
class MVKSwapchain;
|
class MVKSwapchain;
|
||||||
class MVKDeviceMemory;
|
class MVKDeviceMemory;
|
||||||
@ -450,12 +450,12 @@ public:
|
|||||||
void destroySwapchain(MVKSwapchain* mvkSwpChn,
|
void destroySwapchain(MVKSwapchain* mvkSwpChn,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
MVKSwapchainImage* createSwapchainImage(const VkImageCreateInfo* pCreateInfo,
|
MVKPresentableSwapchainImage* createPresentableSwapchainImage(const VkImageCreateInfo* pCreateInfo,
|
||||||
MVKSwapchain* swapchain,
|
MVKSwapchain* swapchain,
|
||||||
uint32_t swapchainIndex,
|
uint32_t swapchainIndex,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
void destroySwapchainImage(MVKSwapchainImage* mvkImg,
|
void destroyPresentableSwapchainImage(MVKPresentableSwapchainImage* mvkImg,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
MVKFence* createFence(const VkFenceCreateInfo* pCreateInfo,
|
MVKFence* createFence(const VkFenceCreateInfo* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator);
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
@ -773,7 +773,15 @@ MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtl
|
|||||||
|
|
||||||
// Initializes the Metal-specific physical device features of this instance.
|
// Initializes the Metal-specific physical device features of this instance.
|
||||||
void MVKPhysicalDevice::initMetalFeatures() {
|
void MVKPhysicalDevice::initMetalFeatures() {
|
||||||
mvkClear(&_metalFeatures); // Start with everything cleared
|
|
||||||
|
# ifndef MVK_CONFIG_USE_MTLHEAP
|
||||||
|
# define MVK_CONFIG_USE_MTLHEAP 0
|
||||||
|
# endif
|
||||||
|
bool useMTLHeaps;
|
||||||
|
MVK_SET_FROM_ENV_OR_BUILD_BOOL(useMTLHeaps, MVK_CONFIG_USE_MTLHEAP);
|
||||||
|
|
||||||
|
// Start with all Metal features cleared
|
||||||
|
mvkClear(&_metalFeatures);
|
||||||
|
|
||||||
_metalFeatures.maxPerStageBufferCount = 31;
|
_metalFeatures.maxPerStageBufferCount = 31;
|
||||||
_metalFeatures.maxMTLBufferSize = (256 * MEBI);
|
_metalFeatures.maxMTLBufferSize = (256 * MEBI);
|
||||||
@ -848,7 +856,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
|||||||
|
|
||||||
if ( mvkOSVersionIsAtLeast(13.0) ) {
|
if ( mvkOSVersionIsAtLeast(13.0) ) {
|
||||||
_metalFeatures.mslVersionEnum = MTLLanguageVersion2_2;
|
_metalFeatures.mslVersionEnum = MTLLanguageVersion2_2;
|
||||||
_metalFeatures.placementHeaps = true;
|
_metalFeatures.placementHeaps = useMTLHeaps;
|
||||||
if (supportsMTLGPUFamily(Apple4)) {
|
if (supportsMTLGPUFamily(Apple4)) {
|
||||||
_metalFeatures.nativeTextureSwizzle = true;
|
_metalFeatures.nativeTextureSwizzle = true;
|
||||||
}
|
}
|
||||||
@ -904,7 +912,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
|||||||
_metalFeatures.native3DCompressedTextures = true;
|
_metalFeatures.native3DCompressedTextures = true;
|
||||||
if (supportsMTLGPUFamily(Mac2)) {
|
if (supportsMTLGPUFamily(Mac2)) {
|
||||||
_metalFeatures.nativeTextureSwizzle = true;
|
_metalFeatures.nativeTextureSwizzle = true;
|
||||||
_metalFeatures.placementHeaps = true;
|
_metalFeatures.placementHeaps = useMTLHeaps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -957,7 +965,6 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the physical device features of this instance.
|
// Initializes the physical device features of this instance.
|
||||||
@ -2131,7 +2138,7 @@ MVKImage* MVKDevice::createImage(const VkImageCreateInfo* pCreateInfo,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (swapchainInfo) {
|
if (swapchainInfo) {
|
||||||
return createSwapchainImage(pCreateInfo, (MVKSwapchain*)swapchainInfo->swapchain, uint32_t(-1), pAllocator);
|
return (MVKImage*)addResource(new MVKPeerSwapchainImage(this, pCreateInfo, (MVKSwapchain*)swapchainInfo->swapchain, uint32_t(-1)));
|
||||||
}
|
}
|
||||||
return (MVKImage*)addResource(new MVKImage(this, pCreateInfo));
|
return (MVKImage*)addResource(new MVKImage(this, pCreateInfo));
|
||||||
}
|
}
|
||||||
@ -2162,15 +2169,15 @@ void MVKDevice::destroySwapchain(MVKSwapchain* mvkSwpChn,
|
|||||||
mvkSwpChn->destroy();
|
mvkSwpChn->destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
MVKSwapchainImage* MVKDevice::createSwapchainImage(const VkImageCreateInfo* pCreateInfo,
|
MVKPresentableSwapchainImage* MVKDevice::createPresentableSwapchainImage(const VkImageCreateInfo* pCreateInfo,
|
||||||
MVKSwapchain* swapchain,
|
MVKSwapchain* swapchain,
|
||||||
uint32_t swapchainIndex,
|
uint32_t swapchainIndex,
|
||||||
const VkAllocationCallbacks* pAllocator) {
|
const VkAllocationCallbacks* pAllocator) {
|
||||||
return (MVKSwapchainImage*)addResource(new MVKSwapchainImage(this, pCreateInfo, swapchain, swapchainIndex));
|
return (MVKPresentableSwapchainImage*)addResource(new MVKPresentableSwapchainImage(this, pCreateInfo, swapchain, swapchainIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKDevice::destroySwapchainImage(MVKSwapchainImage* mvkImg,
|
void MVKDevice::destroyPresentableSwapchainImage(MVKPresentableSwapchainImage* mvkImg,
|
||||||
const VkAllocationCallbacks* pAllocator) {
|
const VkAllocationCallbacks* pAllocator) {
|
||||||
removeResource(mvkImg);
|
removeResource(mvkImg);
|
||||||
mvkImg->destroy();
|
mvkImg->destroy();
|
||||||
}
|
}
|
||||||
@ -2656,10 +2663,9 @@ void MVKDevice::initPhysicalDevice(MVKPhysicalDevice* physicalDevice, const VkDe
|
|||||||
}
|
}
|
||||||
MVKLogInfo("Using %s for Vulkan semaphores.", _useMTLFenceForSemaphores ? "MTLFence" : (_useMTLEventForSemaphores ? "MTLEvent" : "emulation"));
|
MVKLogInfo("Using %s for Vulkan semaphores.", _useMTLFenceForSemaphores ? "MTLFence" : (_useMTLEventForSemaphores ? "MTLEvent" : "emulation"));
|
||||||
|
|
||||||
#ifndef MVK_CONFIG_USE_COMMAND_POOLING
|
# ifndef MVK_CONFIG_USE_COMMAND_POOLING
|
||||||
# define MVK_CONFIG_USE_COMMAND_POOLING 1
|
# define MVK_CONFIG_USE_COMMAND_POOLING 1
|
||||||
#endif
|
# endif
|
||||||
_useCommandPooling = MVK_CONFIG_USE_COMMAND_POOLING;
|
|
||||||
MVK_SET_FROM_ENV_OR_BUILD_BOOL(_useCommandPooling, MVK_CONFIG_USE_COMMAND_POOLING);
|
MVK_SET_FROM_ENV_OR_BUILD_BOOL(_useCommandPooling, MVK_CONFIG_USE_COMMAND_POOLING);
|
||||||
|
|
||||||
#if MVK_MACOS
|
#if MVK_MACOS
|
||||||
|
@ -147,7 +147,7 @@ public:
|
|||||||
#pragma mark Metal
|
#pragma mark Metal
|
||||||
|
|
||||||
/** Returns the Metal texture underlying this image. */
|
/** Returns the Metal texture underlying this image. */
|
||||||
id<MTLTexture> getMTLTexture();
|
virtual id<MTLTexture> getMTLTexture();
|
||||||
|
|
||||||
/** Returns a Metal texture that interprets the pixels in the specified format. */
|
/** Returns a Metal texture that interprets the pixels in the specified format. */
|
||||||
id<MTLTexture> getMTLTexture(MTLPixelFormat mtlPixFmt);
|
id<MTLTexture> getMTLTexture(MTLPixelFormat mtlPixFmt);
|
||||||
@ -235,9 +235,9 @@ protected:
|
|||||||
bool validateUseTexelBuffer();
|
bool validateUseTexelBuffer();
|
||||||
void initSubresources(const VkImageCreateInfo* pCreateInfo);
|
void initSubresources(const VkImageCreateInfo* pCreateInfo);
|
||||||
void initSubresourceLayout(MVKImageSubresource& imgSubRez);
|
void initSubresourceLayout(MVKImageSubresource& imgSubRez);
|
||||||
virtual id<MTLTexture> newMTLTexture();
|
id<MTLTexture> newMTLTexture();
|
||||||
void resetMTLTexture();
|
void releaseMTLTexture();
|
||||||
void resetIOSurface();
|
void releaseIOSurface();
|
||||||
MTLTextureDescriptor* newMTLTextureDescriptor();
|
MTLTextureDescriptor* newMTLTextureDescriptor();
|
||||||
void updateMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
|
void updateMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
|
||||||
void getMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
|
void getMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
|
||||||
@ -274,10 +274,44 @@ protected:
|
|||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark MVKSwapchainImage
|
#pragma mark MVKSwapchainImage
|
||||||
|
|
||||||
|
/** Abstract class of Vulkan image used as a rendering destination within a swapchain. */
|
||||||
|
class MVKSwapchainImage : public MVKImage {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Binds this resource to the specified offset within the specified memory allocation. */
|
||||||
|
VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) override;
|
||||||
|
|
||||||
|
#pragma mark Metal
|
||||||
|
|
||||||
|
/** Returns the Metal texture used by the CAMetalDrawable underlying this image. */
|
||||||
|
id<MTLTexture> getMTLTexture() override;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Construction
|
||||||
|
|
||||||
|
/** Constructs an instance for the specified device and swapchain. */
|
||||||
|
MVKSwapchainImage(MVKDevice* device,
|
||||||
|
const VkImageCreateInfo* pCreateInfo,
|
||||||
|
MVKSwapchain* swapchain,
|
||||||
|
uint32_t swapchainIndex);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class MVKPeerSwapchainImage;
|
||||||
|
|
||||||
|
virtual id<CAMetalDrawable> getCAMetalDrawable() = 0;
|
||||||
|
|
||||||
|
MVKSwapchain* _swapchain;
|
||||||
|
uint32_t _swapchainIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark MVKPresentableSwapchainImage
|
||||||
|
|
||||||
/** Indicates the relative availability of each image in the swapchain. */
|
/** Indicates the relative availability of each image in the swapchain. */
|
||||||
typedef struct MVKSwapchainImageAvailability {
|
typedef struct MVKSwapchainImageAvailability {
|
||||||
uint64_t acquisitionID; /**< When this image was last made available, relative to the other images in the swapchain. Smaller value is earlier. */
|
uint64_t acquisitionID; /**< When this image was last made available, relative to the other images in the swapchain. Smaller value is earlier. */
|
||||||
uint32_t waitCount; /**< The number of semaphores already waiting for this image. */
|
|
||||||
bool isAvailable; /**< Indicates whether this image is currently available. */
|
bool isAvailable; /**< Indicates whether this image is currently available. */
|
||||||
|
|
||||||
bool operator< (const MVKSwapchainImageAvailability& rhs) const;
|
bool operator< (const MVKSwapchainImageAvailability& rhs) const;
|
||||||
@ -287,18 +321,11 @@ typedef struct MVKSwapchainImageAvailability {
|
|||||||
typedef std::pair<MVKSemaphore*, MVKFence*> MVKSwapchainSignaler;
|
typedef std::pair<MVKSemaphore*, MVKFence*> MVKSwapchainSignaler;
|
||||||
|
|
||||||
|
|
||||||
/** Represents a Vulkan image used as a rendering destination within a swapchain. */
|
/** Represents a Vulkan swapchain image that can be submitted to the presentation engine. */
|
||||||
class MVKSwapchainImage : public MVKImage {
|
class MVKPresentableSwapchainImage : public MVKSwapchainImage {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Binds this resource to the specified offset within the specified memory allocation. */
|
|
||||||
VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) override;
|
|
||||||
|
|
||||||
/** Binds this resource according to the specified bind information. */
|
|
||||||
VkResult bindDeviceMemory2(const void* pBindInfo) override;
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Metal
|
#pragma mark Metal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -315,30 +342,27 @@ public:
|
|||||||
#pragma mark Construction
|
#pragma mark Construction
|
||||||
|
|
||||||
/** Constructs an instance for the specified device and swapchain. */
|
/** Constructs an instance for the specified device and swapchain. */
|
||||||
MVKSwapchainImage(MVKDevice* device,
|
MVKPresentableSwapchainImage(MVKDevice* device,
|
||||||
const VkImageCreateInfo* pCreateInfo,
|
const VkImageCreateInfo* pCreateInfo,
|
||||||
MVKSwapchain* swapchain,
|
MVKSwapchain* swapchain,
|
||||||
uint32_t swapchainIndex);
|
uint32_t swapchainIndex);
|
||||||
|
|
||||||
~MVKSwapchainImage() override;
|
~MVKPresentableSwapchainImage() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend MVKSwapchain;
|
friend MVKSwapchain;
|
||||||
|
|
||||||
id<MTLTexture> newMTLTexture() override;
|
id<CAMetalDrawable> getCAMetalDrawable() override;
|
||||||
id<CAMetalDrawable> getCAMetalDrawable();
|
void releaseMetalDrawable();
|
||||||
void resetMetalDrawable();
|
|
||||||
MVKSwapchainImageAvailability getAvailability();
|
MVKSwapchainImageAvailability getAvailability();
|
||||||
void makeAvailable();
|
void makeAvailable();
|
||||||
void signalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence);
|
void acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence);
|
||||||
void signal(MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff);
|
void signal(MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff);
|
||||||
void signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdBuff);
|
void signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdBuff);
|
||||||
static void markAsTracked(MVKSwapchainSignaler& signaler);
|
static void markAsTracked(MVKSwapchainSignaler& signaler);
|
||||||
static void unmarkAsTracked(MVKSwapchainSignaler& signaler);
|
static void unmarkAsTracked(MVKSwapchainSignaler& signaler);
|
||||||
void renderWatermark(id<MTLCommandBuffer> mtlCmdBuff);
|
void renderWatermark(id<MTLCommandBuffer> mtlCmdBuff);
|
||||||
|
|
||||||
MVKSwapchain* _swapchain;
|
|
||||||
uint32_t _swapchainIndex;
|
|
||||||
id<CAMetalDrawable> _mtlDrawable;
|
id<CAMetalDrawable> _mtlDrawable;
|
||||||
MVKSwapchainImageAvailability _availability;
|
MVKSwapchainImageAvailability _availability;
|
||||||
MVKVectorInline<MVKSwapchainSignaler, 1> _availabilitySignalers;
|
MVKVectorInline<MVKSwapchainSignaler, 1> _availabilitySignalers;
|
||||||
@ -347,6 +371,32 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark MVKPeerSwapchainImage
|
||||||
|
|
||||||
|
/** Represents a Vulkan swapchain image that can be associated as a peer to a swapchain image. */
|
||||||
|
class MVKPeerSwapchainImage : public MVKSwapchainImage {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Binds this resource according to the specified bind information. */
|
||||||
|
VkResult bindDeviceMemory2(const void* pBindInfo) override;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Construction
|
||||||
|
|
||||||
|
/** Constructs an instance for the specified device and swapchain. */
|
||||||
|
MVKPeerSwapchainImage(MVKDevice* device,
|
||||||
|
const VkImageCreateInfo* pCreateInfo,
|
||||||
|
MVKSwapchain* swapchain,
|
||||||
|
uint32_t swapchainIndex);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
id<CAMetalDrawable> getCAMetalDrawable() override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark MVKImageView
|
#pragma mark MVKImageView
|
||||||
|
|
||||||
|
@ -298,34 +298,6 @@ id<MTLTexture> MVKImage::getMTLTexture(MTLPixelFormat mtlPixFmt) {
|
|||||||
return mtlTex;
|
return mtlTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult MVKImage::setMTLTexture(id<MTLTexture> mtlTexture) {
|
|
||||||
lock_guard<mutex> lock(_lock);
|
|
||||||
resetMTLTexture();
|
|
||||||
resetIOSurface();
|
|
||||||
|
|
||||||
_mtlTexture = [mtlTexture retain]; // retained
|
|
||||||
|
|
||||||
_mtlPixelFormat = _mtlTexture.pixelFormat;
|
|
||||||
_mtlTextureType = _mtlTexture.textureType;
|
|
||||||
_extent.width = uint32_t(_mtlTexture.width);
|
|
||||||
_extent.height = uint32_t(_mtlTexture.height);
|
|
||||||
_extent.depth = uint32_t(_mtlTexture.depth);
|
|
||||||
_mipLevels = uint32_t(_mtlTexture.mipmapLevelCount);
|
|
||||||
_samples = mvkVkSampleCountFlagBitsFromSampleCount(_mtlTexture.sampleCount);
|
|
||||||
_arrayLayers = uint32_t(_mtlTexture.arrayLength);
|
|
||||||
_usage = getPixelFormats()->getVkImageUsageFlagsFromMTLTextureUsage(_mtlTexture.usage, _mtlPixelFormat);
|
|
||||||
|
|
||||||
if (_device->_pMetalFeatures->ioSurfaces) {
|
|
||||||
_ioSurface = mtlTexture.iosurface;
|
|
||||||
CFRetain(_ioSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return VK_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates and returns a retained Metal texture suitable for use in this instance.
|
|
||||||
// This implementation creates a new MTLTexture from a MTLTextureDescriptor and possible IOSurface.
|
|
||||||
// Subclasses may override this function to create the MTLTexture in a different manner.
|
|
||||||
id<MTLTexture> MVKImage::newMTLTexture() {
|
id<MTLTexture> MVKImage::newMTLTexture() {
|
||||||
id<MTLTexture> mtlTex = nil;
|
id<MTLTexture> mtlTex = nil;
|
||||||
MTLTextureDescriptor* mtlTexDesc = newMTLTextureDescriptor(); // temp retain
|
MTLTextureDescriptor* mtlTexDesc = newMTLTextureDescriptor(); // temp retain
|
||||||
@ -348,15 +320,41 @@ id<MTLTexture> MVKImage::newMTLTexture() {
|
|||||||
return mtlTex;
|
return mtlTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkResult MVKImage::setMTLTexture(id<MTLTexture> mtlTexture) {
|
||||||
|
lock_guard<mutex> lock(_lock);
|
||||||
|
|
||||||
|
releaseMTLTexture();
|
||||||
|
releaseIOSurface();
|
||||||
|
|
||||||
|
_mtlTexture = [mtlTexture retain]; // retained
|
||||||
|
|
||||||
|
_mtlPixelFormat = mtlTexture.pixelFormat;
|
||||||
|
_mtlTextureType = mtlTexture.textureType;
|
||||||
|
_extent.width = uint32_t(mtlTexture.width);
|
||||||
|
_extent.height = uint32_t(mtlTexture.height);
|
||||||
|
_extent.depth = uint32_t(mtlTexture.depth);
|
||||||
|
_mipLevels = uint32_t(mtlTexture.mipmapLevelCount);
|
||||||
|
_samples = mvkVkSampleCountFlagBitsFromSampleCount(mtlTexture.sampleCount);
|
||||||
|
_arrayLayers = uint32_t(mtlTexture.arrayLength);
|
||||||
|
_usage = getPixelFormats()->getVkImageUsageFlagsFromMTLTextureUsage(mtlTexture.usage, _mtlPixelFormat);
|
||||||
|
|
||||||
|
if (_device->_pMetalFeatures->ioSurfaces) {
|
||||||
|
_ioSurface = mtlTexture.iosurface;
|
||||||
|
CFRetain(_ioSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// Removes and releases the MTLTexture object, and all associated texture views
|
// Removes and releases the MTLTexture object, and all associated texture views
|
||||||
void MVKImage::resetMTLTexture() {
|
void MVKImage::releaseMTLTexture() {
|
||||||
[_mtlTexture release];
|
[_mtlTexture release];
|
||||||
_mtlTexture = nil;
|
_mtlTexture = nil;
|
||||||
for (auto elem : _mtlTextureViews) { [elem.second release]; }
|
for (auto elem : _mtlTextureViews) { [elem.second release]; }
|
||||||
_mtlTextureViews.clear();
|
_mtlTextureViews.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKImage::resetIOSurface() {
|
void MVKImage::releaseIOSurface() {
|
||||||
if (_ioSurface) {
|
if (_ioSurface) {
|
||||||
CFRelease(_ioSurface);
|
CFRelease(_ioSurface);
|
||||||
_ioSurface = nil;
|
_ioSurface = nil;
|
||||||
@ -372,8 +370,8 @@ VkResult MVKImage::useIOSurface(IOSurfaceRef ioSurface) {
|
|||||||
|
|
||||||
#if MVK_SUPPORT_IOSURFACE_BOOL
|
#if MVK_SUPPORT_IOSURFACE_BOOL
|
||||||
|
|
||||||
resetMTLTexture();
|
releaseMTLTexture();
|
||||||
resetIOSurface();
|
releaseIOSurface();
|
||||||
|
|
||||||
MVKPixelFormats* pixFmts = getPixelFormats();
|
MVKPixelFormats* pixFmts = getPixelFormats();
|
||||||
|
|
||||||
@ -788,8 +786,8 @@ void MVKImage::initSubresourceLayout(MVKImageSubresource& imgSubRez) {
|
|||||||
|
|
||||||
MVKImage::~MVKImage() {
|
MVKImage::~MVKImage() {
|
||||||
if (_deviceMemory) { _deviceMemory->removeImage(this); }
|
if (_deviceMemory) { _deviceMemory->removeImage(this); }
|
||||||
resetMTLTexture();
|
releaseMTLTexture();
|
||||||
resetIOSurface();
|
releaseIOSurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -800,37 +798,34 @@ VkResult MVKSwapchainImage::bindDeviceMemory(MVKDeviceMemory*, VkDeviceSize) {
|
|||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult MVKSwapchainImage::bindDeviceMemory2(const void* pBindInfo) {
|
|
||||||
const auto* imageInfo = (const VkBindImageMemoryInfo*)pBindInfo;
|
#pragma mark Metal
|
||||||
const VkBindImageMemorySwapchainInfoKHR* swapchainInfo = nullptr;
|
|
||||||
for (const auto* next = (const VkBaseInStructure*)imageInfo->pNext; next; next = next->pNext) {
|
// Overridden to always retrieve the MTLTexture directly from the CAMetalDrawable.
|
||||||
switch (next->sType) {
|
id<MTLTexture> MVKSwapchainImage::getMTLTexture() { return [getCAMetalDrawable() texture]; }
|
||||||
case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR:
|
|
||||||
swapchainInfo = (const VkBindImageMemorySwapchainInfoKHR*)next;
|
|
||||||
break;
|
#pragma mark Construction
|
||||||
default:
|
|
||||||
break;
|
MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
|
||||||
}
|
const VkImageCreateInfo* pCreateInfo,
|
||||||
if (swapchainInfo) { break; }
|
MVKSwapchain* swapchain,
|
||||||
}
|
uint32_t swapchainIndex) : MVKImage(device, pCreateInfo) {
|
||||||
if (!swapchainInfo) {
|
_swapchain = swapchain;
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
_swapchainIndex = swapchainIndex;
|
||||||
}
|
|
||||||
_swapchainIndex = swapchainInfo->imageIndex;
|
|
||||||
return VK_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark MVKPresentableSwapchainImage
|
||||||
|
|
||||||
bool MVKSwapchainImageAvailability::operator< (const MVKSwapchainImageAvailability& rhs) const {
|
bool MVKSwapchainImageAvailability::operator< (const MVKSwapchainImageAvailability& rhs) const {
|
||||||
if ( isAvailable && !rhs.isAvailable) { return true; }
|
if ( isAvailable && !rhs.isAvailable) { return true; }
|
||||||
if ( !isAvailable && rhs.isAvailable) { return false; }
|
if ( !isAvailable && rhs.isAvailable) { return false; }
|
||||||
|
|
||||||
if (waitCount < rhs.waitCount) { return true; }
|
|
||||||
if (waitCount > rhs.waitCount) { return false; }
|
|
||||||
|
|
||||||
return acquisitionID < rhs.acquisitionID;
|
return acquisitionID < rhs.acquisitionID;
|
||||||
}
|
}
|
||||||
|
|
||||||
MVKSwapchainImageAvailability MVKSwapchainImage::getAvailability() {
|
MVKSwapchainImageAvailability MVKPresentableSwapchainImage::getAvailability() {
|
||||||
lock_guard<mutex> lock(_availabilityLock);
|
lock_guard<mutex> lock(_availabilityLock);
|
||||||
|
|
||||||
return _availability;
|
return _availability;
|
||||||
@ -839,7 +834,7 @@ MVKSwapchainImageAvailability MVKSwapchainImage::getAvailability() {
|
|||||||
// Makes an image available for acquisition by the app.
|
// Makes an image available for acquisition by the app.
|
||||||
// If any semaphores are waiting to be signaled when this image becomes available, the
|
// 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.
|
// earliest semaphore is signaled, and this image remains unavailable for other uses.
|
||||||
void MVKSwapchainImage::makeAvailable() {
|
void MVKPresentableSwapchainImage::makeAvailable() {
|
||||||
lock_guard<mutex> lock(_availabilityLock);
|
lock_guard<mutex> lock(_availabilityLock);
|
||||||
|
|
||||||
// Mark when this event happened, relative to that of other images
|
// Mark when this event happened, relative to that of other images
|
||||||
@ -870,9 +865,13 @@ void MVKSwapchainImage::makeAvailable() {
|
|||||||
// MVKLogDebug("Signaling%s swapchain image %p semaphore %p from present, with %lu remaining semaphores.", (_availability.isAvailable ? " pre-signaled" : ""), this, signaler.first, _availabilitySignalers.size());
|
// MVKLogDebug("Signaling%s swapchain image %p semaphore %p from present, with %lu remaining semaphores.", (_availability.isAvailable ? " pre-signaled" : ""), this, signaler.first, _availabilitySignalers.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKSwapchainImage::signalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) {
|
void MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) {
|
||||||
lock_guard<mutex> lock(_availabilityLock);
|
lock_guard<mutex> lock(_availabilityLock);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
releaseMetalDrawable();
|
||||||
|
|
||||||
auto signaler = make_pair(semaphore, fence);
|
auto signaler = make_pair(semaphore, fence);
|
||||||
if (_availability.isAvailable) {
|
if (_availability.isAvailable) {
|
||||||
_availability.isAvailable = false;
|
_availability.isAvailable = false;
|
||||||
@ -899,7 +898,7 @@ void MVKSwapchainImage::signalWhenAvailable(MVKSemaphore* semaphore, MVKFence* f
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If present, signal the semaphore for the first waiter for the given image.
|
// If present, signal the semaphore for the first waiter for the given image.
|
||||||
void MVKSwapchainImage::signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdBuff) {
|
void MVKPresentableSwapchainImage::signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdBuff) {
|
||||||
lock_guard<mutex> lock(_availabilityLock);
|
lock_guard<mutex> lock(_availabilityLock);
|
||||||
|
|
||||||
if ( !_availabilitySignalers.empty() ) {
|
if ( !_availabilitySignalers.empty() ) {
|
||||||
@ -909,19 +908,19 @@ void MVKSwapchainImage::signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdB
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Signal either or both of the semaphore and fence in the specified tracker pair.
|
// Signal either or both of the semaphore and fence in the specified tracker pair.
|
||||||
void MVKSwapchainImage::signal(MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff) {
|
void MVKPresentableSwapchainImage::signal(MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff) {
|
||||||
if (signaler.first) { signaler.first->encodeSignal(mtlCmdBuff); }
|
if (signaler.first) { signaler.first->encodeSignal(mtlCmdBuff); }
|
||||||
if (signaler.second) { signaler.second->signal(); }
|
if (signaler.second) { signaler.second->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.
|
||||||
void MVKSwapchainImage::markAsTracked(MVKSwapchainSignaler& signaler) {
|
void MVKPresentableSwapchainImage::markAsTracked(MVKSwapchainSignaler& signaler) {
|
||||||
if (signaler.first) { signaler.first->retain(); }
|
if (signaler.first) { signaler.first->retain(); }
|
||||||
if (signaler.second) { signaler.second->retain(); }
|
if (signaler.second) { signaler.second->retain(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the semaphore and fence that they are no longer being tracked for future signaling.
|
// Tell the semaphore and fence that they are no longer being tracked for future signaling.
|
||||||
void MVKSwapchainImage::unmarkAsTracked(MVKSwapchainSignaler& signaler) {
|
void MVKPresentableSwapchainImage::unmarkAsTracked(MVKSwapchainSignaler& signaler) {
|
||||||
if (signaler.first) { signaler.first->release(); }
|
if (signaler.first) { signaler.first->release(); }
|
||||||
if (signaler.second) { signaler.second->release(); }
|
if (signaler.second) { signaler.second->release(); }
|
||||||
}
|
}
|
||||||
@ -929,19 +928,13 @@ void MVKSwapchainImage::unmarkAsTracked(MVKSwapchainSignaler& signaler) {
|
|||||||
|
|
||||||
#pragma mark Metal
|
#pragma mark Metal
|
||||||
|
|
||||||
// Creates and returns a retained Metal texture suitable for use in this instance.
|
id<CAMetalDrawable> MVKPresentableSwapchainImage::getCAMetalDrawable() {
|
||||||
// This implementation retrieves a MTLTexture from the CAMetalDrawable.
|
|
||||||
id<MTLTexture> MVKSwapchainImage::newMTLTexture() {
|
|
||||||
return [[getCAMetalDrawable() texture] retain];
|
|
||||||
}
|
|
||||||
|
|
||||||
id<CAMetalDrawable> MVKSwapchainImage::getCAMetalDrawable() {
|
|
||||||
while ( !_mtlDrawable ) {
|
while ( !_mtlDrawable ) {
|
||||||
@autoreleasepool { // Reclaim auto-released drawable object before end of loop
|
@autoreleasepool { // Reclaim auto-released drawable object before end of loop
|
||||||
uint64_t startTime = _device->getPerformanceTimestamp();
|
uint64_t startTime = _device->getPerformanceTimestamp();
|
||||||
|
|
||||||
_mtlDrawable = [_swapchain->_mtlLayer.nextDrawable retain];
|
_mtlDrawable = [_swapchain->_mtlLayer.nextDrawable retain];
|
||||||
if ( !_mtlDrawable ) { MVKLogError("CAMetalDrawable could not be acquired after %.6f ms.", mvkGetElapsedMilliseconds(startTime)); }
|
if ( !_mtlDrawable ) { MVKLogError("CAMetalDrawable could not be acquired."); }
|
||||||
|
|
||||||
_device->addActivityPerformance(_device->_performanceStatistics.queue.nextCAMetalDrawable, startTime);
|
_device->addActivityPerformance(_device->_performanceStatistics.queue.nextCAMetalDrawable, startTime);
|
||||||
}
|
}
|
||||||
@ -950,7 +943,7 @@ id<CAMetalDrawable> MVKSwapchainImage::getCAMetalDrawable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
void MVKSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff) {
|
void MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff) {
|
||||||
_swapchain->willPresentSurface(getMTLTexture(), mtlCmdBuff);
|
_swapchain->willPresentSurface(getMTLTexture(), mtlCmdBuff);
|
||||||
|
|
||||||
NSString* scName = _swapchain->getDebugName();
|
NSString* scName = _swapchain->getDebugName();
|
||||||
@ -968,8 +961,8 @@ void MVKSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resets the MTLTexture and CAMetalDrawable underlying this image.
|
// Resets the MTLTexture and CAMetalDrawable underlying this image.
|
||||||
void MVKSwapchainImage::resetMetalDrawable() {
|
void MVKPresentableSwapchainImage::releaseMetalDrawable() {
|
||||||
resetMTLTexture(); // Release texture first so drawable will be last to release it
|
releaseMTLTexture(); // Release texture first so drawable will be last to release it
|
||||||
[_mtlDrawable release];
|
[_mtlDrawable release];
|
||||||
_mtlDrawable = nil;
|
_mtlDrawable = nil;
|
||||||
}
|
}
|
||||||
@ -977,12 +970,12 @@ void MVKSwapchainImage::resetMetalDrawable() {
|
|||||||
|
|
||||||
#pragma mark Construction
|
#pragma mark Construction
|
||||||
|
|
||||||
MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
|
MVKPresentableSwapchainImage::MVKPresentableSwapchainImage(MVKDevice* device,
|
||||||
const VkImageCreateInfo* pCreateInfo,
|
const VkImageCreateInfo* pCreateInfo,
|
||||||
MVKSwapchain* swapchain,
|
MVKSwapchain* swapchain,
|
||||||
uint32_t swapchainIndex) : MVKImage(device, pCreateInfo) {
|
uint32_t swapchainIndex) :
|
||||||
_swapchain = swapchain;
|
MVKSwapchainImage(device, pCreateInfo, swapchain, swapchainIndex) {
|
||||||
_swapchainIndex = swapchainIndex;
|
|
||||||
_mtlDrawable = nil;
|
_mtlDrawable = nil;
|
||||||
|
|
||||||
_availability.acquisitionID = _swapchain->getNextAcquisitionID();
|
_availability.acquisitionID = _swapchain->getNextAcquisitionID();
|
||||||
@ -990,11 +983,52 @@ MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
|
|||||||
_preSignaler = make_pair(nullptr, nullptr);
|
_preSignaler = make_pair(nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
MVKSwapchainImage::~MVKSwapchainImage() {
|
MVKPresentableSwapchainImage::~MVKPresentableSwapchainImage() {
|
||||||
resetMetalDrawable();
|
releaseMetalDrawable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark MVKPeerSwapchainImage
|
||||||
|
|
||||||
|
VkResult MVKPeerSwapchainImage::bindDeviceMemory2(const void* pBindInfo) {
|
||||||
|
const auto* imageInfo = (const VkBindImageMemoryInfo*)pBindInfo;
|
||||||
|
const VkBindImageMemorySwapchainInfoKHR* swapchainInfo = nullptr;
|
||||||
|
for (const auto* next = (const VkBaseInStructure*)imageInfo->pNext; next; next = next->pNext) {
|
||||||
|
switch (next->sType) {
|
||||||
|
case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR:
|
||||||
|
swapchainInfo = (const VkBindImageMemorySwapchainInfoKHR*)next;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (swapchainInfo) { break; }
|
||||||
|
}
|
||||||
|
if (!swapchainInfo) {
|
||||||
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
|
}
|
||||||
|
_swapchainIndex = swapchainInfo->imageIndex;
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Metal
|
||||||
|
|
||||||
|
id<CAMetalDrawable> MVKPeerSwapchainImage::getCAMetalDrawable() {
|
||||||
|
return ((MVKSwapchainImage*)_swapchain->getPresentableImage(_swapchainIndex))->getCAMetalDrawable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Construction
|
||||||
|
|
||||||
|
MVKPeerSwapchainImage::MVKPeerSwapchainImage(MVKDevice* device,
|
||||||
|
const VkImageCreateInfo* pCreateInfo,
|
||||||
|
MVKSwapchain* swapchain,
|
||||||
|
uint32_t swapchainIndex) :
|
||||||
|
MVKSwapchainImage(device, pCreateInfo, swapchain, swapchainIndex) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark MVKImageView
|
#pragma mark MVKImageView
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ static NSArray<id<MTLDevice>>* availableMTLDevicesArray() {
|
|||||||
#if MVK_MACOS
|
#if MVK_MACOS
|
||||||
NSArray* rawMTLDevs = [MTLCopyAllDevices() autorelease];
|
NSArray* rawMTLDevs = [MTLCopyAllDevices() autorelease];
|
||||||
if (rawMTLDevs) {
|
if (rawMTLDevs) {
|
||||||
bool forceLowPower = MVK_CONFIG_FORCE_LOW_POWER_GPU;
|
bool forceLowPower;
|
||||||
MVK_SET_FROM_ENV_OR_BUILD_BOOL(forceLowPower, MVK_CONFIG_FORCE_LOW_POWER_GPU);
|
MVK_SET_FROM_ENV_OR_BUILD_BOOL(forceLowPower, MVK_CONFIG_FORCE_LOW_POWER_GPU);
|
||||||
|
|
||||||
// Populate the array of appropriate MTLDevices
|
// Populate the array of appropriate MTLDevices
|
||||||
|
@ -228,6 +228,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
id<MTLCommandBuffer> getMTLCommandBuffer();
|
id<MTLCommandBuffer> getMTLCommandBuffer();
|
||||||
|
|
||||||
MVKVectorInline<MVKSwapchainImage*, 4> _surfaceImages;
|
MVKVectorInline<MVKPresentableSwapchainImage*, 4> _presentableImages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ void MVKQueuePresentSurfaceSubmission::execute() {
|
|||||||
// The semaphores know what to do.
|
// The semaphores know what to do.
|
||||||
id<MTLCommandBuffer> mtlCmdBuff = getMTLCommandBuffer();
|
id<MTLCommandBuffer> mtlCmdBuff = getMTLCommandBuffer();
|
||||||
for (auto& ws : _waitSemaphores) { ws->encodeWait(mtlCmdBuff); }
|
for (auto& ws : _waitSemaphores) { ws->encodeWait(mtlCmdBuff); }
|
||||||
for (auto& si : _surfaceImages) { si->presentCAMetalDrawable(mtlCmdBuff); }
|
for (auto& img : _presentableImages) { img->presentCAMetalDrawable(mtlCmdBuff); }
|
||||||
for (auto& ws : _waitSemaphores) { ws->encodeWait(nil); }
|
for (auto& ws : _waitSemaphores) { ws->encodeWait(nil); }
|
||||||
[mtlCmdBuff commit];
|
[mtlCmdBuff commit];
|
||||||
|
|
||||||
@ -363,10 +363,10 @@ MVKQueuePresentSurfaceSubmission::MVKQueuePresentSurfaceSubmission(MVKQueue* que
|
|||||||
: MVKQueueSubmission(queue, pPresentInfo->waitSemaphoreCount, pPresentInfo->pWaitSemaphores) {
|
: MVKQueueSubmission(queue, pPresentInfo->waitSemaphoreCount, pPresentInfo->pWaitSemaphores) {
|
||||||
|
|
||||||
// Populate the array of swapchain images, testing each one for a change in surface size
|
// Populate the array of swapchain images, testing each one for a change in surface size
|
||||||
_surfaceImages.reserve(pPresentInfo->swapchainCount);
|
_presentableImages.reserve(pPresentInfo->swapchainCount);
|
||||||
for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
|
for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
|
||||||
MVKSwapchain* mvkSC = (MVKSwapchain*)pPresentInfo->pSwapchains[i];
|
MVKSwapchain* mvkSC = (MVKSwapchain*)pPresentInfo->pSwapchains[i];
|
||||||
_surfaceImages.push_back(mvkSC->getImage(pPresentInfo->pImageIndices[i]));
|
_presentableImages.push_back(mvkSC->getPresentableImage(pPresentInfo->pImageIndices[i]));
|
||||||
// Surface loss takes precedence over out-of-date errors.
|
// Surface loss takes precedence over out-of-date errors.
|
||||||
if (mvkSC->getIsSurfaceLost()) {
|
if (mvkSC->getIsSurfaceLost()) {
|
||||||
setConfigurationResult(VK_ERROR_SURFACE_LOST_KHR);
|
setConfigurationResult(VK_ERROR_SURFACE_LOST_KHR);
|
||||||
|
@ -42,10 +42,10 @@ public:
|
|||||||
VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT; }
|
VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT; }
|
||||||
|
|
||||||
/** Returns the number of images in this swapchain. */
|
/** Returns the number of images in this swapchain. */
|
||||||
inline uint32_t getImageCount() { return (uint32_t)_surfaceImages.size(); }
|
inline uint32_t getImageCount() { return (uint32_t)_presentableImages.size(); }
|
||||||
|
|
||||||
/** Returns the image at the specified index. */
|
/** Returns the image at the specified index. */
|
||||||
inline MVKSwapchainImage* getImage(uint32_t index) { return _surfaceImages[index]; }
|
inline MVKPresentableSwapchainImage* getPresentableImage(uint32_t index) { return _presentableImages[index]; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the array of presentable images associated with this swapchain.
|
* Returns the array of presentable images associated with this swapchain.
|
||||||
@ -89,7 +89,7 @@ public:
|
|||||||
~MVKSwapchain() override;
|
~MVKSwapchain() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class MVKSwapchainImage;
|
friend class MVKPresentableSwapchainImage;
|
||||||
|
|
||||||
void propogateDebugName() override;
|
void propogateDebugName() override;
|
||||||
void initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt);
|
void initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt);
|
||||||
@ -103,7 +103,7 @@ protected:
|
|||||||
|
|
||||||
CAMetalLayer* _mtlLayer;
|
CAMetalLayer* _mtlLayer;
|
||||||
MVKWatermark* _licenseWatermark;
|
MVKWatermark* _licenseWatermark;
|
||||||
MVKVectorInline<MVKSwapchainImage*, kMVKMaxSwapchainImageCount> _surfaceImages;
|
MVKVectorInline<MVKPresentableSwapchainImage*, kMVKMaxSwapchainImageCount> _presentableImages;
|
||||||
std::atomic<uint64_t> _currentAcquisitionID;
|
std::atomic<uint64_t> _currentAcquisitionID;
|
||||||
CGSize _mtlLayerOrigDrawSize;
|
CGSize _mtlLayerOrigDrawSize;
|
||||||
MVKSwapchainPerformance _performanceStatistics;
|
MVKSwapchainPerformance _performanceStatistics;
|
||||||
|
@ -40,10 +40,10 @@ using namespace std;
|
|||||||
|
|
||||||
void MVKSwapchain::propogateDebugName() {
|
void MVKSwapchain::propogateDebugName() {
|
||||||
if (_debugName) {
|
if (_debugName) {
|
||||||
size_t imgCnt = _surfaceImages.size();
|
size_t imgCnt = _presentableImages.size();
|
||||||
for (size_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
|
for (size_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
|
||||||
NSString* nsName = [[NSString alloc] initWithFormat: @"%@(%lu)", _debugName, imgIdx]; // temp retain
|
NSString* nsName = [[NSString alloc] initWithFormat: @"%@(%lu)", _debugName, imgIdx]; // temp retain
|
||||||
_surfaceImages[imgIdx]->setDebugName(nsName.UTF8String);
|
_presentableImages[imgIdx]->setDebugName(nsName.UTF8String);
|
||||||
[nsName release]; // release temp string
|
[nsName release]; // release temp string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ VkResult MVKSwapchain::getImages(uint32_t* pCount, VkImage* pSwapchainImages) {
|
|||||||
|
|
||||||
// Now populate the images
|
// Now populate the images
|
||||||
for (uint32_t imgIdx = 0; imgIdx < *pCount; imgIdx++) {
|
for (uint32_t imgIdx = 0; imgIdx < *pCount; imgIdx++) {
|
||||||
pSwapchainImages[imgIdx] = (VkImage)_surfaceImages[imgIdx];
|
pSwapchainImages[imgIdx] = (VkImage)_presentableImages[imgIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -80,14 +80,12 @@ VkResult MVKSwapchain::acquireNextImageKHR(uint64_t timeout,
|
|||||||
|
|
||||||
if ( getIsSurfaceLost() ) { return VK_ERROR_SURFACE_LOST_KHR; }
|
if ( getIsSurfaceLost() ) { return VK_ERROR_SURFACE_LOST_KHR; }
|
||||||
|
|
||||||
// Find the image that has the smallest availability measure
|
// Find the image that has the shortest wait by finding the smallest availability measure.
|
||||||
MVKSwapchainImage* minWaitImage = nullptr;
|
MVKPresentableSwapchainImage* minWaitImage = nullptr;
|
||||||
MVKSwapchainImageAvailability minAvailability = { .acquisitionID = kMVKUndefinedLargeUInt64,
|
MVKSwapchainImageAvailability minAvailability = { kMVKUndefinedLargeUInt64, false };
|
||||||
.waitCount = kMVKUndefinedLargeUInt32,
|
|
||||||
.isAvailable = false };
|
|
||||||
uint32_t imgCnt = getImageCount();
|
uint32_t imgCnt = getImageCount();
|
||||||
for (uint32_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
|
for (uint32_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
|
||||||
MVKSwapchainImage* img = getImage(imgIdx);
|
auto* img = getPresentableImage(imgIdx);
|
||||||
auto imgAvail = img->getAvailability();
|
auto imgAvail = img->getAvailability();
|
||||||
if (imgAvail < minAvailability) {
|
if (imgAvail < minAvailability) {
|
||||||
minAvailability = imgAvail;
|
minAvailability = imgAvail;
|
||||||
@ -95,10 +93,10 @@ VkResult MVKSwapchain::acquireNextImageKHR(uint64_t timeout,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the index of the image with the shortest wait and signal the semaphore and fence when it's available
|
// Return the index of the image with the shortest wait,
|
||||||
|
// and signal the semaphore and fence when it's available
|
||||||
*pImageIndex = minWaitImage->_swapchainIndex;
|
*pImageIndex = minWaitImage->_swapchainIndex;
|
||||||
minWaitImage->resetMetalDrawable();
|
minWaitImage->acquireAndSignalWhenAvailable((MVKSemaphore*)semaphore, (MVKFence*)fence);
|
||||||
minWaitImage->signalWhenAvailable((MVKSemaphore*)semaphore, (MVKFence*)fence);
|
|
||||||
|
|
||||||
return getHasSurfaceSizeChanged() ? VK_ERROR_OUT_OF_DATE_KHR : VK_SUCCESS;
|
return getHasSurfaceSizeChanged() ? VK_ERROR_OUT_OF_DATE_KHR : VK_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -384,7 +382,7 @@ void MVKSwapchain::initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
|
for (uint32_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
|
||||||
_surfaceImages.push_back(_device->createSwapchainImage(&imgInfo, this, imgIdx, NULL));
|
_presentableImages.push_back(_device->createPresentableSwapchainImage(&imgInfo, this, imgIdx, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
MVKLogInfo("Created %d swapchain images with initial size (%d, %d).", imgCnt, imgExtent.width, imgExtent.height);
|
MVKLogInfo("Created %d swapchain images with initial size (%d, %d).", imgCnt, imgExtent.width, imgExtent.height);
|
||||||
@ -405,7 +403,7 @@ void MVKSwapchain::initFrameIntervalTracking() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MVKSwapchain::~MVKSwapchain() {
|
MVKSwapchain::~MVKSwapchain() {
|
||||||
for (auto& img : _surfaceImages) { _device->destroySwapchainImage(img, NULL); }
|
for (auto& img : _presentableImages) { _device->destroyPresentableSwapchainImage(img, NULL); }
|
||||||
|
|
||||||
if (_licenseWatermark) { _licenseWatermark->destroy(); }
|
if (_licenseWatermark) { _licenseWatermark->destroy(); }
|
||||||
[this->_layerObserver release];
|
[this->_layerObserver release];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user