Fix rounding error when checking if the drawableSize of a CAMetalLayer has changed.
- Add mvkGetNaturalExtent() to consolidate retrieving the natural rounded extent of the CAMetalDrawables that will be created by a CAMetalLayer, based on its drawableSize and contentsScale properties. - Replace MVKSwapchain::_mtlLayerDrawableSize with _mtlLayerDrawableExtent. - MVKSwapchain::hasOptimalSurface() compares last, actual, and natural rounded drawable extents of CAMetalLayer.
This commit is contained in:
parent
eabede8cdf
commit
fbf5159ec2
@ -1141,7 +1141,7 @@ VkResult MVKPhysicalDevice::getSurfaceCapabilities( const VkPhysicalDeviceSurfac
|
||||
VkSurfaceCapabilitiesKHR& surfCaps = pSurfaceCapabilities->surfaceCapabilities;
|
||||
surfCaps.minImageCount = _metalFeatures.minSwapchainImageCount;
|
||||
surfCaps.maxImageCount = _metalFeatures.maxSwapchainImageCount;
|
||||
surfCaps.currentExtent = mvkVkExtent2DFromCGSize(mtlLayer.naturalDrawableSizeMVK);
|
||||
surfCaps.currentExtent = mvkGetNaturalExtent(mtlLayer);
|
||||
surfCaps.minImageExtent = { 1, 1 };
|
||||
surfCaps.maxImageExtent = { _properties.limits.maxImageDimension2D, _properties.limits.maxImageDimension2D };
|
||||
surfCaps.maxImageArrayLayers = 1;
|
||||
@ -1389,7 +1389,7 @@ VkResult MVKPhysicalDevice::getPresentRectangles(MVKSurface* surface,
|
||||
*pRectCount = 1;
|
||||
|
||||
pRects[0].offset = { 0, 0 };
|
||||
pRects[0].extent = mvkVkExtent2DFromCGSize(mtlLayer.naturalDrawableSizeMVK);
|
||||
pRects[0].extent = mvkGetNaturalExtent(mtlLayer);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
@ -79,19 +79,8 @@ public:
|
||||
/** Returns whether the parent surface is now lost and this swapchain must be recreated. */
|
||||
bool getIsSurfaceLost() { return _surfaceLost; }
|
||||
|
||||
/**
|
||||
* Returns whether this swapchain is optimally sized for the surface.
|
||||
* It is if the app has specified deliberate swapchain scaling, or the CAMetalLayer
|
||||
* drawableSize has not changed since the swapchain was created, and the CAMetalLayer
|
||||
* will not need to be scaled when composited.
|
||||
*/
|
||||
bool hasOptimalSurface() {
|
||||
if (_isDeliberatelyScaled) { return true; }
|
||||
|
||||
auto drawSize = _mtlLayer.drawableSize;
|
||||
return (CGSizeEqualToSize(drawSize, _mtlLayerDrawableSize) &&
|
||||
CGSizeEqualToSize(drawSize, _mtlLayer.naturalDrawableSizeMVK));
|
||||
}
|
||||
/** Returns whether this swapchain is optimally sized for the surface. */
|
||||
bool hasOptimalSurface();
|
||||
|
||||
/** Returns the status of the surface. Surface loss takes precedence over sub-optimal errors. */
|
||||
VkResult getSurfaceStatus() {
|
||||
@ -145,7 +134,7 @@ protected:
|
||||
std::mutex _presentHistoryLock;
|
||||
std::mutex _layerLock;
|
||||
uint64_t _lastFrameTime = 0;
|
||||
CGSize _mtlLayerDrawableSize = {0.0, 0.0};
|
||||
VkExtent2D _mtlLayerDrawableExtent = {0, 0};
|
||||
uint32_t _currentPerfLogFrameCount = 0;
|
||||
uint32_t _presentHistoryCount = 0;
|
||||
uint32_t _presentHistoryIndex = 0;
|
||||
@ -154,3 +143,17 @@ protected:
|
||||
bool _isDeliberatelyScaled = false;
|
||||
};
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Support functions
|
||||
|
||||
/**
|
||||
* Returns the natural extent of the CAMetalLayer.
|
||||
*
|
||||
* The natural extent is the size of the bounds property of the layer,
|
||||
* multiplied by the contentsScale property of the layer, rounded
|
||||
* to nearest integer using half-to-even rounding.
|
||||
*/
|
||||
static inline VkExtent2D mvkGetNaturalExtent(CAMetalLayer* mtlLayer) {
|
||||
return mvkVkExtent2DFromCGSize(mtlLayer.naturalDrawableSizeMVK);
|
||||
}
|
||||
|
@ -115,6 +115,18 @@ uint64_t MVKSwapchain::getNextAcquisitionID() { return ++_currentAcquisitionID;
|
||||
void MVKSwapchain::releaseUndisplayedSurfaces() {}
|
||||
|
||||
|
||||
// This swapchain is optimally sized for the surface if the app has specified deliberate
|
||||
// swapchain scaling, or the CAMetalLayer drawableSize has not changed since the swapchain
|
||||
// was created, and the CAMetalLayer will not need to be scaled when composited.
|
||||
bool MVKSwapchain::hasOptimalSurface() {
|
||||
if (_isDeliberatelyScaled) { return true; }
|
||||
|
||||
VkExtent2D drawExtent = mvkVkExtent2DFromCGSize(_mtlLayer.drawableSize);
|
||||
return (mvkVkExtent2DsAreEqual(drawExtent, _mtlLayerDrawableExtent) &&
|
||||
mvkVkExtent2DsAreEqual(drawExtent, mvkGetNaturalExtent(_mtlLayer)));
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Rendering
|
||||
|
||||
// Called automatically when a swapchain image is about to be presented to the surface by the queue.
|
||||
@ -339,9 +351,10 @@ void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_STORAGE_BIT));
|
||||
// Remember drawable size to later detect if it has changed under the covers.
|
||||
_mtlLayerDrawableSize = mvkCGSizeFromVkExtent2D(pCreateInfo->imageExtent);
|
||||
_mtlLayer.drawableSize = _mtlLayerDrawableSize;
|
||||
// Remember the extent to later detect if it has changed under the covers,
|
||||
// and set the drawable size of the CAMetalLayer from the extent.
|
||||
_mtlLayerDrawableExtent = pCreateInfo->imageExtent;
|
||||
_mtlLayer.drawableSize = mvkCGSizeFromVkExtent2D(_mtlLayerDrawableExtent);
|
||||
|
||||
if (pCreateInfo->compositeAlpha != VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
|
||||
_mtlLayer.opaque = pCreateInfo->compositeAlpha == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
|
@ -38,8 +38,8 @@
|
||||
/**
|
||||
* Returns the natural drawable size for this layer.
|
||||
*
|
||||
* The natural drawable size is the size of the bounds property of this layer,
|
||||
* multiplied by the contentsScale property of this layer.
|
||||
* The natural drawable size is the size of the bounds
|
||||
* property multiplied by the contentsScale property.
|
||||
*/
|
||||
@property(nonatomic, readonly) CGSize naturalDrawableSizeMVK;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user