mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-06 02:09:55 +03:00
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:
committed by
Angle LUCI CQ
parent
d2be11634e
commit
ffbb65bc9e
@@ -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 "
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -175,6 +175,9 @@ class CommandProcessorTask
|
||||
VkPresentRegionsKHR mPresentRegions;
|
||||
std::vector<VkRectLayerKHR> mRects;
|
||||
|
||||
VkSwapchainPresentFenceInfoEXT mPresentFenceInfo;
|
||||
VkFence mPresentFence;
|
||||
|
||||
// Used by OneOffQueueSubmit
|
||||
VkCommandBuffer mOneOffCommandBufferVk;
|
||||
const Semaphore *mOneOffWaitSemaphore;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -290,6 +290,7 @@ enum class Feature
|
||||
SupportsSurfacelessQueryExtension,
|
||||
SupportsSurfaceProtectedCapabilitiesExtension,
|
||||
SupportsSurfaceProtectedSwapchains,
|
||||
SupportsSwapchainMaintenance1,
|
||||
SupportsTimestampSurfaceAttribute,
|
||||
SupportsTransformFeedbackExtension,
|
||||
SupportsVertexInputDynamicState,
|
||||
|
||||
Reference in New Issue
Block a user