Add ability to automatically capture first GPU frame.
Refactor auto GPU capture code to support both device and frame capture. Add ability to automatically capture first GPU frame by setting `MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE` to `2`. Wrap GPU capture in autorelease pool to handle both cases of capture call being made in run loop as in an app GUI, or in one-shot app like CTS.
This commit is contained in:
parent
fcb4701f47
commit
95cf144ccf
@ -25,6 +25,8 @@ Released TBD
|
||||
- `vkGetMoltenVKConfigurationMVK()` and `vkSetMoltenVKConfigurationMVK()` functions
|
||||
can now be used with a `VkInstance` from another Vulkan layer, or with a `VK_NULL_HANDLE VkInstance`.
|
||||
- `MVKConfiguration` extended to cover all MoltenVK environment variables.
|
||||
- Add ability to automatically capture first GPU frame by setting `MVKConfiguration::autoGPUCaptureScope`
|
||||
(or environment variable `MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE`) to `2`.
|
||||
- Support _GitHub Actions_ for CI builds on pull requests.
|
||||
- Remove support for _Travis-CI_.
|
||||
- `Makefile` and `fetchDependencies` support `xcpretty` (if available)
|
||||
|
@ -583,6 +583,7 @@ typedef struct {
|
||||
* To automatically trigger a GPU capture, set this value as follows:
|
||||
* 0: No automatic GPU capture.
|
||||
* 1: Capture all GPU commands issued during the lifetime of the VkDevice.
|
||||
* 2: Capture all GPU commands issued during the first rendered frame.
|
||||
*
|
||||
* The value of this parameter must be changed before creating a VkDevice,
|
||||
* for the change to take effect.
|
||||
|
@ -692,6 +692,36 @@ public:
|
||||
*/
|
||||
bool shouldPrefillMTLCommandBuffers();
|
||||
|
||||
/**
|
||||
* Checks if automatic GPU capture is supported, and is enabled for the specified auto
|
||||
* capture scope, and if so, starts capturing from the specified Metal capture object.
|
||||
* The capture will be made either to Xcode, or to a file if one has been configured.
|
||||
*
|
||||
* The autoGPUCaptureScope parameter must be one of:
|
||||
* - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE
|
||||
* - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE
|
||||
* - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME
|
||||
*
|
||||
* The mtlCaptureObject must be one of:
|
||||
* - MTLDevice for scope MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE
|
||||
* - MTLCommandQueue for scope MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME.
|
||||
*/
|
||||
void startAutoGPUCapture(int32_t autoGPUCaptureScope, id mtlCaptureObject);
|
||||
|
||||
/**
|
||||
* Checks if automatic GPU capture is enabled for the specified
|
||||
* auto capture scope, and if so, stops capturing.
|
||||
*
|
||||
* The autoGPUCaptureScope parameter must be one of:
|
||||
* - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE
|
||||
* - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE
|
||||
* - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME
|
||||
*/
|
||||
void stopAutoGPUCapture(int32_t autoGPUCaptureScope);
|
||||
|
||||
/** Returns whether this instance is currently automatically capturing a GPU trace. */
|
||||
inline bool isCurrentlyAutoGPUCapturing() { return _isCurrentlyAutoGPUCapturing; }
|
||||
|
||||
|
||||
#pragma mark Properties directly accessible
|
||||
|
||||
@ -797,6 +827,7 @@ protected:
|
||||
bool _useMTLEventForSemaphores;
|
||||
bool _logActivityPerformanceInline;
|
||||
bool _isPerformanceTracking;
|
||||
bool _isCurrentlyAutoGPUCapturing;
|
||||
};
|
||||
|
||||
|
||||
|
@ -3675,6 +3675,62 @@ bool MVKDevice::shouldPrefillMTLCommandBuffers() {
|
||||
_enabledInlineUniformBlockFeatures.descriptorBindingInlineUniformBlockUpdateAfterBind));
|
||||
}
|
||||
|
||||
void MVKDevice::startAutoGPUCapture(int32_t autoGPUCaptureScope, id mtlCaptureObject) {
|
||||
|
||||
if (_isCurrentlyAutoGPUCapturing || (mvkGetMVKConfiguration()->autoGPUCaptureScope != autoGPUCaptureScope)) { return; }
|
||||
|
||||
_isCurrentlyAutoGPUCapturing = true;
|
||||
|
||||
@autoreleasepool {
|
||||
MTLCaptureManager *captureMgr = [MTLCaptureManager sharedCaptureManager];
|
||||
|
||||
// Before macOS 10.15 and iOS 13.0, captureDesc will just be nil
|
||||
MTLCaptureDescriptor *captureDesc = [[MTLCaptureDescriptor new] autorelease];
|
||||
captureDesc.captureObject = mtlCaptureObject;
|
||||
captureDesc.destination = MTLCaptureDestinationDeveloperTools;
|
||||
|
||||
char* filePath = mvkGetMVKConfiguration()->autoGPUCaptureOutputFilepath;
|
||||
if (strlen(filePath)) {
|
||||
if ([captureMgr respondsToSelector: @selector(supportsDestination:)] &&
|
||||
[captureMgr supportsDestination: MTLCaptureDestinationGPUTraceDocument] ) {
|
||||
|
||||
NSString* expandedFilePath = [[NSString stringWithUTF8String: filePath] stringByExpandingTildeInPath];
|
||||
MVKLogInfo("Capturing GPU trace to file %s.", expandedFilePath.UTF8String);
|
||||
|
||||
captureDesc.destination = MTLCaptureDestinationGPUTraceDocument;
|
||||
captureDesc.outputURL = [NSURL fileURLWithPath: expandedFilePath];
|
||||
|
||||
} else {
|
||||
reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Capturing GPU traces to a file requires macOS 10.15 or iOS 13.0 and GPU capturing to be enabled. Falling back to Xcode GPU capture.");
|
||||
}
|
||||
} else {
|
||||
MVKLogInfo("Capturing GPU trace to Xcode.");
|
||||
}
|
||||
|
||||
// Suppress deprecation warnings for startCaptureWithXXX: on MacCatalyst.
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if ([captureMgr respondsToSelector: @selector(startCaptureWithDescriptor:error:)] ) {
|
||||
NSError *err = nil;
|
||||
if ( ![captureMgr startCaptureWithDescriptor: captureDesc error: &err] ) {
|
||||
reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to automatically start GPU capture session (Error code %li): %s", (long)err.code, err.localizedDescription.UTF8String);
|
||||
}
|
||||
} else if ([mtlCaptureObject conformsToProtocol:@protocol(MTLCommandQueue)]) {
|
||||
[captureMgr startCaptureWithCommandQueue: mtlCaptureObject];
|
||||
} else if ([mtlCaptureObject conformsToProtocol:@protocol(MTLDevice)]) {
|
||||
[captureMgr startCaptureWithDevice: mtlCaptureObject];
|
||||
}
|
||||
# pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
void MVKDevice::stopAutoGPUCapture(int32_t autoGPUCaptureScope) {
|
||||
if (_isCurrentlyAutoGPUCapturing && mvkGetMVKConfiguration()->autoGPUCaptureScope == autoGPUCaptureScope) {
|
||||
[[MTLCaptureManager sharedCaptureManager] stopCapture];
|
||||
_isCurrentlyAutoGPUCapturing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Construction
|
||||
|
||||
@ -3695,7 +3751,8 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo
|
||||
_enabledVtxAttrDivFeatures(),
|
||||
_enabledPrivateDataFeatures(),
|
||||
_enabledPortabilityFeatures(),
|
||||
_enabledExtensions(this)
|
||||
_enabledExtensions(this),
|
||||
_isCurrentlyAutoGPUCapturing(false)
|
||||
{
|
||||
// If the physical device is lost, bail.
|
||||
if (physicalDevice->getConfigurationResult() != VK_SUCCESS) {
|
||||
@ -3717,41 +3774,7 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo
|
||||
|
||||
_commandResourceFactory = new MVKCommandResourceFactory(this);
|
||||
|
||||
// This code will be refactored in an upcoming release, but for now,
|
||||
// suppress deprecation warnings for startCaptureWithDevice: on MacCatalyst.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (mvkGetMVKConfiguration()->autoGPUCaptureScope == MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE) {
|
||||
MTLCaptureManager *captureMgr = [MTLCaptureManager sharedCaptureManager];
|
||||
char* filePath = mvkGetMVKConfiguration()->autoGPUCaptureOutputFilepath;
|
||||
if (strlen(filePath)) {
|
||||
if ( ![captureMgr respondsToSelector: @selector(supportsDestination:)] ||
|
||||
![captureMgr supportsDestination: MTLCaptureDestinationGPUTraceDocument] ) {
|
||||
reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Capturing GPU traces to a file requires macOS 10.15 or iOS 13.0. Falling back to Xcode GPU capture.");
|
||||
[captureMgr startCaptureWithDevice: getMTLDevice()];
|
||||
} else {
|
||||
NSError *err = nil;
|
||||
NSString *path, *expandedPath;
|
||||
MTLCaptureDescriptor *captureDesc = [MTLCaptureDescriptor new];
|
||||
captureDesc.captureObject = getMTLDevice();
|
||||
captureDesc.destination = MTLCaptureDestinationGPUTraceDocument;
|
||||
path = [NSString stringWithUTF8String: filePath];
|
||||
expandedPath = path.stringByExpandingTildeInPath;
|
||||
captureDesc.outputURL = [NSURL fileURLWithPath: expandedPath];
|
||||
if (![captureMgr startCaptureWithDescriptor: captureDesc error: &err]) {
|
||||
reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to start GPU capture session to %s (Error code %li): %s", filePath, (long)err.code, err.localizedDescription.UTF8String);
|
||||
[err release];
|
||||
}
|
||||
[captureDesc.outputURL release];
|
||||
[captureDesc release];
|
||||
[expandedPath release];
|
||||
[path release];
|
||||
}
|
||||
} else {
|
||||
[captureMgr startCaptureWithDevice: getMTLDevice()];
|
||||
}
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
startAutoGPUCapture(MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE, getMTLDevice());
|
||||
|
||||
MVKLogInfo("Created VkDevice to run on GPU %s with the following %d Vulkan extensions enabled:%s",
|
||||
_pProperties->deviceName,
|
||||
@ -4104,9 +4127,7 @@ MVKDevice::~MVKDevice() {
|
||||
[_globalVisibilityResultMTLBuffer release];
|
||||
[_defaultMTLSamplerState release];
|
||||
|
||||
if (mvkGetMVKConfiguration()->autoGPUCaptureScope == MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE) {
|
||||
[[MTLCaptureManager sharedCaptureManager] stopCapture];
|
||||
}
|
||||
stopAutoGPUCapture(MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE);
|
||||
|
||||
mvkDestroyContainerContents(_privateDataSlots);
|
||||
}
|
||||
|
@ -252,6 +252,7 @@ public:
|
||||
|
||||
protected:
|
||||
id<MTLCommandBuffer> getMTLCommandBuffer();
|
||||
void stopAutoGPUCapture();
|
||||
|
||||
MVKSmallVector<MVKPresentTimingInfo, 4> _presentInfo;
|
||||
};
|
||||
|
@ -199,6 +199,8 @@ void MVKQueue::initGPUCaptureScopes() {
|
||||
_submissionCaptureScope->makeDefault();
|
||||
}
|
||||
_submissionCaptureScope->beginScope(); // Allow Xcode to capture the first frame if desired.
|
||||
|
||||
getDevice()->startAutoGPUCapture(MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME, _mtlQueue);
|
||||
}
|
||||
|
||||
MVKQueue::~MVKQueue() {
|
||||
@ -398,6 +400,7 @@ void MVKQueuePresentSurfaceSubmission::execute() {
|
||||
auto cs = _queue->_submissionCaptureScope;
|
||||
cs->endScope();
|
||||
cs->beginScope();
|
||||
stopAutoGPUCapture();
|
||||
|
||||
this->destroy();
|
||||
}
|
||||
@ -409,6 +412,14 @@ id<MTLCommandBuffer> MVKQueuePresentSurfaceSubmission::getMTLCommandBuffer() {
|
||||
return mtlCmdBuff;
|
||||
}
|
||||
|
||||
void MVKQueuePresentSurfaceSubmission::stopAutoGPUCapture() {
|
||||
const MVKConfiguration* pMVKConfig = mvkGetMVKConfiguration();
|
||||
if (_queue->_queueFamily->getIndex() == pMVKConfig->defaultGPUCaptureScopeQueueFamilyIndex &&
|
||||
_queue->_index == pMVKConfig->defaultGPUCaptureScopeQueueIndex) {
|
||||
_queue->getDevice()->stopAutoGPUCapture(MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME);
|
||||
}
|
||||
}
|
||||
|
||||
MVKQueuePresentSurfaceSubmission::MVKQueuePresentSurfaceSubmission(MVKQueue* queue,
|
||||
const VkPresentInfoKHR* pPresentInfo)
|
||||
: MVKQueueSubmission(queue, pPresentInfo->waitSemaphoreCount, pPresentInfo->pWaitSemaphores) {
|
||||
|
@ -224,6 +224,7 @@ void mvkSetMVKConfiguration(MVKConfiguration* pMVKConfig);
|
||||
*/
|
||||
#define MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE 0
|
||||
#define MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE 1
|
||||
#define MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME 2
|
||||
#ifndef MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE
|
||||
# define MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user