Merge pull request #1090 from billhollings/drawable-present

Move Metal drawable presentation from MTLCommandBuffer to MTLDrawable.
This commit is contained in:
Bill Hollings 2020-10-05 17:33:45 -04:00 committed by GitHub
commit 38c4921b69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 54 deletions

View File

@ -21,6 +21,8 @@ Released TBD
- Use `VK_KHR_image_format_list` to disable `MTLTextureUsagePixelFormatView`
if only swizzles or `sRGB` conversion will be used for image views, improving
performance on *iOS* by allowing Metal to use lossless texture compression.
- Move *Metal* drawable presentation from `MTLCommandBuffer` to `MTLDrawable`
to improve performance and reduce blocking.

View File

@ -429,6 +429,14 @@ typedef struct MVKSwapchainImageAvailability {
bool operator< (const MVKSwapchainImageAvailability& rhs) const;
} MVKSwapchainImageAvailability;
/** VK_GOOGLE_display_timing extension info */
typedef struct {
MVKPresentableSwapchainImage* presentableImage;
bool hasPresentTime; // Keep track of whether presentation included VK_GOOGLE_display_timing
uint32_t presentID; // VK_GOOGLE_display_timing presentID
uint64_t desiredPresentTime; // VK_GOOGLE_display_timing desired presentation time in nanoseconds
} MVKPresentTimingInfo;
/** Tracks a semaphore and fence for later signaling. */
typedef std::pair<MVKSemaphore*, MVKFence*> MVKSwapchainSignaler;
@ -440,15 +448,9 @@ public:
#pragma mark Metal
/**
* Presents the contained drawable to the OS, releases the Metal drawable and its
* texture back to the Metal layer's pool, and makes the image memory available for new use.
*
* If mtlCmdBuff is not nil, the contained drawable is scheduled for presentation using
* the presentDrawable: method of the command buffer. If mtlCmdBuff is nil, the contained
* drawable is presented immediately using the present method of the drawable.
*/
void presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff, bool hasPresentTime, uint32_t presentID, uint64_t desiredPresentTime);
/** Presents the contained drawable to the OS. */
void presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff,
MVKPresentTimingInfo presentTimingInfo);
#pragma mark Construction
@ -465,6 +467,7 @@ protected:
friend MVKSwapchain;
id<CAMetalDrawable> getCAMetalDrawable() override;
void presentCAMetalDrawable(MVKPresentTimingInfo presentTimingInfo);
void releaseMetalDrawable();
MVKSwapchainImageAvailability getAvailability();
void makeAvailable();

View File

@ -1287,52 +1287,53 @@ id<CAMetalDrawable> MVKPresentableSwapchainImage::getCAMetalDrawable() {
}
// Present the drawable and make myself available only once the command buffer has completed.
void MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff, bool hasPresentTime, uint32_t presentID, uint64_t desiredPresentTime) {
void MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff,
MVKPresentTimingInfo presentTimingInfo) {
_swapchain->willPresentSurface(getMTLTexture(0), mtlCmdBuff);
NSString* scName = _swapchain->getDebugName();
if (scName) { mvkPushDebugGroup(mtlCmdBuff, scName); }
if (!hasPresentTime) {
[mtlCmdBuff presentDrawable: getCAMetalDrawable()];
}
else {
// Convert from nsecs to seconds
CFTimeInterval presentTimeSeconds = ( double ) desiredPresentTime * 1.0e-9;
[mtlCmdBuff presentDrawable: getCAMetalDrawable() atTime:(CFTimeInterval)presentTimeSeconds];
}
if (scName) { mvkPopDebugGroup(mtlCmdBuff); }
[mtlCmdBuff addScheduledHandler: ^(id<MTLCommandBuffer> mcb) {
presentCAMetalDrawable(presentTimingInfo);
}];
signalPresentationSemaphore(mtlCmdBuff);
retain(); // Ensure this image is not destroyed while awaiting MTLCommandBuffer completion
// Ensure this image is not destroyed while awaiting MTLCommandBuffer completion
retain();
[mtlCmdBuff addCompletedHandler: ^(id<MTLCommandBuffer> mcb) {
makeAvailable();
release();
}];
if (hasPresentTime) {
signalPresentationSemaphore(mtlCmdBuff);
}
// If MTLDrawable.presentedTime/addPresentedHandler isn't supported.
// Treat it as if the present happened when requested.
void MVKPresentableSwapchainImage::presentCAMetalDrawable(MVKPresentTimingInfo presentTimingInfo) {
id<CAMetalDrawable> mtlDrwbl = getCAMetalDrawable();
if (presentTimingInfo.hasPresentTime) {
// Convert from nsecs to seconds for Metal
[mtlDrwbl presentAtTime: (double)presentTimingInfo.desiredPresentTime * 1.0e-9];
#if MVK_OS_SIMULATOR
// If MTLDrawable.presentedTime/addPresentedHandler isn't supported, just treat it as if the
// present happened when requested
_swapchain->recordPresentTime(presentID, desiredPresentTime, desiredPresentTime);
_swapchain->recordPresentTime(presentTimingInfo);
#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);
if ([mtlDrwbl respondsToSelector: @selector(addPresentedHandler:)]) {
// Ensure this image is not destroyed while awaiting presentation
retain();
[mtlDrwbl addPresentedHandler: ^(id<MTLDrawable> drawable) {
_swapchain->recordPresentTime(presentTimingInfo, drawable.presentedTime * 1.0e9);
release();
}];
} else {
// If MTLDrawable.presentedTime/addPresentedHandler isn't supported, just treat it as if the
// present happened when requested
_swapchain->recordPresentTime(presentID, desiredPresentTime, desiredPresentTime);
_swapchain->recordPresentTime(presentTimingInfo);
}
#endif
} else {
[mtlDrwbl present];
}
}
// Resets the MTLTexture and CAMetalDrawable underlying this image.

View File

@ -255,13 +255,6 @@ public:
protected:
id<MTLCommandBuffer> getMTLCommandBuffer();
typedef struct {
MVKPresentableSwapchainImage* presentableImage;
bool hasPresentTime; // Keep track of whether present included VK_GOOGLE_display_timing
uint32_t presentID; // VK_GOOGLE_display_timing presentID
uint64_t desiredPresentTime; // VK_GOOGLE_display_timing desired presentation time in nanoseconds
} PresentInfo;
MVKSmallVector<PresentInfo, 4> _presentInfo;
MVKSmallVector<MVKPresentTimingInfo, 4> _presentInfo;
};

