Merge pull request #557 from cdavis5e/surface-loss
Handle surface loss.
This commit is contained in:
commit
7fd61a4610
@ -9,6 +9,10 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
|
45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
|
||||||
45003E74214AD4E600E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
|
45003E74214AD4E600E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
|
||||||
|
4553AEFB2251617100E8EBCD /* MVKBlockObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4553AEF62251617100E8EBCD /* MVKBlockObserver.m */; };
|
||||||
|
4553AEFC2251617100E8EBCD /* MVKBlockObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4553AEF62251617100E8EBCD /* MVKBlockObserver.m */; };
|
||||||
|
4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */; };
|
||||||
|
4553AEFE2251617100E8EBCD /* MVKBlockObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */; };
|
||||||
45557A5221C9EFF3008868BD /* MVKCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45557A4D21C9EFF3008868BD /* MVKCodec.cpp */; };
|
45557A5221C9EFF3008868BD /* MVKCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45557A4D21C9EFF3008868BD /* MVKCodec.cpp */; };
|
||||||
45557A5321C9EFF3008868BD /* MVKCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45557A4D21C9EFF3008868BD /* MVKCodec.cpp */; };
|
45557A5321C9EFF3008868BD /* MVKCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45557A4D21C9EFF3008868BD /* MVKCodec.cpp */; };
|
||||||
45557A5421C9EFF3008868BD /* MVKCodec.h in Headers */ = {isa = PBXBuildFile; fileRef = 45557A5121C9EFF3008868BD /* MVKCodec.h */; };
|
45557A5421C9EFF3008868BD /* MVKCodec.h in Headers */ = {isa = PBXBuildFile; fileRef = 45557A5121C9EFF3008868BD /* MVKCodec.h */; };
|
||||||
@ -271,6 +275,8 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
45003E6F214AD4C900E989CB /* MVKExtensions.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKExtensions.def; sourceTree = "<group>"; };
|
45003E6F214AD4C900E989CB /* MVKExtensions.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKExtensions.def; sourceTree = "<group>"; };
|
||||||
|
4553AEF62251617100E8EBCD /* MVKBlockObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVKBlockObserver.m; sourceTree = "<group>"; };
|
||||||
|
4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKBlockObserver.h; sourceTree = "<group>"; };
|
||||||
45557A4D21C9EFF3008868BD /* MVKCodec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MVKCodec.cpp; sourceTree = "<group>"; };
|
45557A4D21C9EFF3008868BD /* MVKCodec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MVKCodec.cpp; sourceTree = "<group>"; };
|
||||||
45557A5121C9EFF3008868BD /* MVKCodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCodec.h; sourceTree = "<group>"; };
|
45557A5121C9EFF3008868BD /* MVKCodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCodec.h; sourceTree = "<group>"; };
|
||||||
45557A5721CD83C3008868BD /* MVKDXTnCodec.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKDXTnCodec.def; sourceTree = "<group>"; };
|
45557A5721CD83C3008868BD /* MVKDXTnCodec.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKDXTnCodec.def; sourceTree = "<group>"; };
|
||||||
@ -508,6 +514,8 @@
|
|||||||
A98149401FB6A3F7005F00B4 /* Utility */ = {
|
A98149401FB6A3F7005F00B4 /* Utility */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */,
|
||||||
|
4553AEF62251617100E8EBCD /* MVKBlockObserver.m */,
|
||||||
45557A5721CD83C3008868BD /* MVKDXTnCodec.def */,
|
45557A5721CD83C3008868BD /* MVKDXTnCodec.def */,
|
||||||
45557A4D21C9EFF3008868BD /* MVKCodec.cpp */,
|
45557A4D21C9EFF3008868BD /* MVKCodec.cpp */,
|
||||||
45557A5121C9EFF3008868BD /* MVKCodec.h */,
|
45557A5121C9EFF3008868BD /* MVKCodec.h */,
|
||||||
@ -654,6 +662,7 @@
|
|||||||
A94FB7BC1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
|
A94FB7BC1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
|
||||||
A94FB7F81C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
|
A94FB7F81C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
|
||||||
A94FB7F01C7DFB4800632CA3 /* MVKImage.h in Headers */,
|
A94FB7F01C7DFB4800632CA3 /* MVKImage.h in Headers */,
|
||||||
|
4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
|
||||||
A94FB7B81C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */,
|
A94FB7B81C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */,
|
||||||
A94FB7C81C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */,
|
A94FB7C81C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */,
|
||||||
A94FB7D01C7DFB4800632CA3 /* MVKCommandBuffer.h in Headers */,
|
A94FB7D01C7DFB4800632CA3 /* MVKCommandBuffer.h in Headers */,
|
||||||
@ -718,6 +727,7 @@
|
|||||||
A94FB7BD1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
|
A94FB7BD1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
|
||||||
A94FB7F91C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
|
A94FB7F91C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
|
||||||
A94FB7F11C7DFB4800632CA3 /* MVKImage.h in Headers */,
|
A94FB7F11C7DFB4800632CA3 /* MVKImage.h in Headers */,
|
||||||
|
4553AEFE2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
|
||||||
A94FB7B91C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */,
|
A94FB7B91C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */,
|
||||||
A94FB7C91C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */,
|
A94FB7C91C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */,
|
||||||
A94FB7D11C7DFB4800632CA3 /* MVKCommandBuffer.h in Headers */,
|
A94FB7D11C7DFB4800632CA3 /* MVKCommandBuffer.h in Headers */,
|
||||||
@ -929,6 +939,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
4553AEFB2251617100E8EBCD /* MVKBlockObserver.m in Sources */,
|
||||||
A9E53DFF21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m in Sources */,
|
A9E53DFF21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m in Sources */,
|
||||||
A94FB80A1C7DFB4800632CA3 /* MVKResource.mm in Sources */,
|
A94FB80A1C7DFB4800632CA3 /* MVKResource.mm in Sources */,
|
||||||
A94FB7E21C7DFB4800632CA3 /* MVKDescriptorSet.mm in Sources */,
|
A94FB7E21C7DFB4800632CA3 /* MVKDescriptorSet.mm in Sources */,
|
||||||
@ -983,6 +994,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
4553AEFC2251617100E8EBCD /* MVKBlockObserver.m in Sources */,
|
||||||
A9E53E0021064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m in Sources */,
|
A9E53E0021064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m in Sources */,
|
||||||
A94FB80B1C7DFB4800632CA3 /* MVKResource.mm in Sources */,
|
A94FB80B1C7DFB4800632CA3 /* MVKResource.mm in Sources */,
|
||||||
A94FB7E31C7DFB4800632CA3 /* MVKDescriptorSet.mm in Sources */,
|
A94FB7E31C7DFB4800632CA3 /* MVKDescriptorSet.mm in Sources */,
|
||||||
|
@ -390,7 +390,10 @@ MVKQueuePresentSurfaceSubmission::MVKQueuePresentSurfaceSubmission(MVKDevice* de
|
|||||||
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]));
|
_surfaceImages.push_back(mvkSC->getImage(pPresentInfo->pImageIndices[i]));
|
||||||
if (mvkSC->getHasSurfaceSizeChanged()) {
|
// Surface loss takes precedence over out-of-date errors.
|
||||||
|
if (mvkSC->getIsSurfaceLost()) {
|
||||||
|
_submissionResult = VK_ERROR_SURFACE_LOST_KHR;
|
||||||
|
} else if (mvkSC->getHasSurfaceSizeChanged() && _submissionResult != VK_ERROR_SURFACE_LOST_KHR) {
|
||||||
_submissionResult = VK_ERROR_OUT_OF_DATE_KHR;
|
_submissionResult = VK_ERROR_OUT_OF_DATE_KHR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "mvk_vulkan.h"
|
#include "mvk_vulkan.h"
|
||||||
#include "MVKBaseObject.h"
|
#include "MVKBaseObject.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
|
||||||
// Expose MoltenVK Apple surface extension functionality
|
// Expose MoltenVK Apple surface extension functionality
|
||||||
@ -27,14 +28,14 @@
|
|||||||
# define vkCreate_PLATFORM_SurfaceMVK vkCreateIOSSurfaceMVK
|
# define vkCreate_PLATFORM_SurfaceMVK vkCreateIOSSurfaceMVK
|
||||||
# define Vk_PLATFORM_SurfaceCreateInfoMVK VkIOSSurfaceCreateInfoMVK
|
# define Vk_PLATFORM_SurfaceCreateInfoMVK VkIOSSurfaceCreateInfoMVK
|
||||||
# define PLATFORM_VIEW_CLASS UIView
|
# define PLATFORM_VIEW_CLASS UIView
|
||||||
# include <UIKit/UIView.h>
|
# import <UIKit/UIView.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_MACOS_MVK
|
#ifdef VK_USE_PLATFORM_MACOS_MVK
|
||||||
# define vkCreate_PLATFORM_SurfaceMVK vkCreateMacOSSurfaceMVK
|
# define vkCreate_PLATFORM_SurfaceMVK vkCreateMacOSSurfaceMVK
|
||||||
# define Vk_PLATFORM_SurfaceCreateInfoMVK VkMacOSSurfaceCreateInfoMVK
|
# define Vk_PLATFORM_SurfaceCreateInfoMVK VkMacOSSurfaceCreateInfoMVK
|
||||||
# define PLATFORM_VIEW_CLASS NSView
|
# define PLATFORM_VIEW_CLASS NSView
|
||||||
# include <AppKit/NSView.h>
|
# import <AppKit/NSView.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#import <Metal/Metal.h>
|
#import <Metal/Metal.h>
|
||||||
@ -42,6 +43,8 @@
|
|||||||
|
|
||||||
class MVKInstance;
|
class MVKInstance;
|
||||||
|
|
||||||
|
@class MVKBlockObserver;
|
||||||
|
|
||||||
|
|
||||||
#pragma mark MVKSurface
|
#pragma mark MVKSurface
|
||||||
|
|
||||||
@ -51,7 +54,10 @@ class MVKSurface : public MVKConfigurableObject {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/** Returns the CAMetalLayer underlying this surface. */
|
/** Returns the CAMetalLayer underlying this surface. */
|
||||||
inline CAMetalLayer* getCAMetalLayer() { return _mtlCAMetalLayer; }
|
inline CAMetalLayer* getCAMetalLayer() {
|
||||||
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
|
return _mtlCAMetalLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Construction
|
#pragma mark Construction
|
||||||
@ -64,5 +70,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
CAMetalLayer* _mtlCAMetalLayer;
|
CAMetalLayer* _mtlCAMetalLayer;
|
||||||
|
std::mutex _lock;
|
||||||
|
MVKBlockObserver* _layerObserver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "MVKInstance.h"
|
#include "MVKInstance.h"
|
||||||
#include "MVKFoundation.h"
|
#include "MVKFoundation.h"
|
||||||
#include "MVKOSExtensions.h"
|
#include "MVKOSExtensions.h"
|
||||||
|
#import "MVKBlockObserver.h"
|
||||||
|
|
||||||
|
|
||||||
#pragma mark MVKSurface
|
#pragma mark MVKSurface
|
||||||
@ -57,6 +58,19 @@ MVKSurface::MVKSurface(MVKInstance* mvkInstance,
|
|||||||
// Confirm that we were provided with a CAMetalLayer
|
// Confirm that we were provided with a CAMetalLayer
|
||||||
if ([obj isKindOfClass: [CAMetalLayer class]]) {
|
if ([obj isKindOfClass: [CAMetalLayer class]]) {
|
||||||
_mtlCAMetalLayer = (CAMetalLayer*)[obj retain]; // retained
|
_mtlCAMetalLayer = (CAMetalLayer*)[obj retain]; // retained
|
||||||
|
if ([_mtlCAMetalLayer.delegate isKindOfClass: [PLATFORM_VIEW_CLASS class]]) {
|
||||||
|
// Sometimes, the owning view can replace its CAMetalLayer. In that case, the client
|
||||||
|
// needs to recreate the surface.
|
||||||
|
_layerObserver = [MVKBlockObserver observerWithBlock: ^(NSString* path, id, NSDictionary*, void*) {
|
||||||
|
if ( ![path isEqualTo: @"layer"] ) { return; }
|
||||||
|
std::lock_guard<std::mutex> lock(this->_lock);
|
||||||
|
[this->_mtlCAMetalLayer release];
|
||||||
|
this->_mtlCAMetalLayer = nil;
|
||||||
|
this->setConfigurationResult(VK_ERROR_SURFACE_LOST_KHR);
|
||||||
|
[this->_layerObserver release];
|
||||||
|
this->_layerObserver = nil;
|
||||||
|
} forObject: _mtlCAMetalLayer.delegate atKeyPath: @"layer"];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "%s(): On-screen rendering requires a layer of type CAMetalLayer.", mvkSurfaceCreateFuncName));
|
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "%s(): On-screen rendering requires a layer of type CAMetalLayer.", mvkSurfaceCreateFuncName));
|
||||||
_mtlCAMetalLayer = nil;
|
_mtlCAMetalLayer = nil;
|
||||||
@ -64,6 +78,8 @@ MVKSurface::MVKSurface(MVKInstance* mvkInstance,
|
|||||||
}
|
}
|
||||||
|
|
||||||
MVKSurface::~MVKSurface() {
|
MVKSurface::~MVKSurface() {
|
||||||
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
[_mtlCAMetalLayer release];
|
[_mtlCAMetalLayer release];
|
||||||
|
[_layerObserver release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
class MVKSwapchainImage;
|
class MVKSwapchainImage;
|
||||||
class MVKWatermark;
|
class MVKWatermark;
|
||||||
|
|
||||||
|
@class MVKBlockObserver;
|
||||||
|
|
||||||
|
|
||||||
#pragma mark MVKSwapchain
|
#pragma mark MVKSwapchain
|
||||||
|
|
||||||
@ -63,6 +65,9 @@ public:
|
|||||||
/** Returns whether the surface size has changed since the last time this function was called. */
|
/** Returns whether the surface size has changed since the last time this function was called. */
|
||||||
bool getHasSurfaceSizeChanged();
|
bool getHasSurfaceSizeChanged();
|
||||||
|
|
||||||
|
/** Returns whether the parent surface is now lost and this swapchain must be recreated. */
|
||||||
|
bool getIsSurfaceLost() { return _surfaceLost; }
|
||||||
|
|
||||||
/** Returns the specified performance stats structure. */
|
/** Returns the specified performance stats structure. */
|
||||||
const MVKSwapchainPerformance* getPerformanceStatistics() { return &_performanceStatistics; }
|
const MVKSwapchainPerformance* getPerformanceStatistics() { return &_performanceStatistics; }
|
||||||
|
|
||||||
@ -106,5 +111,7 @@ protected:
|
|||||||
uint64_t _lastFrameTime;
|
uint64_t _lastFrameTime;
|
||||||
double _averageFrameIntervalFilterAlpha;
|
double _averageFrameIntervalFilterAlpha;
|
||||||
uint32_t _currentPerfLogFrameCount;
|
uint32_t _currentPerfLogFrameCount;
|
||||||
|
std::atomic<bool> _surfaceLost;
|
||||||
|
MVKBlockObserver* _layerObserver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "mvk_datatypes.h"
|
#include "mvk_datatypes.h"
|
||||||
#include "MVKLogging.h"
|
#include "MVKLogging.h"
|
||||||
#import "CAMetalLayer+MoltenVK.h"
|
#import "CAMetalLayer+MoltenVK.h"
|
||||||
|
#import "MVKBlockObserver.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -65,6 +66,9 @@ VkResult MVKSwapchain::acquireNextImageKHR(uint64_t timeout,
|
|||||||
VkFence fence,
|
VkFence fence,
|
||||||
uint32_t deviceMask,
|
uint32_t deviceMask,
|
||||||
uint32_t* pImageIndex) {
|
uint32_t* pImageIndex) {
|
||||||
|
|
||||||
|
if ( getIsSurfaceLost() ) { return VK_ERROR_SURFACE_LOST_KHR; }
|
||||||
|
|
||||||
// Find the image that has the smallest availability measure
|
// Find the image that has the smallest availability measure
|
||||||
uint32_t minWaitIndex = 0;
|
uint32_t minWaitIndex = 0;
|
||||||
MVKSwapchainImageAvailability minAvailability = { .acquisitionID = kMVKUndefinedLargeUInt64,
|
MVKSwapchainImageAvailability minAvailability = { .acquisitionID = kMVKUndefinedLargeUInt64,
|
||||||
@ -173,7 +177,7 @@ id<CAMetalDrawable> MVKSwapchain::getNextCAMetalDrawable() {
|
|||||||
#pragma mark Construction
|
#pragma mark Construction
|
||||||
|
|
||||||
MVKSwapchain::MVKSwapchain(MVKDevice* device,
|
MVKSwapchain::MVKSwapchain(MVKDevice* device,
|
||||||
const VkSwapchainCreateInfoKHR* pCreateInfo) : MVKBaseDeviceObject(device) {
|
const VkSwapchainCreateInfoKHR* pCreateInfo) : MVKBaseDeviceObject(device), _surfaceLost(false) {
|
||||||
_currentAcquisitionID = 0;
|
_currentAcquisitionID = 0;
|
||||||
|
|
||||||
// If applicable, release any surfaces (not currently being displayed) from the old swapchain.
|
// If applicable, release any surfaces (not currently being displayed) from the old swapchain.
|
||||||
@ -194,6 +198,12 @@ MVKSwapchain::MVKSwapchain(MVKDevice* device,
|
|||||||
void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt) {
|
void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt) {
|
||||||
|
|
||||||
MVKSurface* mvkSrfc = (MVKSurface*)pCreateInfo->surface;
|
MVKSurface* mvkSrfc = (MVKSurface*)pCreateInfo->surface;
|
||||||
|
if ( !mvkSrfc->getCAMetalLayer() ) {
|
||||||
|
setConfigurationResult(mvkSrfc->getConfigurationResult());
|
||||||
|
_surfaceLost = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_mtlLayer = mvkSrfc->getCAMetalLayer();
|
_mtlLayer = mvkSrfc->getCAMetalLayer();
|
||||||
_mtlLayer.device = getMTLDevice();
|
_mtlLayer.device = getMTLDevice();
|
||||||
_mtlLayer.pixelFormat = getMTLPixelFormatFromVkFormat(pCreateInfo->imageFormat);
|
_mtlLayer.pixelFormat = getMTLPixelFormatFromVkFormat(pCreateInfo->imageFormat);
|
||||||
@ -211,12 +221,27 @@ void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo,
|
|||||||
// - drawsAsynchronously
|
// - drawsAsynchronously
|
||||||
// - colorspace (macOS only) Vulkan only supports sRGB colorspace for now.
|
// - colorspace (macOS only) Vulkan only supports sRGB colorspace for now.
|
||||||
// - wantsExtendedDynamicRangeContent (macOS only)
|
// - wantsExtendedDynamicRangeContent (macOS only)
|
||||||
|
|
||||||
|
if ( [_mtlLayer.delegate isKindOfClass: [PLATFORM_VIEW_CLASS class]] ) {
|
||||||
|
// Sometimes, the owning view can replace its CAMetalLayer. In that case, the client
|
||||||
|
// needs to recreate the swapchain, or no content will be displayed.
|
||||||
|
_layerObserver = [MVKBlockObserver observerWithBlock: ^(NSString* path, id, NSDictionary*, void*) {
|
||||||
|
if ( ![path isEqualTo: @"layer"] ) { return; }
|
||||||
|
this->_surfaceLost = true;
|
||||||
|
[this->_layerObserver release];
|
||||||
|
this->_layerObserver = nil;
|
||||||
|
} forObject: _mtlLayer.delegate atKeyPath: @"layer"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the array of images used for the surface of this swapchain.
|
// Initializes the array of images used for the surface of this swapchain.
|
||||||
// The CAMetalLayer should already be initialized when this is called.
|
// The CAMetalLayer should already be initialized when this is called.
|
||||||
void MVKSwapchain::initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt) {
|
void MVKSwapchain::initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt) {
|
||||||
|
|
||||||
|
if ( getIsSurfaceLost() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VkExtent2D imgExtent = mvkVkExtent2DFromCGSize(_mtlLayerOrigDrawSize);
|
VkExtent2D imgExtent = mvkVkExtent2DFromCGSize(_mtlLayerOrigDrawSize);
|
||||||
|
|
||||||
VkImageCreateInfo imgInfo = {
|
VkImageCreateInfo imgInfo = {
|
||||||
@ -263,5 +288,6 @@ MVKSwapchain::~MVKSwapchain() {
|
|||||||
for (auto& img : _surfaceImages) { _device->destroySwapchainImage(img, NULL); }
|
for (auto& img : _surfaceImages) { _device->destroySwapchainImage(img, NULL); }
|
||||||
|
|
||||||
if (_licenseWatermark) { _licenseWatermark->destroy(); }
|
if (_licenseWatermark) { _licenseWatermark->destroy(); }
|
||||||
|
[this->_layerObserver release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
MoltenVK/MoltenVK/Utility/MVKBlockObserver.h
Normal file
47
MoltenVK/MoltenVK/Utility/MVKBlockObserver.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* MVKBlockObserver.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Chip Davis for CodeWeavers
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#import <Foundation/NSObject.h>
|
||||||
|
#import <Foundation/NSKeyValueObserving.h>
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark MVKBlockObserver
|
||||||
|
|
||||||
|
typedef void (^MVKKeyValueObserverBlock)(NSString* keyPath, id object, NSDictionary* changeDict, void* context);
|
||||||
|
|
||||||
|
/** Class that calls a block on any key-value observation callback. */
|
||||||
|
@interface MVKBlockObserver : NSObject {
|
||||||
|
MVKKeyValueObserverBlock _block;
|
||||||
|
id _target;
|
||||||
|
NSString* _keyPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithBlock:(MVKKeyValueObserverBlock) block;
|
||||||
|
- (instancetype)initWithBlock:(MVKKeyValueObserverBlock) block forObject: object atKeyPath:(NSString*) keyPath;
|
||||||
|
|
||||||
|
+ (instancetype)observerWithBlock:(MVKKeyValueObserverBlock) block;
|
||||||
|
+ (instancetype)observerWithBlock:(MVKKeyValueObserverBlock) block forObject: object atKeyPath:(NSString*) keyPath;
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(NSString*) path ofObject: object change:(NSDictionary*) changeDict context: (void*)context;
|
||||||
|
|
||||||
|
- (void)startObservingObject: object atKeyPath:(NSString*) keyPath;
|
||||||
|
- (void)stopObserving;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
74
MoltenVK/MoltenVK/Utility/MVKBlockObserver.m
Normal file
74
MoltenVK/MoltenVK/Utility/MVKBlockObserver.m
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* MVKBlockObserver.m
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Chip Davis for CodeWeavers
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#import "MVKBlockObserver.h"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation MVKBlockObserver
|
||||||
|
|
||||||
|
- (instancetype)initWithBlock:(MVKKeyValueObserverBlock) block {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
_block = [block copy];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithBlock:(MVKKeyValueObserverBlock) block forObject: object atKeyPath:(NSString*) keyPath {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
_block = [block copy];
|
||||||
|
[self startObservingObject: object atKeyPath: keyPath];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)observerWithBlock:(MVKKeyValueObserverBlock) block {
|
||||||
|
return [[self alloc] initWithBlock: block];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)observerWithBlock:(MVKKeyValueObserverBlock) block forObject: object atKeyPath:(NSString*) keyPath {
|
||||||
|
return [[self alloc] initWithBlock: block forObject: object atKeyPath: keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[self stopObserving];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(NSString*) path ofObject: object change:(NSDictionary*) changeDict context:(void*) context {
|
||||||
|
_block(path, object, changeDict, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startObservingObject: object atKeyPath:(NSString*) path {
|
||||||
|
if ( !_target ) {
|
||||||
|
_target = [object retain];
|
||||||
|
_keyPath = [path copy];
|
||||||
|
[_target addObserver: self forKeyPath: _keyPath options: 0 context: NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopObserving {
|
||||||
|
[_target removeObserver: self forKeyPath: _keyPath context: NULL];
|
||||||
|
[_target release];
|
||||||
|
[_keyPath release];
|
||||||
|
_target = nil;
|
||||||
|
_keyPath = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user