diff options
Diffstat (limited to 'opengl')
| -rw-r--r-- | opengl/libs/EGL/eglApi.cpp | 117 | ||||
| -rw-r--r-- | opengl/tests/EGLTest/Android.bp | 1 | ||||
| -rw-r--r-- | opengl/tests/EGLTest/EGL_test.cpp | 165 |
3 files changed, 220 insertions, 63 deletions
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 40adf8e229..36deedcb85 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -482,58 +482,35 @@ static EGLint getReportedColorSpace(EGLint colorspace) { } // Returns a list of color spaces understood by the vendor EGL driver. -static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp, - android_pixel_format format) { +static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp) { std::vector<EGLint> colorSpaces; - if (!dp->hasColorSpaceSupport) return colorSpaces; - - // OpenGL drivers only support sRGB encoding with 8-bit formats. - // RGB_888 is never returned by getNativePixelFormat, but is included for completeness. - const bool formatSupportsSRGBEncoding = - format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 || - format == HAL_PIXEL_FORMAT_RGB_888; - const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16; - - if (formatSupportsSRGBEncoding) { - // sRGB and linear are always supported when color space support is present. - colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); - colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); - // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats. - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_display_p3")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); - } - } - // According to the spec, scRGB is only supported for floating point formats. - // For non-linear scRGB, the application is responsible for applying the - // transfer function. - if (formatIsFloatingPoint) { - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_scrgb")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT); - } - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_scrgb_linear")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); - } - } + // sRGB and linear are always supported when color space support is present. + colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); + colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); - // BT2020 can be used with any pixel format. PQ encoding must be applied by the - // application and does not affect the behavior of OpenGL. if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_bt2020_linear")) { + "EGL_EXT_gl_colorspace_display_p3")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_scrgb")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_scrgb_linear")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_bt2020_linear")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT); } if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_bt2020_pq")) { + "EGL_EXT_gl_colorspace_bt2020_pq")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); } - - // Linear DCI-P3 simply uses different primaries than standard RGB and thus - // can be used with any pixel format. if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_display_p3_linear")) { + "EGL_EXT_gl_colorspace_display_p3_linear")) { colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); } return colorSpaces; @@ -543,19 +520,32 @@ static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp, // If there is no color space attribute in attrib_list, colorSpace is left // unmodified. static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, - android_pixel_format format, const EGLint* attrib_list, - EGLint* colorSpace, + const EGLint* attrib_list, EGLint* colorSpace, std::vector<EGLint>* strippedAttribList) { for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) { bool copyAttribute = true; if (attr[0] == EGL_GL_COLORSPACE_KHR) { - // Fail immediately if the driver doesn't have color space support at all. - if (!dp->hasColorSpaceSupport) return false; + switch (attr[1]) { + case EGL_GL_COLORSPACE_LINEAR_KHR: + case EGL_GL_COLORSPACE_SRGB_KHR: + case EGL_GL_COLORSPACE_DISPLAY_P3_EXT: + case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT: + case EGL_GL_COLORSPACE_SCRGB_EXT: + case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT: + case EGL_GL_COLORSPACE_BT2020_PQ_EXT: + case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT: + // Fail immediately if the driver doesn't have color space support at all. + if (!dp->hasColorSpaceSupport) return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); + break; + default: + // BAD_ATTRIBUTE if attr is not any of the EGL_GL_COLORSPACE_* + return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } *colorSpace = attr[1]; // Strip the attribute if the driver doesn't understand it. copyAttribute = false; - std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format); + std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp); for (auto driverColorSpace : driverColorSpaces) { if (attr[1] == driverColorSpace) { copyAttribute = true; @@ -603,12 +593,12 @@ static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, ALOGE("processAttributes: invalid window (win=%p) " "failed (%#x) (already connected to another API?)", window, err); - return false; + return setError(EGL_BAD_NATIVE_WINDOW, EGL_FALSE); } if (!windowSupportsWideColor) { // Application has asked for a wide-color colorspace but // wide-color support isn't available on the display the window is on. - return false; + return setError(EGL_BAD_MATCH, EGL_FALSE); } } return true; @@ -736,10 +726,11 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; - if (!processAttributes(dp, window, format, attrib_list, &colorSpace, + if (!processAttributes(dp, window, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); @@ -754,14 +745,14 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace); - if (dataSpace != HAL_DATASPACE_UNKNOWN) { - int err = native_window_set_buffers_data_space(window, dataSpace); - if (err != 0) { - ALOGE("error setting native window pixel dataSpace: %s (%d)", - strerror(-err), err); - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } + // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN. HAL_DATASPACE_UNKNOWN + // is the default value, but it may have changed at this point. + int err = native_window_set_buffers_data_space(window, dataSpace); + if (err != 0) { + ALOGE("error setting native window pixel dataSpace: %s (%d)", + strerror(-err), err); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } // the EGL spec requires that a new EGLSurface default to swap interval @@ -801,10 +792,10 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, // now select a corresponding sRGB format if needed EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; - if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, + if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); @@ -835,10 +826,10 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, // Select correct colorspace based on user's attribute list EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; - if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, + if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp index f246077037..a9e873ac43 100644 --- a/opengl/tests/EGLTest/Android.bp +++ b/opengl/tests/EGLTest/Android.bp @@ -25,6 +25,7 @@ cc_test { "libhidltransport", "liblog", "libutils", + "libnativewindow", ], include_dirs: [ diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index 5927dc14e8..459b1356b8 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -775,4 +775,169 @@ TEST_F(EGLTest, EGLConfig1010102) { EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); } + +TEST_F(EGLTest, EGLInvalidColorspaceAttribute) { + EGLConfig config; + + 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; + + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + ASSERT_EQ(EGL_NO_SURFACE, eglSurface); +} + +TEST_F(EGLTest, EGLUnsupportedColorspaceFormatCombo) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + const EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 16, + EGL_GREEN_SIZE, 16, + EGL_BLUE_SIZE, 16, + EGL_ALPHA_SIZE, 16, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + EGL_NONE, + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + 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; + + const EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_BAD_MATCH, eglGetError()); + ASSERT_EQ(EGL_NO_SURFACE, eglSurface); +} + +TEST_F(EGLTest, EGLCreateWindowFailAndSucceed) { + EGLConfig config; + + 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; + + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + ASSERT_EQ(EGL_NO_SURFACE, eglSurface); + + // Now recreate surface with a valid colorspace. Ensure proper cleanup is done + // in the first failed attempt (e.g. native_window_api_disconnect). + winAttrs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; + eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + +TEST_F(EGLTest, EGLCreateWindowTwoColorspaces) { + EGLConfig config; + + 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; + + const EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + android_dataspace dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get())); + ASSERT_EQ(dataspace, HAL_DATASPACE_DISPLAY_P3); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); + + // Now create with default attribute (EGL_GL_COLORSPACE_LINEAR_KHR) + eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get())); + // Make sure the dataspace has been reset to UNKNOWN + ASSERT_NE(dataspace, HAL_DATASPACE_DISPLAY_P3); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} } |