mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
Vulkan: Add support for setting timestamp surface attribute
On Android the EGL wrapper handles most of the functionality required by EGL_ANDROID_get_frame_timestamps. However if for some reason the swapchain is recreated, the timestamp state would be lost resulting in stuttering. Introduce EGL_ANGLE_timestamp_surface_attribute extension that adds support for toggling the EGL_TIMESTAMPS_ANDROID attribute of a surface. Cache this state and recreate the swapchain accordingly. Bug: angleproject:7489 Test: EGLSurfaceTest.TimestampSurfaceAttribute* Test: dEQP-EGL.functional.get_frame_timestamps* Change-Id: I3660f7137c006d904164d243a682a4ff520eabd8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3753396 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Ian Elliott <ianelliott@google.com> Commit-Queue: mohan maiya <m.maiya@samsung.com>
This commit is contained in:
committed by
Angle LUCI CQ
parent
f10625d3cc
commit
aa2a558ec2
95
extensions/EGL_ANGLE_timestamp_surface_attribute.txt
Normal file
95
extensions/EGL_ANGLE_timestamp_surface_attribute.txt
Normal file
@@ -0,0 +1,95 @@
|
||||
Name
|
||||
|
||||
ANGLE_timestamp_surface_attribute
|
||||
|
||||
Name Strings
|
||||
|
||||
EGL_ANGLE_timestamp_surface_attribute
|
||||
|
||||
Contributors
|
||||
|
||||
Mohan Maiya
|
||||
Ian Elliot
|
||||
|
||||
Contacts
|
||||
|
||||
Mohan Maiya, Samsung (m.maiya 'at' samsung 'dot' com)
|
||||
|
||||
Notice
|
||||
|
||||
Copyright (c) 2022 The Khronos Group Inc. Copyright terms at
|
||||
http://www.khronos.org/registry/speccopyright.html
|
||||
|
||||
Status
|
||||
|
||||
Draft.
|
||||
|
||||
Version
|
||||
|
||||
Version 1, July 12, 2022
|
||||
|
||||
Number
|
||||
|
||||
EGL Extension ###
|
||||
|
||||
Dependencies
|
||||
|
||||
Requires support for EGL_ANDROID_get_frame_timestamps extension.
|
||||
Refer to EGL_ANDROID_get_frame_timestamps specification for other
|
||||
dependencies.
|
||||
|
||||
Overview
|
||||
|
||||
On Android most of the functionality required by EGL_ANDROID_get_frame_timestamps
|
||||
is handled by a wrapper outside of the EGL driver. However it is necessary
|
||||
to be aware of EGL_TIMESTAMPS_ANDROID state on some drivers
|
||||
(like ANGLE, which layers GLES APIs over Vulkan, which needs this information
|
||||
to setup Vulkan swapchains appropriately).
|
||||
|
||||
This extension allows ANGLE's EGL implementation to rely on the Android EGL
|
||||
loader to support and implement the EGL_ANDROID_get_frame_timestamps extension,
|
||||
with the exception that ANGLE's EGL implementation will support caching
|
||||
EGL_TIMESTAMPS_ANDROID state.
|
||||
|
||||
For details about EGL_TIMESTAMPS_ANDROID and other timestamp related terminology
|
||||
please refer to the EGL_ANDROID_get_frame_timestamps specification.
|
||||
|
||||
|
||||
New Types
|
||||
|
||||
None.
|
||||
|
||||
New Procedures and Functions
|
||||
|
||||
None.
|
||||
|
||||
New Tokens
|
||||
|
||||
None.
|
||||
|
||||
For clarity, restating the section of EGL_ANDROID_get_frame_timestamps specification
|
||||
that will be supported by this extension:
|
||||
|
||||
Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
|
||||
"Surface Attributes", page 43:
|
||||
|
||||
If attribute is EGL_TIMESTAMPS_ANDROID, then values specifies whether to
|
||||
enable/disable timestamp collection for this surface. A value of EGL_TRUE
|
||||
enables timestamp collection, while a value of EGL_FALSE disables it. The
|
||||
initial value is false. If surface is not a window surface this has no
|
||||
effect.
|
||||
|
||||
Issues
|
||||
|
||||
None.
|
||||
|
||||
Revision History
|
||||
|
||||
#2 - (August 23, 2022) Mohan Maiya
|
||||
Added language to clarify that the extension will require support,
|
||||
from an external module, of the EGL_ANDROID_get_frame_timestamps
|
||||
extension for the most part with the exception of providing support
|
||||
for caching EGL_TIMESTAMPS_ANDROID state.
|
||||
|
||||
#1 - (July 12, 2022) Mohan Maiya
|
||||
Original draft
|
||||
@@ -687,11 +687,9 @@ struct FeaturesVk : FeatureSetBase
|
||||
"http://anglebug.com/7553"};
|
||||
|
||||
FeatureInfo preferLinearFilterForYUV = {
|
||||
"preferLinearFilterForYUV",
|
||||
FeatureCategory::VulkanFeatures,
|
||||
"Prefer to use VK_FILTER_LINEAR for VkSamplerYcbcrConversion",
|
||||
&members,
|
||||
};
|
||||
"preferLinearFilterForYUV", FeatureCategory::VulkanFeatures,
|
||||
"Prefer to use VK_FILTER_LINEAR for VkSamplerYcbcrConversion", &members,
|
||||
"https://anglebug.com/7382"};
|
||||
|
||||
FeatureInfo supportsYuvTarget = {
|
||||
"supportsYuvTarget",
|
||||
@@ -713,6 +711,11 @@ struct FeaturesVk : FeatureSetBase
|
||||
"spaces",
|
||||
&members,
|
||||
};
|
||||
|
||||
FeatureInfo supportsTimestampSurfaceAttribute = {
|
||||
"supportsTimestampSurfaceAttribute", FeatureCategory::VulkanFeatures,
|
||||
"Platform supports setting frame timestamp surface attribute", &members,
|
||||
"https://anglebug.com/7489"};
|
||||
};
|
||||
|
||||
inline FeaturesVk::FeaturesVk() = default;
|
||||
|
||||
@@ -933,7 +933,8 @@
|
||||
"category": "Features",
|
||||
"description": [
|
||||
"Prefer to use VK_FILTER_LINEAR for VkSamplerYcbcrConversion"
|
||||
]
|
||||
],
|
||||
"issue": "https://anglebug.com/7382"
|
||||
},
|
||||
{
|
||||
"name": "supports_yuv_target",
|
||||
@@ -958,6 +959,14 @@
|
||||
"Use VK_COLOR_SPACE_PASS_THROUGH_EXT for EGL_NONE or unspecifed color ",
|
||||
"spaces"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "supports_timestamp_surface_attribute",
|
||||
"category": "Features",
|
||||
"description": [
|
||||
"Platform supports setting frame timestamp surface attribute"
|
||||
],
|
||||
"issue": "https://anglebug.com/7489"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"include/platform/FeaturesMtl_autogen.h":
|
||||
"6b6d49c35bc9246361f8dac0a5445a02",
|
||||
"include/platform/FeaturesVk_autogen.h":
|
||||
"c7a1f002d5309d937136394bc698eaad",
|
||||
"c9c02b6fa5cca1c79b6a247dc66d311c",
|
||||
"include/platform/FrontendFeatures_autogen.h":
|
||||
"834af301a444786b363a1005c80e1f53",
|
||||
"include/platform/d3d_features.json":
|
||||
@@ -20,9 +20,9 @@
|
||||
"include/platform/mtl_features.json":
|
||||
"1fabfe4d5c2eb3683a5b567ab60ad83c",
|
||||
"include/platform/vk_features.json":
|
||||
"2cdaa09ec1457cf65147c4e104c0978d",
|
||||
"a0e1f206156a4562886362b1aeb38a49",
|
||||
"util/angle_features_autogen.cpp":
|
||||
"b666b866b5ced187639a1c9db2c47b51",
|
||||
"5ac11ec0033f29fd8a8475658a1f24fa",
|
||||
"util/angle_features_autogen.h":
|
||||
"40154ba910574b9eff2310addf557b9b"
|
||||
"c1b1c0fc7a7ccd997403857b1e6f204f"
|
||||
}
|
||||
@@ -153,6 +153,9 @@ extern PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT
|
||||
extern PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR;
|
||||
extern PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR;
|
||||
|
||||
// VK_GOOGLE_display_timing
|
||||
extern PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE;
|
||||
|
||||
} // namespace rx
|
||||
|
||||
#endif // ANGLE_SHARED_LIBVULKAN
|
||||
|
||||
@@ -1276,6 +1276,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
|
||||
InsertExtensionString("EGL_ANDROID_framebuffer_target", framebufferTargetANDROID, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANDROID_image_native_buffer", imageNativeBuffer, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANDROID_get_frame_timestamps", getFrameTimestamps, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANGLE_timestamp_surface_attribute", timestampSurfaceAttributeANGLE, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANDROID_recordable", recordable, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANGLE_power_preference", powerPreference, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANGLE_image_d3d11_texture", imageD3D11Texture, &extensionStrings);
|
||||
|
||||
@@ -554,6 +554,9 @@ struct DisplayExtensions
|
||||
// EGL_ANDROID_get_frame_timestamps
|
||||
bool getFrameTimestamps = false;
|
||||
|
||||
// EGL_ANGLE_timestamp_surface_attribute
|
||||
bool timestampSurfaceAttributeANGLE = false;
|
||||
|
||||
// EGL_ANDROID_recordable
|
||||
bool recordable = false;
|
||||
|
||||
|
||||
@@ -352,6 +352,9 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
|
||||
getRenderer()->getFeatures().supportsLockSurfaceExtension.enabled;
|
||||
|
||||
outExtensions->partialUpdateKHR = true;
|
||||
|
||||
outExtensions->timestampSurfaceAttributeANGLE =
|
||||
getRenderer()->getFeatures().supportsTimestampSurfaceAttribute.enabled;
|
||||
}
|
||||
|
||||
void DisplayVk::generateCaps(egl::Caps *outCaps) const
|
||||
|
||||
@@ -2454,6 +2454,15 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
|
||||
mEnabledDeviceExtensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
if (getFeatures().supportsTimestampSurfaceAttribute.enabled)
|
||||
{
|
||||
mEnabledDeviceExtensions.push_back(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME);
|
||||
#if !defined(ANGLE_SHARED_LIBVULKAN)
|
||||
InitGetPastPresentationTimingGoogleFunction(mDevice);
|
||||
#endif // !defined(ANGLE_SHARED_LIBVULKAN)
|
||||
ASSERT(vkGetPastPresentationTimingGOOGLE);
|
||||
}
|
||||
|
||||
std::sort(mEnabledDeviceExtensions.begin(), mEnabledDeviceExtensions.end(), StrLess);
|
||||
ANGLE_VK_TRY(displayVk,
|
||||
VerifyExtensionsPresent(deviceExtensionNames, mEnabledDeviceExtensions));
|
||||
@@ -3811,6 +3820,13 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
|
||||
// Only enable it on integrations without EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID passthrough.
|
||||
ANGLE_FEATURE_CONDITION(&mFeatures, forceContinuousRefreshOnSharedPresent, false);
|
||||
|
||||
// Enable setting frame timestamp surface attribute on Android platform.
|
||||
// Frame timestamp is enabled by calling into "vkGetPastPresentationTimingGOOGLE"
|
||||
// which, on Android platforms, makes the necessary ANativeWindow API calls.
|
||||
ANGLE_FEATURE_CONDITION(&mFeatures, supportsTimestampSurfaceAttribute,
|
||||
IsAndroid() && ExtensionFound(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
|
||||
deviceExtensionNames));
|
||||
|
||||
ApplyFeatureOverrides(&mFeatures, displayVk->getState());
|
||||
|
||||
// Disable async command queue when using Vulkan secondary command buffers temporarily to avoid
|
||||
|
||||
@@ -1397,6 +1397,17 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
|
||||
mSwapchain = newSwapChain;
|
||||
mSwapchainPresentMode = mDesiredSwapchainPresentMode;
|
||||
|
||||
// If frame timestamp was enabled for the surface, [re]enable it when [re]creating the swapchain
|
||||
if (renderer->getFeatures().supportsTimestampSurfaceAttribute.enabled &&
|
||||
mState.timestampsEnabled)
|
||||
{
|
||||
// The implementation of "vkGetPastPresentationTimingGOOGLE" on Android calls into the
|
||||
// appropriate ANativeWindow API that enables frame timestamps.
|
||||
uint32_t count = 0;
|
||||
ANGLE_VK_TRY(context,
|
||||
vkGetPastPresentationTimingGOOGLE(device, mSwapchain, &count, nullptr));
|
||||
}
|
||||
|
||||
// Initialize the swapchain image views.
|
||||
uint32_t imageCount = 0;
|
||||
ANGLE_VK_TRY(context, vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, nullptr));
|
||||
@@ -1953,6 +1964,12 @@ bool WindowSurfaceVk::hasStagedUpdates() const
|
||||
return mSwapchainImages[mCurrentSwapchainImageIndex].image.hasStagedUpdatesInAllocatedLevels();
|
||||
}
|
||||
|
||||
void WindowSurfaceVk::setTimestampsEnabled(bool enabled)
|
||||
{
|
||||
// The frontend has already cached the state, nothing to do.
|
||||
ASSERT(IsAndroid());
|
||||
}
|
||||
|
||||
void WindowSurfaceVk::deferAcquireNextImage()
|
||||
{
|
||||
mNeedToAcquireNextSwapchainImage = true;
|
||||
|
||||
@@ -301,6 +301,8 @@ class WindowSurfaceVk : public SurfaceVk
|
||||
|
||||
bool hasStagedUpdates() const;
|
||||
|
||||
void setTimestampsEnabled(bool enabled) override;
|
||||
|
||||
protected:
|
||||
angle::Result prepareSwapImpl(const gl::Context *context);
|
||||
angle::Result swapImpl(const gl::Context *context,
|
||||
|
||||
@@ -1038,6 +1038,9 @@ PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT = null
|
||||
PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR = nullptr;
|
||||
PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR = nullptr;
|
||||
|
||||
// VK_GOOGLE_display_timing
|
||||
PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE = nullptr;
|
||||
|
||||
void InitDebugUtilsEXTFunctions(VkInstance instance)
|
||||
{
|
||||
GET_INSTANCE_FUNC(vkCreateDebugUtilsMessengerEXT);
|
||||
@@ -1194,6 +1197,12 @@ void InitFragmentShadingRateKHRFunctions(VkDevice device)
|
||||
GET_DEVICE_FUNC(vkCmdSetFragmentShadingRateKHR);
|
||||
}
|
||||
|
||||
// VK_GOOGLE_display_timing
|
||||
void InitGetPastPresentationTimingGoogleFunction(VkDevice device)
|
||||
{
|
||||
GET_DEVICE_FUNC(vkGetPastPresentationTimingGOOGLE);
|
||||
}
|
||||
|
||||
# undef GET_INSTANCE_FUNC
|
||||
# undef GET_DEVICE_FUNC
|
||||
|
||||
|
||||
@@ -1031,6 +1031,9 @@ void InitExtendedDynamicState2EXTFunctions(VkDevice device);
|
||||
// VK_KHR_fragment_shading_rate
|
||||
void InitFragmentShadingRateKHRFunctions(VkDevice device);
|
||||
|
||||
// VK_GOOGLE_display_timing
|
||||
void InitGetPastPresentationTimingGoogleFunction(VkDevice device);
|
||||
|
||||
#endif // !defined(ANGLE_SHARED_LIBVULKAN)
|
||||
|
||||
GLenum CalculateGenerateMipmapFilter(ContextVk *contextVk, angle::FormatID formatID);
|
||||
|
||||
@@ -5358,7 +5358,8 @@ bool ValidateSurfaceAttrib(const ValidationContext *val,
|
||||
break;
|
||||
|
||||
case EGL_TIMESTAMPS_ANDROID:
|
||||
if (!display->getExtensions().getFrameTimestamps)
|
||||
if (!display->getExtensions().getFrameTimestamps &&
|
||||
!display->getExtensions().timestampSurfaceAttributeANGLE)
|
||||
{
|
||||
val->setError(EGL_BAD_ATTRIBUTE,
|
||||
"EGL_TIMESTAMPS_ANDROID cannot be used without "
|
||||
@@ -5507,7 +5508,8 @@ bool ValidateQuerySurface(const ValidationContext *val,
|
||||
break;
|
||||
|
||||
case EGL_TIMESTAMPS_ANDROID:
|
||||
if (!display->getExtensions().getFrameTimestamps)
|
||||
if (!display->getExtensions().getFrameTimestamps &&
|
||||
!display->getExtensions().timestampSurfaceAttributeANGLE)
|
||||
{
|
||||
val->setError(EGL_BAD_ATTRIBUTE,
|
||||
"EGL_TIMESTAMPS_ANDROID cannot be used without "
|
||||
|
||||
@@ -1642,6 +1642,66 @@ TEST_P(EGLSurfaceTest, CreateSurfaceSwapIntervalANGLE)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that setting a surface's timestamp attribute works when the extension
|
||||
// EGL_ANGLE_timestamp_surface_attribute is supported.
|
||||
TEST_P(EGLSurfaceTest, TimestampSurfaceAttribute)
|
||||
{
|
||||
initializeDisplay();
|
||||
ASSERT_NE(mDisplay, EGL_NO_DISPLAY);
|
||||
mConfig = chooseDefaultConfig(true);
|
||||
ASSERT_NE(mConfig, nullptr);
|
||||
initializeSurface(mConfig);
|
||||
ASSERT_NE(mWindowSurface, EGL_NO_SURFACE);
|
||||
initializeContext();
|
||||
ASSERT_NE(mContext, EGL_NO_CONTEXT);
|
||||
|
||||
EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext));
|
||||
ASSERT_EGL_SUCCESS() << "eglMakeCurrent failed.";
|
||||
|
||||
const bool extensionSupported =
|
||||
IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANDROID_get_frame_timestamps") ||
|
||||
IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANGLE_timestamp_surface_attribute");
|
||||
|
||||
EGLBoolean setSurfaceAttrib =
|
||||
eglSurfaceAttrib(mDisplay, mWindowSurface, EGL_TIMESTAMPS_ANDROID, EGL_TRUE);
|
||||
|
||||
if (extensionSupported)
|
||||
{
|
||||
EXPECT_EGL_TRUE(setSurfaceAttrib);
|
||||
|
||||
// Swap so the swapchain gets created.
|
||||
glClearColor(1.0, 1.0, 1.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
EXPECT_EGL_TRUE(eglSwapBuffers(mDisplay, mWindowSurface));
|
||||
|
||||
// Query to confirm the attribute persists across swaps.
|
||||
EGLint timestampEnabled = 0;
|
||||
EXPECT_EGL_TRUE(
|
||||
eglQuerySurface(mDisplay, mWindowSurface, EGL_TIMESTAMPS_ANDROID, ×tampEnabled));
|
||||
EXPECT_NE(timestampEnabled, 0);
|
||||
|
||||
// Resize window and swap.
|
||||
mOSWindow->resize(256, 256);
|
||||
glClearColor(1.0, 1.0, 1.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
EXPECT_EGL_TRUE(eglSwapBuffers(mDisplay, mWindowSurface));
|
||||
|
||||
// Query to confirm the attribute persists across swapchain recreations.
|
||||
timestampEnabled = 0;
|
||||
EXPECT_EGL_TRUE(
|
||||
eglQuerySurface(mDisplay, mWindowSurface, EGL_TIMESTAMPS_ANDROID, ×tampEnabled));
|
||||
EXPECT_NE(timestampEnabled, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EGL_FALSE(setSurfaceAttrib);
|
||||
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
|
||||
}
|
||||
|
||||
EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
|
||||
ASSERT_EGL_SUCCESS() << "eglMakeCurrent - uncurrent failed.";
|
||||
}
|
||||
|
||||
TEST_P(EGLSingleBufferTest, OnCreateWindowSurface)
|
||||
{
|
||||
EGLConfig config = EGL_NO_CONFIG_KHR;
|
||||
|
||||
@@ -277,6 +277,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{
|
||||
{Feature::SupportsSurfaceProtectedCapabilitiesExtension,
|
||||
"supportsSurfaceProtectedCapabilitiesExtension"},
|
||||
{Feature::SupportsSurfaceProtectedSwapchains, "supportsSurfaceProtectedSwapchains"},
|
||||
{Feature::SupportsTimestampSurfaceAttribute, "supportsTimestampSurfaceAttribute"},
|
||||
{Feature::SupportsTransformFeedbackExtension, "supportsTransformFeedbackExtension"},
|
||||
{Feature::SupportsYUVSamplerConversion, "supportsYUVSamplerConversion"},
|
||||
{Feature::SupportsYuvTarget, "supportsYuvTarget"},
|
||||
|
||||
@@ -261,6 +261,7 @@ enum class Feature
|
||||
SupportsSurfacelessQueryExtension,
|
||||
SupportsSurfaceProtectedCapabilitiesExtension,
|
||||
SupportsSurfaceProtectedSwapchains,
|
||||
SupportsTimestampSurfaceAttribute,
|
||||
SupportsTransformFeedbackExtension,
|
||||
SupportsYUVSamplerConversion,
|
||||
SupportsYuvTarget,
|
||||
|
||||
Reference in New Issue
Block a user