Fix retrieval of accurate refresh duration across multiple display screens.

- Add [CAMetalLayer screenMVK] extension method to retrieve screen.
- If the layer has a delegate view, use it to locate the screen, otherwise
  revert to iterating across windows, looking for the CAMetalLayer, to identify
  the window the layer is in, from which to retrieve the screen.
- Fix the iteration of the layer hierarchy, to accommodate that Apple may
  add superlayers to the CAMetalLayer under the covers.
- Update MoltenVK_Runtime_UserGuide.md to encourage the app to ensure the view
  is the delegate of the CAMetalLayer, to more efficiently access the screen.
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 155e1fd..ad840f5 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -143,7 +143,7 @@
           - `MoltenVK/dylib/macOS` *(macOS)*
           - `MoltenVK/dylib/iOS` *(iOS)*
           - `MoltenVK/dylib/tvOS` *(tvOS)*
-          
+       
     3. In the **Runpath Search Paths** (aka `LD_RUNPATH_SEARCH_PATHS`) setting, 
        add an entry that matches where the dynamic library will be located in your runtime
        environment. If the dynamic library is to be embedded within your application, 
@@ -188,11 +188,11 @@
    - To copy the `libMoltenVK.dylib` file into your application or component library:
    
 	   1. On the *Build Phases* tab, add a new *Copy Files* build phase.
-	    
+	   
 	   2. Set the *Destination* into which you want to place  the `libMoltenVK.dylib` file.
 	      Typically this will be *Frameworks* (and it should match the **Runpath Search Paths** 
 	      (aka `LD_RUNPATH_SEARCH_PATHS`) build setting you added above).
-	    
+	   
 	   3. Drag **_one_** of the following files to the *Copy Files* list in this new build phase:
 	     - `MoltenVK/dylib/macOS/libMoltenVK.dylib` *(macOS)* 
 	     - `MoltenVK/dylib/iOS/libMoltenVK.dylib` *(iOS)* 
@@ -229,7 +229,7 @@
 
 When a *Metal* app is running from *Xcode*, the default ***Scheme*** settings may reduce performance. 
 To improve performance and gain the benefits of *Metal*, perform the following in *Xcode*:
-   
+
 1. Open the ***Scheme Editor*** for building your main application. You can do 
    this by selecting ***Edit Scheme...*** from the ***Scheme*** drop-down menu, or select 
    ***Product -> Scheme -> Edit Scheme...*** from the main menu.
@@ -337,8 +337,25 @@
 
 In order to visibly display your content on *macOS*, *iOS*, or *tvOS*, you must enable the
 `VK_EXT_metal_surface` extension, and use the function defined in that extension to create a 
-*Vulkan* rendering surface. You can enable the `VK_EXT_metal_surface` extension by defining the `VK_USE_PLATFORM_METAL_EXT` guard macro in your compiler build settings. See the description of 
-the `mvk_vulkan.h` file below for  a convenient way to enable this extension automatically.
+*Vulkan* rendering surface. You can enable the `VK_EXT_metal_surface` extension by defining 
+the `VK_USE_PLATFORM_METAL_EXT` guard macro in your compiler build settings. See the description 
+of the `mvk_vulkan.h` file below for  a convenient way to enable this extension automatically.
+
+When creating a `CAMetalLayer` to underpin the *Vulkan* surface to render to, it is strongly 
+recommended that you ensure the `delegate` of the `CAMetalLayer` is the `NSView/UIView` in 
+which the layer is contained, to ensure correct and optimized *Vulkan* swapchain and refresh 
+timing behavior across multiple display screens that might have different properties.
+
+The view will automatically be the `delegate` of the layer when the view creates the 
+`CAMetalLayer`, as per Apple's documentation:
+
+>If the layer object was created by a view, the view typically assigns itself as the layer’s 
+delegate automatically, and you should not change that relationship. For layers you create 
+yourself, you can assign a delegate object and use that object to provide the contents of 
+the layer dynamically and perform other tasks.
+
+But in the case where you create the `CAMetalLayer` yourself and assign it to the view, 
+you should also assign the view as the `delegate` of the layer. 
 
 Because **MoltenVK** supports the `VK_KHR_portability_subset` extension, when using the 
 *Vulkan Loader* from the *Vulkan SDK* to run **MoltenVK** on *macOS*, the *Vulkan Loader* 
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 1a6bef6..4f82bfb 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -27,10 +27,11 @@
 - Work around MTLCounterSet crash on additional Intel Iris Plus Graphics drivers.
 - Check `MTLDevice` to enable support for `VK_KHR_fragment_shader_barycentric` 
   and `VK_NV_fragment_shader_barycentric` extensions.
+- Ignore sampler update in descriptor set bindings that use immutable samplers.
 - Fix query pool wait block when query is not encoded to be written to.
 - Fix `vkUpdateDescriptorSetWithTemplate()` for inline block descriptors.
-- Ignore sampler update in descriptor set bindings that use immutable samplers.
-- Update _macOS Cube_ demo to demonstrate optimizing swapchain across multiple screens.
+- Fix retrieval of accurate `vkGetRefreshCycleDurationGOOGLE()` across multiple display screens.
+- Update _macOS Cube_ demo to demonstrate optimizing the swapchain across multiple display screens.
 - Update `VK_MVK_MOLTENVK_SPEC_VERSION` to version `35`.
 
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
index 137eaa1..d614790 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
@@ -26,20 +26,8 @@
 #include "MVKWatermarkTextureContent.h"
 #include "MVKWatermarkShaderSource.h"
 #include "mvk_datatypes.hpp"
