Loading opengl/libs/EGL/eglApi.cpp +158 −228 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ extern char const * const gBuiltinExtensionString; extern char const * const gExtensionString; // clang-format off // Extensions implemented by the EGL wrapper. char const * const gBuiltinExtensionString = "EGL_KHR_get_all_proc_addresses " "EGL_ANDROID_presentation_time " Loading @@ -91,6 +92,7 @@ char const * const gBuiltinExtensionString = "EGL_EXT_surface_CTA861_3_metadata " ; // Whitelist of extensions exposed to applications if implemented in the vendor driver. char const * const gExtensionString = "EGL_KHR_image " // mandatory "EGL_KHR_image_base " // mandatory Loading Loading @@ -451,12 +453,8 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, // surfaces // ---------------------------------------------------------------------------- // Turn linear formats into corresponding sRGB formats when colorspace is // EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear // formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where // the modification isn't possible, the original dataSpace is returned. static android_dataspace modifyBufferDataspace(android_dataspace dataSpace, EGLint colorspace) { // Translates EGL color spaces to Android data spaces. static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { return HAL_DATASPACE_SRGB_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { Loading @@ -474,158 +472,106 @@ static android_dataspace modifyBufferDataspace(android_dataspace dataSpace, } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) { return HAL_DATASPACE_BT2020_PQ; } return dataSpace; } // stripAttributes is used by eglCreateWindowSurface, eglCreatePbufferSurface // and eglCreatePixmapSurface to clean up color space related Window parameters // that a driver does not advertise support for. // Return true if stripped_attrib_list has stripped contents. static EGLBoolean stripAttributes(egl_display_ptr dp, const EGLint* attrib_list, EGLint format, std::vector<EGLint>& stripped_attrib_list) { std::vector<EGLint> allowedColorSpaces; bool haveColorSpaceSupport = dp->haveExtension("EGL_KHR_gl_colorspace"); switch (format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: // RGB_888 is never returned by getNativePixelFormat, but is included here for completeness. case HAL_PIXEL_FORMAT_RGB_888: if (haveColorSpaceSupport) { // Spec says: // [fn1] Only OpenGL and OpenGL ES contexts which support sRGB // rendering must respect requests for EGL_GL_COLORSPACE_SRGB_KHR, and // only to sRGB formats supported by the context (normally just SRGB8) // Older versions not supporting sRGB rendering will ignore this // surface attribute. // // We support sRGB and pixel format is SRGB8, so allow // the EGL_GL_COLORSPACE_SRGB_KHR and // EGL_GL_COLORSPACE_LINEAR_KHR // colorspaces to be specified. allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); } if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_linear")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); return HAL_DATASPACE_UNKNOWN; } // 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) { 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")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); } if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_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_bt2020_pq")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); "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")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); } break; case HAL_PIXEL_FORMAT_RGBA_FP16: case HAL_PIXEL_FORMAT_RGBA_1010102: case HAL_PIXEL_FORMAT_RGB_565: // Future: if driver supports XXXX extension, we can pass down that colorspace default: break; } if (!attrib_list) return false; bool stripped = false; for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) { switch (attr[0]) { case EGL_GL_COLORSPACE_KHR: { EGLint colorSpace = attr[1]; bool found = false; // Verify that color space is allowed for (auto it : allowedColorSpaces) { if (colorSpace == it) { found = true; } } if (found) { // Found supported attribute stripped_attrib_list.push_back(attr[0]); stripped_attrib_list.push_back(attr[1]); } else if (!haveColorSpaceSupport) { // Device does not support colorspace extension // pass on the attribute and let downstream // components validate like normal stripped_attrib_list.push_back(attr[0]); stripped_attrib_list.push_back(attr[1]); } else { // Found supported attribute that driver does not // support, strip it. stripped = true; // 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")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT); } if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_pq")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); } break; default: stripped_attrib_list.push_back(attr[0]); stripped_attrib_list.push_back(attr[1]); // 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")) { colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); } return colorSpaces; } // Cleans up color space related parameters that the driver does not understand. // 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, 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; *colorSpace = attr[1]; // Strip the attribute if the driver doesn't understand it. copyAttribute = false; std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format); for (auto driverColorSpace : driverColorSpaces) { if (attr[1] == driverColorSpace) { copyAttribute = true; break; } } // Make sure there is at least one attribute if (stripped) { stripped_attrib_list.push_back(EGL_NONE); } return stripped; if (copyAttribute) { strippedAttribList->push_back(attr[0]); strippedAttribList->push_back(attr[1]); } static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window, const EGLint* attrib_list, EGLint& colorSpace, android_dataspace& dataSpace) { colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; dataSpace = HAL_DATASPACE_UNKNOWN; if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { if (*attr == EGL_GL_COLORSPACE_KHR) { colorSpace = attr[1]; bool found = false; bool verify = true; // Verify that color space is allowed if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) { // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace // is available, so no need to verify. found = true; verify = false; } else if (colorSpace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_BT2020_PQ_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_display_p3_linear")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_display_p3")) { found = true; } if (!found) { return false; } if (verify && window) { bool wide_color_support = true; // Terminate the attribute list. strippedAttribList->push_back(EGL_NONE); // If the passed color space has wide color gamut, check whether the target native window // supports wide color. const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR; if (window && !colorSpaceIsNarrow) { bool windowSupportsWideColor = true; // Ordinarily we'd put a call to native_window_get_wide_color_support // at the beginning of the function so that we'll have the // result when needed elsewhere in the function. Loading @@ -635,35 +581,26 @@ static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType wi // if the application has specifically asked for wide-color we avoid // the deadlock with SurfaceFlinger since it will not ask for a // wide-color surface. int err = native_window_get_wide_color_support(window, &wide_color_support); int err = native_window_get_wide_color_support(window, &windowSupportsWideColor); if (err) { ALOGE("getColorSpaceAttribute: invalid window (win=%p) " ALOGE("processAttributes: invalid window (win=%p) " "failed (%#x) (already connected to another API?)", window, err); return false; } if (!wide_color_support) { 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; } } // Only change the dataSpace from default if the application // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute. dataSpace = modifyBufferDataspace(dataSpace, colorSpace); } } } return true; } static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list, EGLint& colorSpace, android_dataspace& dataSpace) { return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace); } void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) { // Gets the native pixel format corrsponding to the passed EGLConfig. void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, android_pixel_format* format) { // Set the native window's buffers format to match what this config requests. // Whether to use sRGB gamma is not part of the EGLconfig, but is part // of our native format. So if sRGB gamma is requested, we have to Loading Loading @@ -697,27 +634,27 @@ void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig confi // endif if (a == 0) { if (colorDepth <= 16) { format = HAL_PIXEL_FORMAT_RGB_565; *format = HAL_PIXEL_FORMAT_RGB_565; } else { if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { if (colorDepth > 24) { format = HAL_PIXEL_FORMAT_RGBA_1010102; *format = HAL_PIXEL_FORMAT_RGBA_1010102; } else { format = HAL_PIXEL_FORMAT_RGBX_8888; *format = HAL_PIXEL_FORMAT_RGBX_8888; } } else { format = HAL_PIXEL_FORMAT_RGBA_FP16; *format = HAL_PIXEL_FORMAT_RGBA_FP16; } } } else { if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { if (colorDepth > 24) { format = HAL_PIXEL_FORMAT_RGBA_1010102; *format = HAL_PIXEL_FORMAT_RGBA_1010102; } else { format = HAL_PIXEL_FORMAT_RGBA_8888; *format = HAL_PIXEL_FORMAT_RGBA_8888; } } else { format = HAL_PIXEL_FORMAT_RGBA_FP16; *format = HAL_PIXEL_FORMAT_RGBA_FP16; } } } Loading Loading @@ -758,8 +695,6 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { EGLDisplay iDpy = dp->disp.dpy; if (!window) { return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } Loading @@ -778,25 +713,21 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); } EGLint format; getNativePixelFormat(iDpy, cnx, config, format); EGLDisplay iDpy = dp->disp.dpy; android_pixel_format format; getNativePixelFormat(iDpy, cnx, config, &format); // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace; android_dataspace dataSpace; if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) { EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, window, format, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } std::vector<EGLint> strippedAttribList; if (stripAttributes(dp, attrib_list, format, strippedAttribList)) { // Had to modify the attribute list due to use of color space. // Use modified list from here on. attrib_list = strippedAttribList.data(); } if (format != 0) { { int err = native_window_set_buffers_format(window, format); if (err != 0) { ALOGE("error setting native window pixel format: %s (%d)", Loading @@ -806,7 +737,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } } if (dataSpace != 0) { 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)", Loading Loading @@ -844,14 +776,20 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); EGLint colorSpace; android_dataspace dataSpace; if (dp) { EGLDisplay iDpy = dp->disp.dpy; android_pixel_format format; getNativePixelFormat(iDpy, cnx, config, &format); // now select a corresponding sRGB format if needed if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } attrib_list = strippedAttribList.data(); EGLSurface surface = cnx->egl.eglCreatePixmapSurface( dp->disp.dpy, config, pixmap, attrib_list); Loading @@ -872,26 +810,18 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { EGLDisplay iDpy = dp->disp.dpy; EGLint format; getNativePixelFormat(iDpy, cnx, config, format); android_pixel_format format; getNativePixelFormat(iDpy, cnx, config, &format); // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace; android_dataspace dataSpace; if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { // Select correct colorspace based on user's attribute list EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } // Pbuffers are not displayed so we don't need to store the // colorspace. We do need to filter out color spaces the // driver doesn't know how to process. std::vector<EGLint> strippedAttribList; if (stripAttributes(dp, attrib_list, format, strippedAttribList)) { // Had to modify the attribute list due to use of color space. // Use modified list from here on. attrib_list = strippedAttribList.data(); } EGLSurface surface = cnx->egl.eglCreatePbufferSurface( dp->disp.dpy, config, attrib_list); Loading opengl/libs/EGL/egl_display.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -206,12 +206,16 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { mExtensionString = gBuiltinExtensionString; hasColorSpaceSupport = findExtension(disp.queryString.extensions, "EGL_KHR_gl_colorspace"); // Note: CDD requires that devices supporting wide color and/or HDR color also support // the EGL_KHR_gl_colorspace extension. bool wideColorBoardConfig = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>( false); // Add wide-color extensions if device can support wide-color if (wideColorBoardConfig) { if (wideColorBoardConfig && hasColorSpaceSupport) { mExtensionString.append( "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear " "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 "); Loading @@ -220,7 +224,7 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { bool hasHdrBoardConfig = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false); if (hasHdrBoardConfig) { if (hasHdrBoardConfig && hasColorSpaceSupport) { // hasHDRBoardConfig indicates the system is capable of supporting HDR content. // Typically that means there is an HDR capable display attached, but could be // support for attaching an HDR display. In either case, advertise support for Loading opengl/libs/EGL/egl_display.h +1 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ public: DisplayImpl disp; bool finishOnSwap; // property: debug.egl.finish bool traceGpuCompletion; // property: debug.egl.traceGpuCompletion bool hasColorSpaceSupport; private: friend class egl_display_ptr; Loading Loading
opengl/libs/EGL/eglApi.cpp +158 −228 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ extern char const * const gBuiltinExtensionString; extern char const * const gExtensionString; // clang-format off // Extensions implemented by the EGL wrapper. char const * const gBuiltinExtensionString = "EGL_KHR_get_all_proc_addresses " "EGL_ANDROID_presentation_time " Loading @@ -91,6 +92,7 @@ char const * const gBuiltinExtensionString = "EGL_EXT_surface_CTA861_3_metadata " ; // Whitelist of extensions exposed to applications if implemented in the vendor driver. char const * const gExtensionString = "EGL_KHR_image " // mandatory "EGL_KHR_image_base " // mandatory Loading Loading @@ -451,12 +453,8 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, // surfaces // ---------------------------------------------------------------------------- // Turn linear formats into corresponding sRGB formats when colorspace is // EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear // formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where // the modification isn't possible, the original dataSpace is returned. static android_dataspace modifyBufferDataspace(android_dataspace dataSpace, EGLint colorspace) { // Translates EGL color spaces to Android data spaces. static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { return HAL_DATASPACE_SRGB_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { Loading @@ -474,158 +472,106 @@ static android_dataspace modifyBufferDataspace(android_dataspace dataSpace, } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) { return HAL_DATASPACE_BT2020_PQ; } return dataSpace; } // stripAttributes is used by eglCreateWindowSurface, eglCreatePbufferSurface // and eglCreatePixmapSurface to clean up color space related Window parameters // that a driver does not advertise support for. // Return true if stripped_attrib_list has stripped contents. static EGLBoolean stripAttributes(egl_display_ptr dp, const EGLint* attrib_list, EGLint format, std::vector<EGLint>& stripped_attrib_list) { std::vector<EGLint> allowedColorSpaces; bool haveColorSpaceSupport = dp->haveExtension("EGL_KHR_gl_colorspace"); switch (format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: // RGB_888 is never returned by getNativePixelFormat, but is included here for completeness. case HAL_PIXEL_FORMAT_RGB_888: if (haveColorSpaceSupport) { // Spec says: // [fn1] Only OpenGL and OpenGL ES contexts which support sRGB // rendering must respect requests for EGL_GL_COLORSPACE_SRGB_KHR, and // only to sRGB formats supported by the context (normally just SRGB8) // Older versions not supporting sRGB rendering will ignore this // surface attribute. // // We support sRGB and pixel format is SRGB8, so allow // the EGL_GL_COLORSPACE_SRGB_KHR and // EGL_GL_COLORSPACE_LINEAR_KHR // colorspaces to be specified. allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); } if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_linear")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); return HAL_DATASPACE_UNKNOWN; } // 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) { 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")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); } if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_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_bt2020_pq")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); "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")) { allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); } break; case HAL_PIXEL_FORMAT_RGBA_FP16: case HAL_PIXEL_FORMAT_RGBA_1010102: case HAL_PIXEL_FORMAT_RGB_565: // Future: if driver supports XXXX extension, we can pass down that colorspace default: break; } if (!attrib_list) return false; bool stripped = false; for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) { switch (attr[0]) { case EGL_GL_COLORSPACE_KHR: { EGLint colorSpace = attr[1]; bool found = false; // Verify that color space is allowed for (auto it : allowedColorSpaces) { if (colorSpace == it) { found = true; } } if (found) { // Found supported attribute stripped_attrib_list.push_back(attr[0]); stripped_attrib_list.push_back(attr[1]); } else if (!haveColorSpaceSupport) { // Device does not support colorspace extension // pass on the attribute and let downstream // components validate like normal stripped_attrib_list.push_back(attr[0]); stripped_attrib_list.push_back(attr[1]); } else { // Found supported attribute that driver does not // support, strip it. stripped = true; // 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")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT); } if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_pq")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); } break; default: stripped_attrib_list.push_back(attr[0]); stripped_attrib_list.push_back(attr[1]); // 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")) { colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); } return colorSpaces; } // Cleans up color space related parameters that the driver does not understand. // 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, 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; *colorSpace = attr[1]; // Strip the attribute if the driver doesn't understand it. copyAttribute = false; std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format); for (auto driverColorSpace : driverColorSpaces) { if (attr[1] == driverColorSpace) { copyAttribute = true; break; } } // Make sure there is at least one attribute if (stripped) { stripped_attrib_list.push_back(EGL_NONE); } return stripped; if (copyAttribute) { strippedAttribList->push_back(attr[0]); strippedAttribList->push_back(attr[1]); } static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window, const EGLint* attrib_list, EGLint& colorSpace, android_dataspace& dataSpace) { colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; dataSpace = HAL_DATASPACE_UNKNOWN; if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { if (*attr == EGL_GL_COLORSPACE_KHR) { colorSpace = attr[1]; bool found = false; bool verify = true; // Verify that color space is allowed if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) { // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace // is available, so no need to verify. found = true; verify = false; } else if (colorSpace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_BT2020_PQ_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_display_p3_linear")) { found = true; } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT && dp->haveExtension("EGL_EXT_gl_colorspace_display_p3")) { found = true; } if (!found) { return false; } if (verify && window) { bool wide_color_support = true; // Terminate the attribute list. strippedAttribList->push_back(EGL_NONE); // If the passed color space has wide color gamut, check whether the target native window // supports wide color. const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR; if (window && !colorSpaceIsNarrow) { bool windowSupportsWideColor = true; // Ordinarily we'd put a call to native_window_get_wide_color_support // at the beginning of the function so that we'll have the // result when needed elsewhere in the function. Loading @@ -635,35 +581,26 @@ static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType wi // if the application has specifically asked for wide-color we avoid // the deadlock with SurfaceFlinger since it will not ask for a // wide-color surface. int err = native_window_get_wide_color_support(window, &wide_color_support); int err = native_window_get_wide_color_support(window, &windowSupportsWideColor); if (err) { ALOGE("getColorSpaceAttribute: invalid window (win=%p) " ALOGE("processAttributes: invalid window (win=%p) " "failed (%#x) (already connected to another API?)", window, err); return false; } if (!wide_color_support) { 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; } } // Only change the dataSpace from default if the application // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute. dataSpace = modifyBufferDataspace(dataSpace, colorSpace); } } } return true; } static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list, EGLint& colorSpace, android_dataspace& dataSpace) { return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace); } void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) { // Gets the native pixel format corrsponding to the passed EGLConfig. void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, android_pixel_format* format) { // Set the native window's buffers format to match what this config requests. // Whether to use sRGB gamma is not part of the EGLconfig, but is part // of our native format. So if sRGB gamma is requested, we have to Loading Loading @@ -697,27 +634,27 @@ void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig confi // endif if (a == 0) { if (colorDepth <= 16) { format = HAL_PIXEL_FORMAT_RGB_565; *format = HAL_PIXEL_FORMAT_RGB_565; } else { if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { if (colorDepth > 24) { format = HAL_PIXEL_FORMAT_RGBA_1010102; *format = HAL_PIXEL_FORMAT_RGBA_1010102; } else { format = HAL_PIXEL_FORMAT_RGBX_8888; *format = HAL_PIXEL_FORMAT_RGBX_8888; } } else { format = HAL_PIXEL_FORMAT_RGBA_FP16; *format = HAL_PIXEL_FORMAT_RGBA_FP16; } } } else { if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { if (colorDepth > 24) { format = HAL_PIXEL_FORMAT_RGBA_1010102; *format = HAL_PIXEL_FORMAT_RGBA_1010102; } else { format = HAL_PIXEL_FORMAT_RGBA_8888; *format = HAL_PIXEL_FORMAT_RGBA_8888; } } else { format = HAL_PIXEL_FORMAT_RGBA_FP16; *format = HAL_PIXEL_FORMAT_RGBA_FP16; } } } Loading Loading @@ -758,8 +695,6 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { EGLDisplay iDpy = dp->disp.dpy; if (!window) { return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } Loading @@ -778,25 +713,21 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); } EGLint format; getNativePixelFormat(iDpy, cnx, config, format); EGLDisplay iDpy = dp->disp.dpy; android_pixel_format format; getNativePixelFormat(iDpy, cnx, config, &format); // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace; android_dataspace dataSpace; if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) { EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, window, format, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } std::vector<EGLint> strippedAttribList; if (stripAttributes(dp, attrib_list, format, strippedAttribList)) { // Had to modify the attribute list due to use of color space. // Use modified list from here on. attrib_list = strippedAttribList.data(); } if (format != 0) { { int err = native_window_set_buffers_format(window, format); if (err != 0) { ALOGE("error setting native window pixel format: %s (%d)", Loading @@ -806,7 +737,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } } if (dataSpace != 0) { 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)", Loading Loading @@ -844,14 +776,20 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); EGLint colorSpace; android_dataspace dataSpace; if (dp) { EGLDisplay iDpy = dp->disp.dpy; android_pixel_format format; getNativePixelFormat(iDpy, cnx, config, &format); // now select a corresponding sRGB format if needed if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } attrib_list = strippedAttribList.data(); EGLSurface surface = cnx->egl.eglCreatePixmapSurface( dp->disp.dpy, config, pixmap, attrib_list); Loading @@ -872,26 +810,18 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { EGLDisplay iDpy = dp->disp.dpy; EGLint format; getNativePixelFormat(iDpy, cnx, config, format); android_pixel_format format; getNativePixelFormat(iDpy, cnx, config, &format); // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace; android_dataspace dataSpace; if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { // Select correct colorspace based on user's attribute list EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } // Pbuffers are not displayed so we don't need to store the // colorspace. We do need to filter out color spaces the // driver doesn't know how to process. std::vector<EGLint> strippedAttribList; if (stripAttributes(dp, attrib_list, format, strippedAttribList)) { // Had to modify the attribute list due to use of color space. // Use modified list from here on. attrib_list = strippedAttribList.data(); } EGLSurface surface = cnx->egl.eglCreatePbufferSurface( dp->disp.dpy, config, attrib_list); Loading
opengl/libs/EGL/egl_display.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -206,12 +206,16 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { mExtensionString = gBuiltinExtensionString; hasColorSpaceSupport = findExtension(disp.queryString.extensions, "EGL_KHR_gl_colorspace"); // Note: CDD requires that devices supporting wide color and/or HDR color also support // the EGL_KHR_gl_colorspace extension. bool wideColorBoardConfig = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>( false); // Add wide-color extensions if device can support wide-color if (wideColorBoardConfig) { if (wideColorBoardConfig && hasColorSpaceSupport) { mExtensionString.append( "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear " "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 "); Loading @@ -220,7 +224,7 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { bool hasHdrBoardConfig = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false); if (hasHdrBoardConfig) { if (hasHdrBoardConfig && hasColorSpaceSupport) { // hasHDRBoardConfig indicates the system is capable of supporting HDR content. // Typically that means there is an HDR capable display attached, but could be // support for attaching an HDR display. In either case, advertise support for Loading
opengl/libs/EGL/egl_display.h +1 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ public: DisplayImpl disp; bool finishOnSwap; // property: debug.egl.finish bool traceGpuCompletion; // property: debug.egl.traceGpuCompletion bool hasColorSpaceSupport; private: friend class egl_display_ptr; Loading