Vulkan: Use VK_EXT_swapchain_maintenance1 for present fences

Bug: angleproject:7878
Change-Id: Ic3a43c663789a6489cff261848d9ad4a408ca53a
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4088905
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Ian Elliott <ianelliott@google.com>
This commit is contained in:
Shahbaz Youssefi
2022-11-28 13:31:48 -05:00
committed by Angle LUCI CQ
parent d2be11634e
commit ffbb65bc9e
12 changed files with 126 additions and 17 deletions

View File

@@ -812,6 +812,12 @@ struct FeaturesVk : FeatureSetBase
"VK_KHR_maintenance2",
&members, "https://anglebug.com/7899"};
FeatureInfo supportsSwapchainMaintenance1 = {
"supportsSwapchainMaintenance1", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_EXT_surface_maintenance1 and VK_EXT_swapchain_maintenance1 "
"extensions",
&members, "https://anglebug.com/7847"};
FeatureInfo preferSubmitOnAnySamplesPassedQueryEnd = {
"preferSubmitOnAnySamplesPassedQueryEnd", FeatureCategory::VulkanWorkarounds,
"Submit commands to driver when last GL_ANY_SAMPLES_PASSED query is made for performance "

View File

@@ -1100,6 +1100,14 @@
],
"issue": "https://anglebug.com/7899"
},
{
"name": "supports_swapchain_maintenance1",
"category": "Features",
"description": [
"VkDevice supports the VK_EXT_surface_maintenance1 and VK_EXT_swapchain_maintenance1 extensions"
],
"issue": "https://anglebug.com/7847"
},
{
"name": "prefer_submit_on_any_samples_passed_query_end",
"category": "Workarounds",

View File

@@ -6,7 +6,7 @@
"include/platform/FeaturesMtl_autogen.h":
"3f51c002af713c0ef4629c6c6000cb14",
"include/platform/FeaturesVk_autogen.h":
"74dc5f09084196d74c203646aa221645",
"4481f1e1198695596fceeb8152022529",
"include/platform/FrontendFeatures_autogen.h":
"e8ba29b617e21fe318bf7e3c0aa5b071",
"include/platform/d3d_features.json":
@@ -20,9 +20,9 @@
"include/platform/mtl_features.json":
"ab0dce486f4188a22683b375a6c60961",
"include/platform/vk_features.json":
"0915d2e171c000ea2147e59c894233e2",
"5266e522142d92061527d3d1ff2ecc09",
"util/angle_features_autogen.cpp":
"c737309060d3dee61f4e1c8831161101",
"bfb4b454546153645e258a099b64daaf",
"util/angle_features_autogen.h":
"422006a12916d8393d8d9ebec28560bf"
"207859237fc40bada16a9a5368c861f3"
}

View File

@@ -191,6 +191,7 @@ void CommandProcessorTask::initTask()
mPresentInfo.pImageIndices = nullptr;
mPresentInfo.pNext = nullptr;
mPresentInfo.pWaitSemaphores = nullptr;
mPresentFence = VK_NULL_HANDLE;
mOneOffCommandBufferVk = VK_NULL_HANDLE;
mPriority = egl::ContextPriority::Medium;
mHasProtectedContent = false;
@@ -224,7 +225,7 @@ void CommandProcessorTask::copyPresentInfo(const VkPresentInfoKHR &other)
}
mPresentInfo.sType = other.sType;
mPresentInfo.pNext = other.pNext;
mPresentInfo.pNext = nullptr;
if (other.swapchainCount > 0)
{
@@ -268,8 +269,23 @@ void CommandProcessorTask::copyPresentInfo(const VkPresentInfoKHR &other)
mPresentRegions.pNext = presentRegions->pNext;
mPresentRegions.swapchainCount = 1;
mPresentRegions.pRegions = &mPresentRegion;
mPresentInfo.pNext = &mPresentRegions;
pNext = const_cast<void *>(presentRegions->pNext);
AddToPNextChain(&mPresentInfo, &mPresentRegions);
pNext = const_cast<void *>(presentRegions->pNext);
break;
}
case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT:
{
const VkSwapchainPresentFenceInfoEXT *presentFenceInfo =
reinterpret_cast<VkSwapchainPresentFenceInfoEXT *>(pNext);
ASSERT(presentFenceInfo->swapchainCount == 1);
mPresentFence = presentFenceInfo->pFences[0];
mPresentFenceInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT;
mPresentFenceInfo.pNext = nullptr;
mPresentFenceInfo.swapchainCount = 1;
mPresentFenceInfo.pFences = &mPresentFence;
AddToPNextChain(&mPresentInfo, &mPresentFenceInfo);
pNext = const_cast<void *>(presentFenceInfo->pNext);
break;
}
default:

View File

