Merge pull request #852 from billhollings/master

Various fixes resulting from testing for SDK release.
This commit is contained in:
Bill Hollings 2020-04-05 21:30:02 -04:00 committed by GitHub
commit 1a25de5500
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 265 additions and 161 deletions

View File

@ -7,9 +7,6 @@
<Group
location = "container:"
name = "LunarG-VulkanSamples">
<FileRef
location = "group:LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj">
</FileRef>
<FileRef
location = "group:LunarG-VulkanSamples/Cube/Cube.xcodeproj">
</FileRef>

View File

@ -64,7 +64,12 @@ as a system library instead.
<a name="lunarg-vulkan-samples-api"></a>
### *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.
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
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.
> 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.**
@ -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>
### *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.
This is a sophisticated particle demo that populates command buffers from multiple threads.

View File

@ -32,11 +32,13 @@ Released 2020/04/05
- Fix issue causing screen captures from swapchain image to deadlock.
- Fix memory estimates for iOS 13+.
- 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
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
**MoltenVK** is not a fully-compliant implementation of *Vulkan*.
- 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 to latest SPIRV-Cross version:
- MSL: Support inline uniform blocks in argument buffers.

View File

@ -503,8 +503,6 @@
A94FB7841C7DFB4800632CA3 /* MVKDevice.mm */,
A94FB7851C7DFB4800632CA3 /* MVKDeviceMemory.h */,
A94FB7861C7DFB4800632CA3 /* MVKDeviceMemory.mm */,
A9653FB724129C84005999D7 /* MVKPixelFormats.h */,
A9653FB924129C84005999D7 /* MVKPixelFormats.mm */,
A94FB7871C7DFB4800632CA3 /* MVKFramebuffer.h */,
A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */,
A94FB7891C7DFB4800632CA3 /* MVKImage.h */,
@ -513,6 +511,8 @@
A94FB78C1C7DFB4800632CA3 /* MVKInstance.mm */,
A94FB78D1C7DFB4800632CA3 /* MVKPipeline.h */,
A94FB78E1C7DFB4800632CA3 /* MVKPipeline.mm */,
A9653FB724129C84005999D7 /* MVKPixelFormats.h */,
A9653FB924129C84005999D7 /* MVKPixelFormats.mm */,
A94FB78F1C7DFB4800632CA3 /* MVKQueryPool.h */,
A94FB7901C7DFB4800632CA3 /* MVKQueryPool.mm */,
A94FB7911C7DFB4800632CA3 /* MVKQueue.h */,

View File