-#import "CAMetalLayer+MoltenVK.h"
 #import "MVKBlockObserver.h"
 
-#if MVK_IOS_OR_TVOS || MVK_MACCAT
-#	include <UIKit/UIScreen.h>
-#endif
-
-#if MVK_MACOS && !MVK_MACCAT
-#	include <AppKit/NSApplication.h>
-#	include <AppKit/NSScreen.h>
-#	include <AppKit/NSWindow.h>
-#	include <AppKit/NSView.h>
-#endif
-
 #include <libkern/OSByteOrder.h>
 
 using namespace std;
@@ -409,8 +397,13 @@
 		_presentableImages.push_back(_device->createPresentableSwapchainImage(&imgInfo, this, imgIdx, NULL));
 	}
 
-    MVKLogInfo("Created %d swapchain images with initial size (%d, %d) and contents scale %.1f.",
-			   imgCnt, imgExtent.width, imgExtent.height, _mtlLayer.contentsScale);
+#if MVK_MACOS && !MVK_MACCAT
+	NSString* screenName = _mtlLayer.screenMVK.localizedName;
+#else
+	NSString* screenName = @"Main Screen";
+#endif
+    MVKLogInfo("Created %d swapchain images with initial size (%d, %d) and contents scale %.1f for screen %s.",
+			   imgCnt, imgExtent.width, imgExtent.height, _mtlLayer.contentsScale, screenName.UTF8String);
 }
 
 VkResult MVKSwapchain::getRefreshCycleDuration(VkRefreshCycleDurationGOOGLE *pRefreshCycleDuration) {
@@ -418,33 +411,17 @@
 
 #if MVK_IOS_OR_TVOS || MVK_MACCAT
 	NSInteger framesPerSecond = 60;
-	UIScreen* screen = [UIScreen mainScreen];
+	UIScreen* screen = _mtlLayer.screenMVK;
 	if ([screen respondsToSelector: @selector(maximumFramesPerSecond)]) {
 		framesPerSecond = screen.maximumFramesPerSecond;
 	}
 #endif
-
 #if MVK_MACOS && !MVK_MACCAT
-	// Find the screen for the window whose content view is backed by the swapchains CAMetalLayer.
-	// Default to the mainScreen if no such window can be found.
-	NSScreen* screen = [NSScreen mainScreen];
-	CALayer* layer = _mtlLayer;
-	while (layer.superlayer) {
-		layer = layer.superlayer;
-	}
-
-	for (NSWindow* window in [[NSApplication sharedApplication] windows]) {
-		NSView *view = [window contentView];
-		if (view && ([view layer] == layer)) { // Check against layer and not _mtlLayer.
-			screen = [window screen];
-		}
-	}
-
+	NSScreen* screen = _mtlLayer.screenMVK;
 	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];
diff --git a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h
index afe487f..0cf039b 100644
--- a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h
+++ b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h
@@ -18,8 +18,20 @@
 
 #pragma once
 
+#include "MVKCommonEnvironment.h"
+
 #import <QuartzCore/QuartzCore.h>
 
+#if MVK_IOS_OR_TVOS || MVK_MACCAT
+#	define PLATFORM_SCREEN_CLASS	UIScreen
+#	include <UIKit/UIScreen.h>
+#endif
+
+#if MVK_MACOS && !MVK_MACCAT
+#	define PLATFORM_SCREEN_CLASS	NSScreen
+#	include <AppKit/NSScreen.h>
+#endif
+
 /** Extensions to CAMetalLayer to support MoltenVK. */
 @interface CAMetalLayer (MoltenVK)
 
@@ -73,4 +85,7 @@
  */
 @property(nonatomic, readwrite) CFStringRef colorspaceNameMVK;
 
+/** Returns the screen on which this layer is rendering. */
+@property(nonatomic, readonly) PLATFORM_SCREEN_CLASS* screenMVK;
+
 @end
diff --git a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m
index 2da3118..0214e8b 100644
--- a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m
+++ b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m
@@ -18,7 +18,13 @@
 
 
 #include "CAMetalLayer+MoltenVK.h"
-#include "MVKCommonEnvironment.h"
+
+#if MVK_MACOS && !MVK_MACCAT
+#	include <AppKit/NSApplication.h>
+#	include <AppKit/NSWindow.h>
+#	include <AppKit/NSView.h>
+#endif
+
 
 @implementation CAMetalLayer (MoltenVK)
 
@@ -84,4 +90,33 @@
 	CGColorSpaceRelease(csRef);
 }
 
+#if MVK_IOS_OR_TVOS || MVK_MACCAT
+-(UIScreen*) screenMVK {
+	return UIScreen.mainScreen;
+}
+#endif
+
+#if MVK_MACOS && !MVK_MACCAT
+-(NSScreen*) screenMVK {
+	// 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]) {
+		NSWindow* window = ((NSView*)self.delegate).window;
+		if (window) { return window.screen; }
+	} else {
+		// Otherwise we need to iterate through all the windows used by this app, and
+		// check if the content view is using this layer or one of its ancestor layers.
+		// If a match is found, retrieve the screen from the window. It is not sufficient
+		// to first search for the top structural layer, because Core Animation may add
+		// a superlayer to the CAMetalLayer, independent of the content view.
+		for (NSWindow* window in NSApplication.sharedApplication.windows) {
+			CALayer* windowContentLayer = window.contentView.layer;
+			for (CALayer* layer = self; layer; layer = layer.superlayer) {
+				if (layer == windowContentLayer) { return window.screen; }
+			}
+		}
+	}
+	return NSScreen.mainScreen;		// Default to main screen if not found
+}
+#endif
+
 @end