@@ -175,6 +175,9 @@ class CommandProcessorTask
VkPresentRegionsKHR mPresentRegions;
std::vector<VkRectLayerKHR> mRects;
VkSwapchainPresentFenceInfoEXT mPresentFenceInfo;
VkFence mPresentFence;
// Used by OneOffQueueSubmit
VkCommandBuffer mOneOffCommandBufferVk;
const Semaphore *mOneOffWaitSemaphore;

View File

@@ -1563,6 +1563,11 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
}
if (ExtensionFound(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, instanceExtensionNames))
{
mEnabledInstanceExtensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
}
if (ExtensionFound(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, instanceExtensionNames))
{
mEnabledInstanceExtensions.push_back(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME);
@@ -2020,6 +2025,10 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
mRasterizationOrderAttachmentAccessFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT;
mSwapchainMaintenance1FeaturesEXT = {};
mSwapchainMaintenance1FeaturesEXT.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT;
mDrmProperties = {};
mDrmProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT;
@@ -2233,6 +2242,11 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
vk::AddToPNextChain(&deviceFeatures, &mRasterizationOrderAttachmentAccessFeatures);
}
if (ExtensionFound(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mSwapchainMaintenance1FeaturesEXT);
}
if (ExtensionFound(VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceProperties, &mDrmProperties);
@@ -2280,6 +2294,7 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
mPipelineRobustnessFeatures.pNext = nullptr;
mPipelineProtectedAccessFeatures.pNext = nullptr;
mRasterizationOrderAttachmentAccessFeatures.pNext = nullptr;
mSwapchainMaintenance1FeaturesEXT.pNext = nullptr;
mDrmProperties.pNext = nullptr;
}
@@ -2855,6 +2870,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
vk::AddToPNextChain(&mEnabledFeatures, &mRasterizationOrderAttachmentAccessFeatures);
}
if (getFeatures().supportsSwapchainMaintenance1.enabled)
{
vk::AddToPNextChain(&mEnabledFeatures, &mSwapchainMaintenance1FeaturesEXT);
}
mCurrentQueueFamilyIndex = queueFamilyIndex;
vk::QueueFamily queueFamily;
@@ -3912,6 +3932,16 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
mRasterizationOrderAttachmentAccessFeatures.rasterizationOrderColorAttachmentAccess ==
VK_TRUE);
// The VK_EXT_surface_maintenance1 and VK_EXT_swapchain_maintenance1 extensions are used for a
// variety of improvements:
//
// - Recycling present semaphores
// - Avoiding swapchain recreation when present modes change
// - Amortizing the cost of memory allocation for swapchain creation over multiple frames
//
ANGLE_FEATURE_CONDITION(&mFeatures, supportsSwapchainMaintenance1,
mSwapchainMaintenance1FeaturesEXT.swapchainMaintenance1 == VK_TRUE);
// http://anglebug.com/6872
// On ARM hardware, framebuffer-fetch-like behavior on Vulkan is already coherent, so we can
// expose the coherent version of the GL extension despite unofficial Vulkan support.

View File

@@ -812,6 +812,7 @@ class RendererVk : angle::NonCopyable
VkPhysicalDevicePipelineProtectedAccessFeaturesEXT mPipelineProtectedAccessFeatures;
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT
mRasterizationOrderAttachmentAccessFeatures;
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT mSwapchainMaintenance1FeaturesEXT;
VkPhysicalDeviceDrmPropertiesEXT mDrmProperties;
angle::PackedEnumBitSet<gl::ShadingRate, uint8_t> mSupportedFragmentShadingRates;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;

View File