@ -163,6 +163,18 @@ typedef unsigned long MTLLanguageVersion;
* 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()
* 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 {

View File

@ -42,7 +42,7 @@ class MVKResource;
class MVKBuffer;
class MVKBufferView;
class MVKImage;
class MVKSwapchainImage;
class MVKPresentableSwapchainImage;
class MVKImageView;
class MVKSwapchain;
class MVKDeviceMemory;
@ -450,12 +450,12 @@ public:
void destroySwapchain(MVKSwapchain* mvkSwpChn,
const VkAllocationCallbacks* pAllocator);
MVKSwapchainImage* createSwapchainImage(const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex,
const VkAllocationCallbacks* pAllocator);
void destroySwapchainImage(MVKSwapchainImage* mvkImg,
const VkAllocationCallbacks* pAllocator);
MVKPresentableSwapchainImage* createPresentableSwapchainImage(const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex,
const VkAllocationCallbacks* pAllocator);
void destroyPresentableSwapchainImage(MVKPresentableSwapchainImage* mvkImg,
const VkAllocationCallbacks* pAllocator);
MVKFence* createFence(const VkFenceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator);

View File

@ -773,7 +773,15 @@ MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtl
// Initializes the Metal-specific physical device features of this instance.
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.maxMTLBufferSize = (256 * MEBI);
@ -848,7 +856,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
if ( mvkOSVersionIsAtLeast(13.0) ) {
_metalFeatures.mslVersionEnum = MTLLanguageVersion2_2;
_metalFeatures.placementHeaps = true;
_metalFeatures.placementHeaps = useMTLHeaps;
if (supportsMTLGPUFamily(Apple4)) {
_metalFeatures.nativeTextureSwizzle = true;
}
@ -904,7 +912,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
_metalFeatures.native3DCompressedTextures = true;
if (supportsMTLGPUFamily(Mac2)) {
_metalFeatures.nativeTextureSwizzle = true;
_metalFeatures.placementHeaps = true;
_metalFeatures.placementHeaps = useMTLHeaps;
}
}
@ -957,7 +965,6 @@ void MVKPhysicalDevice::initMetalFeatures() {
break;
#endif
}
}
// Initializes the physical device features of this instance.
@ -2131,7 +2138,7 @@ MVKImage* MVKDevice::createImage(const VkImageCreateInfo* pCreateInfo,
}
}
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));
}
@ -2162,15 +2169,15 @@ void MVKDevice::destroySwapchain(MVKSwapchain* mvkSwpChn,
mvkSwpChn->destroy();
}
MVKSwapchainImage* MVKDevice::createSwapchainImage(const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex,
const VkAllocationCallbacks* pAllocator) {
return (MVKSwapchainImage*)addResource(new MVKSwapchainImage(this, pCreateInfo, swapchain, swapchainIndex));
MVKPresentableSwapchainImage* MVKDevice::createPresentableSwapchainImage(const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex,
const VkAllocationCallbacks* pAllocator) {
return (MVKPresentableSwapchainImage*)addResource(new MVKPresentableSwapchainImage(this, pCreateInfo, swapchain, swapchainIndex));
}
void MVKDevice::destroySwapchainImage(MVKSwapchainImage* mvkImg,
const VkAllocationCallbacks* pAllocator) {
void MVKDevice::destroyPresentableSwapchainImage(MVKPresentableSwapchainImage* mvkImg,
const VkAllocationCallbacks* pAllocator) {
removeResource(mvkImg);
mvkImg->destroy();
}
@ -2656,10 +2663,9 @@ void MVKDevice::initPhysicalDevice(MVKPhysicalDevice* physicalDevice, const VkDe
}
MVKLogInfo("Using %s for Vulkan semaphores.", _useMTLFenceForSemaphores ? "MTLFence" : (_useMTLEventForSemaphores ? "MTLEvent" : "emulation"));
#ifndef MVK_CONFIG_USE_COMMAND_POOLING
# define MVK_CONFIG_USE_COMMAND_POOLING 1
#endif
_useCommandPooling = MVK_CONFIG_USE_COMMAND_POOLING;
# ifndef MVK_CONFIG_USE_COMMAND_POOLING
# define MVK_CONFIG_USE_COMMAND_POOLING 1
# endif
MVK_SET_FROM_ENV_OR_BUILD_BOOL(_useCommandPooling, MVK_CONFIG_USE_COMMAND_POOLING);
#if MVK_MACOS

View File

@ -147,7 +147,7 @@ public:
#pragma mark Metal
/** 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. */
id<MTLTexture> getMTLTexture(MTLPixelFormat mtlPixFmt);
@ -235,9 +235,9 @@ protected:
bool validateUseTexelBuffer();
void initSubresources(const VkImageCreateInfo* pCreateInfo);
void initSubresourceLayout(MVKImageSubresource& imgSubRez);
virtual id<MTLTexture> newMTLTexture();
void resetMTLTexture();
void resetIOSurface();
id<MTLTexture> newMTLTexture();
void releaseMTLTexture();
void releaseIOSurface();
MTLTextureDescriptor* newMTLTextureDescriptor();
void updateMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
void getMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
@ -274,10 +274,44 @@ protected:
#pragma mark -
#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. */
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. */
uint32_t waitCount; /**< The number of semaphores already waiting for this image. */
bool isAvailable; /**< Indicates whether this image is currently available. */
bool operator< (const MVKSwapchainImageAvailability& rhs) const;
@ -287,18 +321,11 @@ typedef struct MVKSwapchainImageAvailability {
typedef std::pair<MVKSemaphore*, MVKFence*> MVKSwapchainSignaler;
/** Represents a Vulkan image used as a rendering destination within a swapchain. */
class MVKSwapchainImage : public MVKImage {
/** Represents a Vulkan swapchain image that can be submitted to the presentation engine. */
class MVKPresentableSwapchainImage : public MVKSwapchainImage {
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
/**
@ -315,30 +342,27 @@ public:
#pragma mark Construction
/** Constructs an instance for the specified device and swapchain. */
MVKSwapchainImage(MVKDevice* device,
const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex);
MVKPresentableSwapchainImage(MVKDevice* device,
const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex);
~MVKSwapchainImage() override;
~MVKPresentableSwapchainImage() override;
protected:
friend MVKSwapchain;
id<MTLTexture> newMTLTexture() override;
id<CAMetalDrawable> getCAMetalDrawable();
void resetMetalDrawable();
id<CAMetalDrawable> getCAMetalDrawable() override;
void releaseMetalDrawable();
MVKSwapchainImageAvailability getAvailability();
void makeAvailable();
void signalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence);
void acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence);
void signal(MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff);
void signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdBuff);
static void markAsTracked(MVKSwapchainSignaler& signaler);
static void unmarkAsTracked(MVKSwapchainSignaler& signaler);
void renderWatermark(id<MTLCommandBuffer> mtlCmdBuff);
MVKSwapchain* _swapchain;
uint32_t _swapchainIndex;
id<CAMetalDrawable> _mtlDrawable;
MVKSwapchainImageAvailability _availability;
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 MVKImageView

View File

@ -298,34 +298,6 @@ id<MTLTexture> MVKImage::getMTLTexture(MTLPixelFormat mtlPixFmt) {
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> mtlTex = nil;
MTLTextureDescriptor* mtlTexDesc = newMTLTextureDescriptor(); // temp retain
@ -348,15 +320,41 @@ id<MTLTexture> MVKImage::newMTLTexture() {
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
void MVKImage::resetMTLTexture() {
void MVKImage::releaseMTLTexture() {
[_mtlTexture release];
_mtlTexture = nil;
for (auto elem : _mtlTextureViews) { [elem.second release]; }
_mtlTextureViews.clear();
}
void MVKImage::resetIOSurface() {
void MVKImage::releaseIOSurface() {
if (_ioSurface) {
CFRelease(_ioSurface);
_ioSurface = nil;
@ -372,8 +370,8 @@ VkResult MVKImage::useIOSurface(IOSurfaceRef ioSurface) {
#if MVK_SUPPORT_IOSURFACE_BOOL
resetMTLTexture();
resetIOSurface();
releaseMTLTexture();
releaseIOSurface();
MVKPixelFormats* pixFmts = getPixelFormats();
@ -788,8 +786,8 @@ void MVKImage::initSubresourceLayout(MVKImageSubresource& imgSubRez) {
MVKImage::~MVKImage() {
if (_deviceMemory) { _deviceMemory->removeImage(this); }
resetMTLTexture();
resetIOSurface();
releaseMTLTexture();
releaseIOSurface();
}
@ -800,37 +798,34 @@ VkResult MVKSwapchainImage::bindDeviceMemory(MVKDeviceMemory*, VkDeviceSize) {
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
VkResult MVKSwapchainImage::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
// Overridden to always retrieve the MTLTexture directly from the CAMetalDrawable.
id<MTLTexture> MVKSwapchainImage::getMTLTexture() { return [getCAMetalDrawable() texture]; }
#pragma mark Construction
MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex) : MVKImage(device, pCreateInfo) {
_swapchain = swapchain;
_swapchainIndex = swapchainIndex;
}
#pragma mark -
#pragma mark MVKPresentableSwapchainImage
bool MVKSwapchainImageAvailability::operator< (const MVKSwapchainImageAvailability& rhs) const {
if ( isAvailable && !rhs.isAvailable) { return true; }
if ( !isAvailable && rhs.isAvailable) { return false; }
if (waitCount < rhs.waitCount) { return true; }
if (waitCount > rhs.waitCount) { return false; }
return acquisitionID < rhs.acquisitionID;
}
MVKSwapchainImageAvailability MVKSwapchainImage::getAvailability() {
MVKSwapchainImageAvailability MVKPresentableSwapchainImage::getAvailability() {
lock_guard<mutex> lock(_availabilityLock);
return _availability;
@ -839,7 +834,7 @@ MVKSwapchainImageAvailability MVKSwapchainImage::getAvailability() {
// 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 MVKSwapchainImage::makeAvailable() {
void MVKPresentableSwapchainImage::makeAvailable() {
lock_guard<mutex> lock(_availabilityLock);
// 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());
}
void MVKSwapchainImage::signalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) {
void MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) {
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);
if (_availability.isAvailable) {
_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.
void MVKSwapchainImage::signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdBuff) {
void MVKPresentableSwapchainImage::signalPresentationSemaphore(id<MTLCommandBuffer> mtlCmdBuff) {
lock_guard<mutex> lock(_availabilityLock);
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.
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.second) { signaler.second->signal(); }
}
// 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.second) { signaler.second->retain(); }
}
// 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.second) { signaler.second->release(); }
}
@ -929,19 +928,13 @@ void MVKSwapchainImage::unmarkAsTracked(MVKSwapchainSignaler& signaler) {
#pragma mark Metal
// Creates and returns a retained Metal texture suitable for use in this instance.
// This implementation retrieves a MTLTexture from the CAMetalDrawable.
id<MTLTexture> MVKSwapchainImage::newMTLTexture() {
return [[getCAMetalDrawable() texture] retain];
}
id<CAMetalDrawable> MVKSwapchainImage::getCAMetalDrawable() {
id<CAMetalDrawable> MVKPresentableSwapchainImage::getCAMetalDrawable() {
while ( !_mtlDrawable ) {
@autoreleasepool { // Reclaim auto-released drawable object before end of loop
uint64_t startTime = _device->getPerformanceTimestamp();
_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);
}
@ -950,7 +943,7 @@ id<CAMetalDrawable> MVKSwapchainImage::getCAMetalDrawable() {
}
// 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);
NSString* scName = _swapchain->getDebugName();
@ -968,8 +961,8 @@ void MVKSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff)
}
// Resets the MTLTexture and CAMetalDrawable underlying this image.
void MVKSwapchainImage::resetMetalDrawable() {
resetMTLTexture(); // Release texture first so drawable will be last to release it
void MVKPresentableSwapchainImage::releaseMetalDrawable() {
releaseMTLTexture(); // Release texture first so drawable will be last to release it
[_mtlDrawable release];
_mtlDrawable = nil;
}
@ -977,12 +970,12 @@ void MVKSwapchainImage::resetMetalDrawable() {
#pragma mark Construction
MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex) : MVKImage(device, pCreateInfo) {
_swapchain = swapchain;
_swapchainIndex = swapchainIndex;
MVKPresentableSwapchainImage::MVKPresentableSwapchainImage(MVKDevice* device,
const VkImageCreateInfo* pCreateInfo,
MVKSwapchain* swapchain,
uint32_t swapchainIndex) :
MVKSwapchainImage(device, pCreateInfo, swapchain, swapchainIndex) {
_mtlDrawable = nil;
_availability.acquisitionID = _swapchain->getNextAcquisitionID();
@ -990,11 +983,52 @@ MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
_preSignaler = make_pair(nullptr, nullptr);
}
MVKSwapchainImage::~MVKSwapchainImage() {
resetMetalDrawable();
MVKPresentableSwapchainImage::~MVKPresentableSwapchainImage() {
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 MVKImageView

View File

@ -289,7 +289,7 @@ static NSArray<id<MTLDevice>>* availableMTLDevicesArray() {
#if MVK_MACOS
NSArray* rawMTLDevs = [MTLCopyAllDevices() autorelease];
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);
// Populate the array of appropriate MTLDevices

View File

@ -228,6 +228,6 @@ public:
protected:
id<MTLCommandBuffer> getMTLCommandBuffer();
MVKVectorInline<MVKSwapchainImage*, 4> _surfaceImages;
MVKVectorInline<MVKPresentableSwapchainImage*, 4> _presentableImages;
};

View File

@ -339,7 +339,7 @@ void MVKQueuePresentSurfaceSubmission::execute() {
// The semaphores know what to do.
id<MTLCommandBuffer> mtlCmdBuff = getMTLCommandBuffer();
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); }
[mtlCmdBuff commit];
@ -363,10 +363,10 @@ MVKQueuePresentSurfaceSubmission::MVKQueuePresentSurfaceSubmission(MVKQueue* que
: MVKQueueSubmission(queue, pPresentInfo->waitSemaphoreCount, pPresentInfo->pWaitSemaphores) {
// 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++) {
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.
if (mvkSC->getIsSurfaceLost()) {
setConfigurationResult(VK_ERROR_SURFACE_LOST_KHR);

View File

@ -42,10 +42,10 @@ public:
VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT; }
/** 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. */
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.
@ -89,7 +89,7 @@ public:
~MVKSwapchain() override;
protected:
friend class MVKSwapchainImage;
friend class MVKPresentableSwapchainImage;
void propogateDebugName() override;
void initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt);
@ -103,7 +103,7 @@ protected:
CAMetalLayer* _mtlLayer;
MVKWatermark* _licenseWatermark;
MVKVectorInline<MVKSwapchainImage*, kMVKMaxSwapchainImageCount> _surfaceImages;
MVKVectorInline<MVKPresentableSwapchainImage*, kMVKMaxSwapchainImageCount> _presentableImages;
std::atomic<uint64_t> _currentAcquisitionID;
CGSize _mtlLayerOrigDrawSize;
MVKSwapchainPerformance _performanceStatistics;

View File

@ -40,10 +40,10 @@ using namespace std;
void MVKSwapchain::propogateDebugName() {
if (_debugName) {
size_t imgCnt = _surfaceImages.size();
size_t imgCnt = _presentableImages.size();
for (size_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
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
}
}
@ -66,7 +66,7 @@ VkResult MVKSwapchain::getImages(uint32_t* pCount, VkImage* pSwapchainImages) {
// Now populate the images
for (uint32_t imgIdx = 0; imgIdx < *pCount; imgIdx++) {
pSwapchainImages[imgIdx] = (VkImage)_surfaceImages[imgIdx];
pSwapchainImages[imgIdx] = (VkImage)_presentableImages[imgIdx];
}
return result;
@ -80,14 +80,12 @@ VkResult MVKSwapchain::acquireNextImageKHR(uint64_t timeout,
if ( getIsSurfaceLost() ) { return VK_ERROR_SURFACE_LOST_KHR; }
// Find the image that has the smallest availability measure
MVKSwapchainImage* minWaitImage = nullptr;
MVKSwapchainImageAvailability minAvailability = { .acquisitionID = kMVKUndefinedLargeUInt64,
.waitCount = kMVKUndefinedLargeUInt32,
.isAvailable = false };
// Find the image that has the shortest wait by finding the smallest availability measure.
MVKPresentableSwapchainImage* minWaitImage = nullptr;
MVKSwapchainImageAvailability minAvailability = { kMVKUndefinedLargeUInt64, false };
uint32_t imgCnt = getImageCount();
for (uint32_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
MVKSwapchainImage* img = getImage(imgIdx);
auto* img = getPresentableImage(imgIdx);
auto imgAvail = img->getAvailability();
if (imgAvail < minAvailability) {
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;
minWaitImage->resetMetalDrawable();
minWaitImage->signalWhenAvailable((MVKSemaphore*)semaphore, (MVKFence*)fence);
minWaitImage->acquireAndSignalWhenAvailable((MVKSemaphore*)semaphore, (MVKFence*)fence);
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++) {
_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);
@ -405,7 +403,7 @@ void MVKSwapchain::initFrameIntervalTracking() {
}
MVKSwapchain::~MVKSwapchain() {
for (auto& img : _surfaceImages) { _device->destroySwapchainImage(img, NULL); }
for (auto& img : _presentableImages) { _device->destroyPresentableSwapchainImage(img, NULL); }
if (_licenseWatermark) { _licenseWatermark->destroy(); }
[this->_layerObserver release];