From 8c0bbfbbf53e2ff1453ebba8dd319883fc73e39a Mon Sep 17 00:00:00 2001 From: Jeff Vigil Date: Mon, 25 Nov 2019 14:48:11 -0800 Subject: [PATCH] EGL: Implement EGL_ANDROID_framebuffer_target Add attribute to configs. Add attribute matching logic. Does not set attribute in Vulkan configs, need solution to query Android for which formats are valid. anglebug.com/4208 New end2end test. Bug: angleproject:3961 Test: angle_end2end_tests --gtest_filter=EGLAndroidFramebufferTargetTest* Change-Id: I7e14c47b39e9539f6181c3c1d75c76fe63ca0f8c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1960508 Reviewed-by: Jamie Madill Reviewed-by: Courtney Goeltzenleuchter Commit-Queue: Mohan Maiya --- .../GL_EGL_WGL_loader.json | 2 +- .../GL_EGL_entry_points.json | 2 +- .../GLenum_value_to_string_map.json | 2 +- .../code_generation_hashes/proc_table.json | 2 +- scripts/registry_xml.py | 1 + src/libANGLE/Caps.cpp | 1 + src/libANGLE/Caps.h | 3 + src/libANGLE/Config.cpp | 6 +- src/libANGLE/Config.h | 3 + src/libANGLE/queryutils.cpp | 3 + src/libANGLE/renderer/gl/egl/DisplayEGL.cpp | 2 + src/libANGLE/renderer/vulkan/DisplayVk.cpp | 3 + src/libANGLE/validationEGL.cpp | 7 ++ src/tests/angle_end2end_tests.gni | 1 + .../EGLAndroidFrameBufferTargetTest.cpp | 90 +++++++++++++++++++ src/tests/egl_tests/EGLPrintEGLinfoTest.cpp | 16 +++- 16 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 src/tests/egl_tests/EGLAndroidFrameBufferTargetTest.cpp diff --git a/scripts/code_generation_hashes/GL_EGL_WGL_loader.json b/scripts/code_generation_hashes/GL_EGL_WGL_loader.json index f0b8e7f3b48..a07d919958c 100644 --- a/scripts/code_generation_hashes/GL_EGL_WGL_loader.json +++ b/scripts/code_generation_hashes/GL_EGL_WGL_loader.json @@ -6,7 +6,7 @@ "scripts/generate_loader.py": "48c60c668bec42a80378179aae2acc61", "scripts/registry_xml.py": - "78a90e53e3170645d2e24a9998cc7b16", + "e817317edf2899585efcd8e521dcb23e", "scripts/wgl.xml": "aa96419c582af2f6673430e2847693f4", "src/libEGL/egl_loader_autogen.cpp": diff --git a/scripts/code_generation_hashes/GL_EGL_entry_points.json b/scripts/code_generation_hashes/GL_EGL_entry_points.json index 278f26f1b0b..ce1078a2e10 100644 --- a/scripts/code_generation_hashes/GL_EGL_entry_points.json +++ b/scripts/code_generation_hashes/GL_EGL_entry_points.json @@ -12,7 +12,7 @@ "scripts/gl_angle_ext.xml": "d6907cd84d95ac0b32a164194eadcf53", "scripts/registry_xml.py": - "78a90e53e3170645d2e24a9998cc7b16", + "e817317edf2899585efcd8e521dcb23e", "scripts/wgl.xml": "aa96419c582af2f6673430e2847693f4", "src/libANGLE/Context_gl_1_0_autogen.h": diff --git a/scripts/code_generation_hashes/GLenum_value_to_string_map.json b/scripts/code_generation_hashes/GLenum_value_to_string_map.json index cf1364552f9..9e00b8315e9 100644 --- a/scripts/code_generation_hashes/GLenum_value_to_string_map.json +++ b/scripts/code_generation_hashes/GLenum_value_to_string_map.json @@ -6,7 +6,7 @@ "scripts/gl_angle_ext.xml": "d6907cd84d95ac0b32a164194eadcf53", "scripts/registry_xml.py": - "78a90e53e3170645d2e24a9998cc7b16", + "e817317edf2899585efcd8e521dcb23e", "src/libANGLE/gl_enum_utils_autogen.cpp": "fc023ad21e10d2279c8f14686bf838b6", "src/libANGLE/gl_enum_utils_autogen.h": diff --git a/scripts/code_generation_hashes/proc_table.json b/scripts/code_generation_hashes/proc_table.json index f832d0f78ff..522aabf6d4f 100644 --- a/scripts/code_generation_hashes/proc_table.json +++ b/scripts/code_generation_hashes/proc_table.json @@ -10,7 +10,7 @@ "scripts/gl_angle_ext.xml": "d6907cd84d95ac0b32a164194eadcf53", "scripts/registry_xml.py": - "78a90e53e3170645d2e24a9998cc7b16", + "e817317edf2899585efcd8e521dcb23e", "scripts/wgl.xml": "aa96419c582af2f6673430e2847693f4", "src/libGL/proc_table_wgl_autogen.cpp": diff --git a/scripts/registry_xml.py b/scripts/registry_xml.py index 6678eab71ee..6e0b4222a4f 100644 --- a/scripts/registry_xml.py +++ b/scripts/registry_xml.py @@ -106,6 +106,7 @@ supported_egl_extensions = [ "EGL_ANDROID_blob_cache", + "EGL_ANDROID_framebuffer_target", "EGL_ANDROID_get_frame_timestamps", "EGL_ANDROID_get_native_client_buffer", "EGL_ANDROID_native_fence_sync", diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp index 66018c9e76d..97e678522bf 100644 --- a/src/libANGLE/Caps.cpp +++ b/src/libANGLE/Caps.cpp @@ -1259,6 +1259,7 @@ std::vector DisplayExtensions::getStrings() const InsertExtensionString("EGL_ANGLE_create_context_extensions_enabled", createContextExtensionsEnabled, &extensionStrings); InsertExtensionString("EGL_ANDROID_presentation_time", presentationTime, &extensionStrings); InsertExtensionString("EGL_ANDROID_blob_cache", blobCache, &extensionStrings); + 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_ANDROID_recordable", recordable, &extensionStrings); diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h index b33b8e27ab5..1b5473a5915 100644 --- a/src/libANGLE/Caps.h +++ b/src/libANGLE/Caps.h @@ -990,6 +990,9 @@ struct DisplayExtensions // EGL_EXT_gl_colorspace_display_p3_passthrough bool glColorspaceDisplayP3Passthrough = false; + + // EGL_ANDROID_framebuffer_target + bool framebufferTargetANDROID = false; }; struct DeviceExtensions diff --git a/src/libANGLE/Config.cpp b/src/libANGLE/Config.cpp index 5cb2e57fe0e..35b1236b9a8 100644 --- a/src/libANGLE/Config.cpp +++ b/src/libANGLE/Config.cpp @@ -60,7 +60,8 @@ Config::Config() transparentBlueValue(0), optimalOrientation(0), colorComponentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT), - recordable(EGL_FALSE) + recordable(EGL_FALSE), + framebufferTarget(EGL_FALSE) // TODO: http://anglebug.com/4208 {} Config::~Config() {} @@ -360,6 +361,9 @@ std::vector ConfigSet::filter(const AttributeMap &attributeMap) case EGL_RECORDABLE_ANDROID: match = config.recordable == static_cast(attributeValue); break; + case EGL_FRAMEBUFFER_TARGET_ANDROID: + match = config.framebufferTarget == static_cast(attributeValue); + break; default: UNREACHABLE(); } diff --git a/src/libANGLE/Config.h b/src/libANGLE/Config.h index cbeea9fadc0..1f4fc27f4ae 100644 --- a/src/libANGLE/Config.h +++ b/src/libANGLE/Config.h @@ -70,6 +70,9 @@ struct Config EGLint optimalOrientation; // Optimal window surface orientation EGLenum colorComponentType; // Color component type EGLBoolean recordable; // EGL_TRUE if a surface can support recording on Android + EGLBoolean framebufferTarget; // EGL_TRUE if the config supports rendering to a ANativeWindow + // for which the buffers are passed to the HWComposer HAL as a + // framebuffer target layer. }; class ConfigSet diff --git a/src/libANGLE/queryutils.cpp b/src/libANGLE/queryutils.cpp index 2e535693916..53fbc4bd25f 100644 --- a/src/libANGLE/queryutils.cpp +++ b/src/libANGLE/queryutils.cpp @@ -3712,6 +3712,9 @@ void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value) case EGL_RECORDABLE_ANDROID: *value = config->recordable; break; + case EGL_FRAMEBUFFER_TARGET_ANDROID: + *value = config->framebufferTarget; + break; default: UNREACHABLE(); break; diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp index 1ac24cf8938..ac31b694ce7 100644 --- a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp +++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp @@ -167,6 +167,8 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const outExtensions->noConfigContext = mEGL->hasExtension("EGL_KHR_no_config_context"); + outExtensions->framebufferTargetANDROID = mEGL->hasExtension("EGL_ANDROID_framebuffer_target"); + DisplayGL::generateExtensions(outExtensions); } diff --git a/src/libANGLE/renderer/vulkan/DisplayVk.cpp b/src/libANGLE/renderer/vulkan/DisplayVk.cpp index 73de515fcb3..fd08b36c600 100644 --- a/src/libANGLE/renderer/vulkan/DisplayVk.cpp +++ b/src/libANGLE/renderer/vulkan/DisplayVk.cpp @@ -194,6 +194,9 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const outExtensions->surfacelessContext = true; outExtensions->glColorspace = getRenderer()->getFeatures().supportsSwapchainColorspace.enabled; +#if defined(ANGLE_PLATFORM_ANDROID) + outExtensions->framebufferTargetANDROID = true; +#endif // defined(ANGLE_PLATFORM_ANDROID) outExtensions->noConfigContext = true; #if defined(ANGLE_PLATFORM_GGP) diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp index 8a57fe16c02..5beff614256 100644 --- a/src/libANGLE/validationEGL.cpp +++ b/src/libANGLE/validationEGL.cpp @@ -218,6 +218,13 @@ Error ValidateConfigAttribute(const Display *display, EGLAttrib attribute) } break; + case EGL_FRAMEBUFFER_TARGET_ANDROID: + if (!display->getExtensions().framebufferTargetANDROID) + { + return EglBadAttribute() << "EGL_ANDROID_framebuffer_target is not enabled."; + } + break; + default: return EglBadAttribute() << "Unknown attribute."; } diff --git a/src/tests/angle_end2end_tests.gni b/src/tests/angle_end2end_tests.gni index aa151943239..dc7dabb425a 100644 --- a/src/tests/angle_end2end_tests.gni +++ b/src/tests/angle_end2end_tests.gni @@ -135,6 +135,7 @@ angle_end2end_tests_sources = [ "gl_tests/WebGLFramebufferTest.cpp", "gl_tests/WebGLReadOutsideFramebufferTest.cpp", "gl_tests/WEBGLVideoTextureTest.cpp", + "egl_tests/EGLAndroidFrameBufferTargetTest.cpp", "egl_tests/EGLBackwardsCompatibleContextTest.cpp", "egl_tests/EGLBlobCacheTest.cpp", "egl_tests/EGLChooseConfigTest.cpp", diff --git a/src/tests/egl_tests/EGLAndroidFrameBufferTargetTest.cpp b/src/tests/egl_tests/EGLAndroidFrameBufferTargetTest.cpp new file mode 100644 index 00000000000..1d25d0e4333 --- /dev/null +++ b/src/tests/egl_tests/EGLAndroidFrameBufferTargetTest.cpp @@ -0,0 +1,90 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// EGLAndroidFrameBufferTargetTest.cpp: +// This test verifies the extension EGL_ANDROID_framebuffer_target +// 1. When the EGLFRAME_BUFFER_TARGET_ANDROID attribute is used with eglChooseConfig +// It should match with configs according to Config selection rules and the extension +// + +#include + +#include "common/string_utils.h" +#include "test_utils/ANGLETest.h" + +using namespace angle; + +class EGLAndroidFrameBufferTargetTest : public ANGLETest +{ + protected: + EGLAndroidFrameBufferTargetTest() {} + + void testSetUp() override + { + mDisplay = getEGLWindow()->getDisplay(); + ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY); + } + + EGLDisplay mDisplay = EGL_NO_DISPLAY; +}; + +namespace +{ +EGLint GetAttrib(EGLDisplay display, EGLConfig config, EGLint attrib) +{ + EGLint value = 0; + EXPECT_EGL_TRUE(eglGetConfigAttrib(display, config, attrib, &value)); + return value; +} +} // namespace + +// Verify config matching is working. +TEST_P(EGLAndroidFrameBufferTargetTest, MatchFramebufferTargetConfigs) +{ + ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANDROID_framebuffer_target")); + + // Get all the configs + EGLint count; + EXPECT_EGL_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &count)); + EXPECT_TRUE(count > 0); + std::vector configs(count); + EXPECT_EGL_TRUE(eglGetConfigs(mDisplay, configs.data(), count, &count)); + ASSERT_EQ(configs.size(), static_cast(count)); + + // Filter out all non-framebuffertarget configs + std::vector filterConfigs(0); + for (auto config : configs) + { + if (GetAttrib(mDisplay, config, EGL_FRAMEBUFFER_TARGET_ANDROID) == EGL_TRUE) + { + filterConfigs.push_back(config); + } + } + // sort configs by increaing ID + std::sort(filterConfigs.begin(), filterConfigs.end(), [this](EGLConfig a, EGLConfig b) -> bool { + return GetAttrib(mDisplay, a, EGL_CONFIG_ID) < GetAttrib(mDisplay, b, EGL_CONFIG_ID); + }); + + // Now get configs that selection algorithm identifies + EGLint attribs[] = {EGL_FRAMEBUFFER_TARGET_ANDROID, + EGL_TRUE, + EGL_COLOR_BUFFER_TYPE, + EGL_DONT_CARE, + EGL_COLOR_COMPONENT_TYPE_EXT, + EGL_DONT_CARE, + EGL_NONE}; + EXPECT_EGL_TRUE(eglChooseConfig(mDisplay, attribs, nullptr, 0, &count)); + std::vector matchConfigs(count); + EXPECT_EGL_TRUE(eglChooseConfig(mDisplay, attribs, matchConfigs.data(), count, &count)); + matchConfigs.resize(count); + // sort configs by increasing ID + std::sort(matchConfigs.begin(), matchConfigs.end(), [this](EGLConfig a, EGLConfig b) -> bool { + return GetAttrib(mDisplay, a, EGL_CONFIG_ID) < GetAttrib(mDisplay, b, EGL_CONFIG_ID); + }); + + EXPECT_EQ(matchConfigs, filterConfigs) << "Filtered configs do not match selection Configs"; +} + +ANGLE_INSTANTIATE_TEST(EGLAndroidFrameBufferTargetTest, ES2_VULKAN(), ES3_VULKAN()); diff --git a/src/tests/egl_tests/EGLPrintEGLinfoTest.cpp b/src/tests/egl_tests/EGLPrintEGLinfoTest.cpp index 51f624520db..76b7548552d 100644 --- a/src/tests/egl_tests/EGLPrintEGLinfoTest.cpp +++ b/src/tests/egl_tests/EGLPrintEGLinfoTest.cpp @@ -28,6 +28,8 @@ class EGLPrintEGLinfoTest : public ANGLETest EGLDisplay mDisplay = EGL_NO_DISPLAY; }; +namespace +{ // Parse space separated extension string into a vector of strings std::vector ParseExtensions(const char *extensions) { @@ -63,6 +65,8 @@ const char *GetGLString(EGLint name) return value; } +} // namespace + // Print the EGL strings and extensions TEST_P(EGLPrintEGLinfoTest, PrintEGLInfo) { @@ -463,8 +467,16 @@ TEST_P(EGLPrintEGLinfoTest, PrintConfigInfo) std::cout << std::endl; // Extensions - std::cout << "\tAndroid Recordable: " << GetAttrib(mDisplay, config, EGL_RECORDABLE_ANDROID) - << std::endl; + if (IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANDROID_recordable")) + { + std::cout << "\tAndroid Recordable: " + << GetAttrib(mDisplay, config, EGL_RECORDABLE_ANDROID) << std::endl; + } + if (IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANDROID_framebuffer_target")) + { + std::cout << "\tAndroid framebuffer target: " + << GetAttrib(mDisplay, config, EGL_FRAMEBUFFER_TARGET_ANDROID) << std::endl; + } // Separator between configs std::cout << std::endl;