@@ -1872,7 +1872,20 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
presentRegions.swapchainCount = 1;
presentRegions.pRegions = &presentRegion;
presentInfo.pNext = &presentRegions;
vk::AddToPNextChain(&presentInfo, &presentRegions);
}
VkSwapchainPresentFenceInfoEXT presentFenceInfo = {};
vk::Fence presentFence;
if (contextVk->getFeatures().supportsSwapchainMaintenance1.enabled)
{
ANGLE_VK_TRY(contextVk, NewFence(contextVk, &mPresentFenceRecycler, &presentFence));
presentFenceInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT;
presentFenceInfo.swapchainCount = 1;
presentFenceInfo.pFences = presentFence.ptr();
vk::AddToPNextChain(&presentInfo, &presentFenceInfo);
}
ASSERT(mAcquireImageSemaphore == nullptr);
@@ -1887,7 +1900,18 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
mPresentHistory.emplace_back();
mPresentHistory.back().semaphore = std::move(presentSemaphore);
mPresentHistory.back().oldSwapchains = std::move(mOldSwapchains);
mPresentHistory.back().imageIndex = mCurrentSwapchainImageIndex;
if (contextVk->getFeatures().supportsSwapchainMaintenance1.enabled)
{
mPresentHistory.back().imageIndex = kInvalidImageIndex;
mPresentHistory.back().fence = std::move(presentFence);
}
else
{
// The fence needed to know when the semaphore can be recycled will be one that is passed to
// vkAcquireNextImageKHR that returns the same image index. That is why the image index
// needs to be tracked in this case.
mPresentHistory.back().imageIndex = mCurrentSwapchainImageIndex;
}
// Clean up whatever present is already finished.
ANGLE_TRY(cleanUpPresentHistory(contextVk));
@@ -1964,7 +1988,7 @@ angle::Result WindowSurfaceVk::cleanUpPresentHistory(vk::Context *context)
impl::ImagePresentOperation presentOperation = std::move(mPresentHistory.front());
mPresentHistory.pop_front();
// We can't be stuck on an a presentation to an old swapchain without a fence.
// We can't be stuck on a presentation to an old swapchain without a fence.
ASSERT(presentOperation.imageIndex != kInvalidImageIndex);
// Move clean up data to the next (now first) present operation, if any. Note that there
@@ -2138,13 +2162,18 @@ VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
// vkAcquireNextImageKHR, it's actually about the present operation. There is currently no way
// to associate the fence with the present operation itself, so this is a hack.
vk::Fence presentFence;
VkResult result = NewFence(context, &mPresentFenceRecycler, &presentFence);
if (result != VK_SUCCESS)
const bool presentFenceInferredFromAcquire =
!context->getFeatures().supportsSwapchainMaintenance1.enabled;
if (presentFenceInferredFromAcquire)
{
return result;
const VkResult result = NewFence(context, &mPresentFenceRecycler, &presentFence);
if (result != VK_SUCCESS)
{
return result;
}
}
result =
VkResult result =
vkAcquireNextImageKHR(device, mSwapchain, UINT64_MAX, acquireImageSemaphore->getHandle(),
presentFence.getHandle(), &mCurrentSwapchainImageIndex);
@@ -2152,13 +2181,19 @@ VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
if (ANGLE_UNLIKELY(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR))
{
// On failure, the fence is going to be untouched, so it can be recycled right away.
mPresentFenceRecycler.recycle(std::move(presentFence));
if (presentFenceInferredFromAcquire)
{
mPresentFenceRecycler.recycle(std::move(presentFence));
}
return result;
}
// Associate the present fence with the last present operation.
AssociateFenceWithPresentHistory(mCurrentSwapchainImageIndex, std::move(presentFence),
&mPresentHistory);
if (presentFenceInferredFromAcquire)
{
AssociateFenceWithPresentHistory(mCurrentSwapchainImageIndex, std::move(presentFence),
&mPresentHistory);
}
SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];

View File

@@ -169,6 +169,8 @@ struct ImagePresentOperation : angle::NonCopyable
std::vector<SwapchainCleanupData> oldSwapchains;
// Used to associate an acquire fence with the previous present operation of the image.
// Only relevant when VK_EXT_swapchain_maintenance1 is not supported; otherwise a fence is
// always associated with the present operation.
uint32_t imageIndex;
};

View File

@@ -89,3 +89,9 @@ could be recreated while there are pending old swapchains to be destroyed. The
old swapchains must now be deferred to when the first QP of the new swapchain has been processed.
If an application resizes the window constantly and at a high rate, ANGLE would keep accumulating
old swapchains and not free them until it stops.
## VK_EXT_swapchain_maintenance1
With the VK_EXT_swapchain_maintenance1, all the above is unnecessary. Each QP operation can have an
associated fence, which can be used to know when the semaphore associated with it can be recycled.
The old swapchains can be destroyed at the same time as before.

View File

@@ -312,6 +312,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{
{Feature::SupportsSurfaceProtectedCapabilitiesExtension,
"supportsSurfaceProtectedCapabilitiesExtension"},
{Feature::SupportsSurfaceProtectedSwapchains, "supportsSurfaceProtectedSwapchains"},
{Feature::SupportsSwapchainMaintenance1, "supportsSwapchainMaintenance1"},
{Feature::SupportsTimestampSurfaceAttribute, "supportsTimestampSurfaceAttribute"},
{Feature::SupportsTransformFeedbackExtension, "supportsTransformFeedbackExtension"},
{Feature::SupportsVertexInputDynamicState, "supportsVertexInputDynamicState"},

View File

@@ -290,6 +290,7 @@ enum class Feature
SupportsSurfacelessQueryExtension,
SupportsSurfaceProtectedCapabilitiesExtension,
SupportsSurfaceProtectedSwapchains,
SupportsSwapchainMaintenance1,
SupportsTimestampSurfaceAttribute,
SupportsTransformFeedbackExtension,
SupportsVertexInputDynamicState,