Add HDR dataspaces to EGL
bug: 63710530
Test: adb shell /data/nativetest/EGL_test/EGL_test
Test: adb -d shell am start -n \
com.drawelements.deqp/android.app.NativeActivity \
-e cmdLine '"deqp --deqp-case=dEQP-EGL.functional.hdr_color.* \
--deqp-log-filename=/sdcard/dEQP-Log.qpa"'
Change-Id: I52c43539806c901c674f037489d502d771080a30
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index b67a053..8bb74a2 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -53,7 +53,20 @@
static bool hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+static bool hasHdrDisplay =
+ getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+
+union FlexAttribute {
+ EGLint uint_value;
+ float float_value;
+};
+
class EGLTest : public ::testing::Test {
+public:
+ void get8BitConfig(EGLConfig& config);
+ void addOptionalWindowMetadata(std::vector<EGLint>& attrs);
+ void checkOptionalWindowMetadata(EGLSurface eglSurface);
+
protected:
EGLDisplay mEglDisplay;
@@ -365,6 +378,261 @@
EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
}
+void EGLTest::get8BitConfig(EGLConfig& config) {
+ EGLint numConfigs;
+ EGLBoolean success;
+
+ // Use 8-bit to keep focus on colorspace aspect
+ const EGLint attrs[] = {
+ // clang-format off
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+ EGL_NONE,
+ // clang-format on
+ };
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(1, numConfigs);
+
+ EGLint components[4];
+ EGLint value;
+ eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ // Verify component sizes on config match what was asked for.
+ EXPECT_EQ(components[0], 8);
+ EXPECT_EQ(components[1], 8);
+ EXPECT_EQ(components[2], 8);
+ EXPECT_EQ(components[3], 8);
+}
+
+void EGLTest::addOptionalWindowMetadata(std::vector<EGLint>& attrs) {
+ FlexAttribute data;
+ if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
+ attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT);
+ data.float_value = 0.640;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT);
+ data.float_value = 0.330;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT);
+ data.float_value = 0.290;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT);
+ data.float_value = 0.600;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT);
+ data.float_value = 0.150;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT);
+ data.float_value = 0.060;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_WHITE_POINT_X_EXT);
+ data.float_value = 0.3127;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_WHITE_POINT_Y_EXT);
+ data.float_value = 0.3290;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_MAX_LUMINANCE_EXT);
+ data.float_value = 300.0;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_SMPTE2086_MIN_LUMINANCE_EXT);
+ data.float_value = 0.7;
+ attrs.push_back(data.uint_value);
+ }
+
+ if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
+ attrs.push_back(EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT);
+ data.float_value = 300.0;
+ attrs.push_back(data.uint_value);
+ attrs.push_back(EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT);
+ data.float_value = 75.0;
+ attrs.push_back(data.uint_value);
+ }
+}
+
+void EGLTest::checkOptionalWindowMetadata(EGLSurface eglSurface) {
+ EGLBoolean success;
+ EGLint value;
+ FlexAttribute expected;
+
+ if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.640;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.330;
+ ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(0, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.290;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.600;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.150;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.060;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_X_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.3127;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.3290;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 300.0;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 0.7;
+ ASSERT_EQ(expected.uint_value, value);
+ }
+
+ if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 300.0;
+ ASSERT_EQ(expected.uint_value, value);
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ expected.float_value = 75.0;
+ ASSERT_EQ(expected.uint_value, value);
+ }
+}
+
+TEST_F(EGLTest, EGLBT2020Linear) {
+ EGLConfig config;
+ EGLBoolean success;
+
+ if (!hasHdrDisplay) {
+ // skip this test if device does not have HDR display
+ RecordProperty("hasHdrDisplay", false);
+ return;
+ }
+
+ // Test that bt2020 linear extension exists
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_bt2020_linear"))
+ << "EGL_EXT_gl_colorspace_bt2020_linear extension not available";
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ std::vector<EGLint> winAttrs;
+ winAttrs.push_back(EGL_GL_COLORSPACE_KHR);
+ winAttrs.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
+
+ ASSERT_NO_FATAL_FAILURE(addOptionalWindowMetadata(winAttrs));
+
+ winAttrs.push_back(EGL_NONE);
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs.data());
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ EGLint value;
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_GL_COLORSPACE_BT2020_PQ_EXT, value);
+
+ ASSERT_NO_FATAL_FAILURE(checkOptionalWindowMetadata(eglSurface));
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGLBT2020PQ) {
+ EGLConfig config;
+ EGLBoolean success;
+
+ if (!hasHdrDisplay) {
+ // skip this test if device does not have HDR display
+ RecordProperty("hasHdrDisplay", false);
+ return;
+ }
+
+ // Test that bt2020-pq extension exists
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_bt2020_pq"))
+ << "EGL_EXT_gl_colorspace_bt2020_pq extension not available";
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+ std::vector<EGLint> winAttrs;
+ winAttrs.push_back(EGL_GL_COLORSPACE_KHR);
+ winAttrs.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
+
+ ASSERT_NO_FATAL_FAILURE(addOptionalWindowMetadata(winAttrs));
+
+ winAttrs.push_back(EGL_NONE);
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs.data());
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ EGLint value;
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_GL_COLORSPACE_BT2020_PQ_EXT, value);
+
+ ASSERT_NO_FATAL_FAILURE(checkOptionalWindowMetadata(eglSurface));
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
TEST_F(EGLTest, EGLConfigFP16) {
EGLint numConfigs;
EGLConfig config;
@@ -372,13 +640,13 @@
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
- std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
+ RecordProperty("hasWideColorDisplay", false);
return;
}
ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_pixel_format_float"));
- EGLint attrs[] = {
+ const EGLint attrs[] = {
// clang-format off
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
@@ -387,7 +655,7 @@
EGL_BLUE_SIZE, 16,
EGL_ALPHA_SIZE, 16,
EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
- EGL_NONE, EGL_NONE
+ EGL_NONE,
// clang-format on
};
success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
@@ -437,7 +705,7 @@
TEST_F(EGLTest, EGLNoConfigContext) {
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
- std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
+ RecordProperty("hasWideColorDisplay", false);
return;
}
@@ -475,11 +743,11 @@
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
- std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
+ RecordProperty("hasWideColorDisplay", false);
return;
}
- EGLint attrs[] = {
+ const EGLint attrs[] = {
// clang-format off
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,