Merge pull request #1090 from billhollings/drawable-present
Move Metal drawable presentation from MTLCommandBuffer to MTLDrawable.
This commit is contained in:
commit
38c4921b69
@ -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.
|
||||
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user