View File

@ -353,7 +353,7 @@ void MVKQueuePresentSurfaceSubmission::execute() {
for (auto& ws : _waitSemaphores) { ws->encodeWait(mtlCmdBuff); }
for (int i = 0; i < _presentInfo.size(); i++ ) {
MVKPresentableSwapchainImage *img = _presentInfo[i].presentableImage;
img->presentCAMetalDrawable(mtlCmdBuff, _presentInfo[i].hasPresentTime, _presentInfo[i].presentID, _presentInfo[i].desiredPresentTime);
img->presentCAMetalDrawable(mtlCmdBuff, _presentInfo[i]);
}
for (auto& ws : _waitSemaphores) { ws->encodeWait(nil); }
[mtlCmdBuff commit];
@ -401,7 +401,7 @@ MVKQueuePresentSurfaceSubmission::MVKQueuePresentSurfaceSubmission(MVKQueue* que
_presentInfo.reserve(scCnt);
for (uint32_t scIdx = 0; scIdx < scCnt; scIdx++) {
MVKSwapchain* mvkSC = (MVKSwapchain*)pPresentInfo->pSwapchains[scIdx];
PresentInfo presentInfo = {};
MVKPresentTimingInfo presentInfo = {};
presentInfo.presentableImage = mvkSC->getPresentableImage(pPresentInfo->pImageIndices[scIdx]);
if ( pPresentTimesGOOGLE ) {
presentInfo.hasPresentTime = true;

View File

@ -113,7 +113,7 @@ protected:
void willPresentSurface(id<MTLTexture> mtlTexture, id<MTLCommandBuffer> mtlCmdBuff);
void renderWatermark(id<MTLTexture> mtlTexture, id<MTLCommandBuffer> mtlCmdBuff);
void markFrameInterval();
void recordPresentTime(uint32_t presentID, uint64_t desiredPresentTime, uint64_t actualPresentTime);
void recordPresentTime(MVKPresentTimingInfo presentTimingInfo, uint64_t actualPresentTime = 0);
CAMetalLayer* _mtlLayer;
MVKWatermark* _licenseWatermark;

View File

@ -434,7 +434,7 @@ VkResult MVKSwapchain::getPastPresentationTiming(uint32_t *pCount, VkPastPresent
return VK_SUCCESS;
}
void MVKSwapchain::recordPresentTime(uint32_t presentID, uint64_t desiredPresentTime, uint64_t actualPresentTime) {
void MVKSwapchain::recordPresentTime(MVKPresentTimingInfo presentTimingInfo, uint64_t actualPresentTime) {
std::lock_guard<std::mutex> lock(_presentHistoryLock);
if (_presentHistoryCount < kMaxPresentationHistory) {
_presentHistoryCount++;
@ -442,8 +442,12 @@ void MVKSwapchain::recordPresentTime(uint32_t presentID, uint64_t desiredPresent
} else {
_presentHistoryHeadIndex = (_presentHistoryHeadIndex + 1) % kMaxPresentationHistory;
}
_presentTimingHistory[_presentHistoryIndex].presentID = presentID;
_presentTimingHistory[_presentHistoryIndex].desiredPresentTime = desiredPresentTime;
// If actual time not supplied, use desired time instead
if (actualPresentTime == 0) { actualPresentTime = presentTimingInfo.desiredPresentTime; }
_presentTimingHistory[_presentHistoryIndex].presentID = presentTimingInfo.presentID;
_presentTimingHistory[_presentHistoryIndex].desiredPresentTime = presentTimingInfo.desiredPresentTime;
_presentTimingHistory[_presentHistoryIndex].actualPresentTime = actualPresentTime;
// These details are not available in Metal
_presentTimingHistory[_presentHistoryIndex].earliestPresentTime = actualPresentTime;