Merge pull request #1080 from cdavis5e/display-timing-use-after-free

MVKSwapchainImage: Retain image and swapchain until presentation is done.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index a7b81b8..4dab04b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -402,6 +402,8 @@
 					  MVKSwapchain* swapchain,
 					  uint32_t swapchainIndex);
 
+	~MVKSwapchainImage() override;
+
 protected:
 	friend class MVKPeerSwapchainImage;
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 8b07945..52e2e8d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -1115,6 +1115,12 @@
 									 uint32_t swapchainIndex) : MVKImage(device, pCreateInfo) {
 	_swapchain = swapchain;
 	_swapchainIndex = swapchainIndex;
+
+	_swapchain->retain();
+}
+
+MVKSwapchainImage::~MVKSwapchainImage() {
+	if (_swapchain) { _swapchain->release(); }
 }
 
 
@@ -1275,11 +1281,13 @@
 		_swapchain->recordPresentTime(presentID, desiredPresentTime, desiredPresentTime);
 #else
 		if ([_mtlDrawable respondsToSelector: @selector(addPresentedHandler:)]) {
+			retain();	// Ensure this image is not destroyed while awaiting presentation
 			[_mtlDrawable addPresentedHandler: ^(id<MTLDrawable> drawable) {
 				// Record the presentation time
 				CFTimeInterval presentedTimeSeconds = drawable.presentedTime;
 				uint64_t presentedTimeNanoseconds = (uint64_t)(presentedTimeSeconds * 1.0e9);
 				_swapchain->recordPresentTime(presentID, desiredPresentTime, presentedTimeNanoseconds);
+				release();
 			}];
 		} else {
 			// If MTLDrawable.presentedTime/addPresentedHandler isn't supported, just treat it as if the