diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index ffe4ea46279ff..8bea006071bf6 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -304,12 +304,23 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * @see android.R.attr#colorMode */ public static final int COLOR_MODE_HDR = 2; + // 3 Corresponds to android::uirenderer::ColorMode::Hdr10. + /** + * Value of {@link #colorMode} indicating that the activity should use an + * 8 bit alpha buffer if the presentation display supports it. + * + * @see android.R.attr#colorMode + * @hide + */ + public static final int COLOR_MODE_A8 = 4; + /** @hide */ @IntDef(prefix = { "COLOR_MODE_" }, value = { COLOR_MODE_DEFAULT, COLOR_MODE_WIDE_COLOR_GAMUT, COLOR_MODE_HDR, + COLOR_MODE_A8, }) @Retention(RetentionPolicy.SOURCE) public @interface ColorMode {} @@ -1682,6 +1693,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { return "COLOR_MODE_WIDE_COLOR_GAMUT"; case COLOR_MODE_HDR: return "COLOR_MODE_HDR"; + case COLOR_MODE_A8: + return "COLOR_MODE_A8"; default: return Integer.toString(colorMode); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 75d5ecfa24094..70505fcc09b53 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4910,13 +4910,14 @@ public final class ViewRootImpl implements ViewParent, } } - private void updateColorModeIfNeeded(int colorMode) { + private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode) { if (mAttachInfo.mThreadedRenderer == null) { return; } // TODO: Centralize this sanitization? Why do we let setting bad modes? // Alternatively, can we just let HWUI figure it out? Do we need to care here? - if (!getConfiguration().isScreenWideColorGamut()) { + if (colorMode != ActivityInfo.COLOR_MODE_A8 + && !getConfiguration().isScreenWideColorGamut()) { colorMode = ActivityInfo.COLOR_MODE_DEFAULT; } mAttachInfo.mThreadedRenderer.setColorMode(colorMode); diff --git a/libs/hwui/ColorMode.h b/libs/hwui/ColorMode.h index 6d387f9ef43d6..3df5c3c9caed4 100644 --- a/libs/hwui/ColorMode.h +++ b/libs/hwui/ColorMode.h @@ -29,6 +29,8 @@ enum class ColorMode { Hdr = 2, // HDR Rec2020 + 1010102 Hdr10 = 3, + // Alpha 8 + A8 = 4, }; } // namespace android::uirenderer diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 9bca4df577c9d..744739accb2c2 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -91,6 +91,8 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con fboInfo.fFormat = GL_RGBA8; } else if (colorType == kRGBA_1010102_SkColorType) { fboInfo.fFormat = GL_RGB10_A2; + } else if (colorType == kAlpha_8_SkColorType) { + fboInfo.fFormat = GL_R8; } else { LOG_ALWAYS_FATAL("Unsupported color type."); } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 4e7471d5d8884..bc386feb2d6f5 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -613,6 +613,10 @@ void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) { mSurfaceColorType = SkColorType::kRGBA_1010102_SkColorType; mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020); break; + case ColorMode::A8: + mSurfaceColorType = SkColorType::kAlpha_8_SkColorType; + mSurfaceColorSpace = nullptr; + break; } } diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index c7d7a17a23ebc..2f8ddeecced0f 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -90,6 +90,7 @@ EglManager::EglManager() , mEglConfig(nullptr) , mEglConfigF16(nullptr) , mEglConfig1010102(nullptr) + , mEglConfigA8(nullptr) , mEglContext(EGL_NO_CONTEXT) , mPBufferSurface(EGL_NO_SURFACE) , mCurrentSurface(EGL_NO_SURFACE) @@ -246,6 +247,52 @@ EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavi return config; } +EGLConfig EglManager::loadA8Config(EGLDisplay display, EglManager::SwapBehavior swapBehavior) { + EGLint eglSwapBehavior = + (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; + EGLint attribs[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 0, + EGL_BLUE_SIZE, + 0, + EGL_ALPHA_SIZE, + 0, + EGL_DEPTH_SIZE, + 0, + EGL_STENCIL_SIZE, + STENCIL_BUFFER_SIZE, + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | eglSwapBehavior, + EGL_NONE}; + EGLint numConfigs = 1; + if (!eglChooseConfig(display, attribs, nullptr, numConfigs, &numConfigs)) { + return EGL_NO_CONFIG_KHR; + } + + std::vector configs(numConfigs, EGL_NO_CONFIG_KHR); + if (!eglChooseConfig(display, attribs, configs.data(), numConfigs, &numConfigs)) { + return EGL_NO_CONFIG_KHR; + } + + // The component sizes passed to eglChooseConfig are minimums, so configs + // contains entries that exceed them. Choose one that matches the sizes + // exactly. + for (EGLConfig config : configs) { + EGLint r{0}, g{0}, b{0}, a{0}; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + if (8 == r && 0 == g && 0 == b && 0 == a) { + return config; + } + } + return EGL_NO_CONFIG_KHR; +} + void EglManager::initExtensions() { auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); @@ -307,6 +354,10 @@ void EglManager::loadConfigs() { ALOGW("Failed to initialize 101010-2 format, error = %s", eglErrorString()); } + mEglConfigA8 = loadA8Config(mEglDisplay, mSwapBehavior); + if (mEglConfigA8 == EGL_NO_CONFIG_KHR) { + ALOGE("Failed to initialize A8 format, error = %s", eglErrorString()); + } } void EglManager::createContext() { @@ -345,10 +396,14 @@ Result EglManager::createSurface(EGLNativeWindowType window, sk_sp colorSpace) { LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized"); - if (!mHasWideColorGamutSupport || !EglExtensions.noConfigContext) { + if (!EglExtensions.noConfigContext) { + // The caller shouldn't use A8 if we cannot switch modes. + LOG_ALWAYS_FATAL_IF(colorMode == ColorMode::A8, + "Cannot use A8 without EGL_KHR_no_config_context!"); + + // Cannot switch modes without EGL_KHR_no_config_context. colorMode = ColorMode::Default; } - // The color space we want to use depends on whether linear blending is turned // on and whether the app has requested wide color gamut rendering. When wide // color gamut rendering is off, the app simply renders in the display's native @@ -374,42 +429,57 @@ Result EglManager::createSurface(EGLNativeWindowType window, EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE}; EGLConfig config = mEglConfig; - if (DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType) { - if (mEglConfigF16 == EGL_NO_CONFIG_KHR) { + if (colorMode == ColorMode::A8) { + // A8 doesn't use a color space + config = mEglConfigA8; + + LOG_ALWAYS_FATAL_IF(!mEglConfigA8, "Requested ColorMode::A8, but EGL lacks support!"); + } else { + if (!mHasWideColorGamutSupport) { colorMode = ColorMode::Default; - } else { - config = mEglConfigF16; } - } - if (EglExtensions.glColorSpace) { - attribs[0] = EGL_GL_COLORSPACE_KHR; - switch (colorMode) { - case ColorMode::Default: - attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; - break; - case ColorMode::WideColorGamut: { - skcms_Matrix3x3 colorGamut; - LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut), - "Could not get gamut matrix from color space"); - if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) { - attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT; - } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) { - attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT; - } else if (memcmp(&colorGamut, &SkNamedGamut::kRec2020, sizeof(colorGamut)) == 0) { - attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT; - } else { - LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); - } - break; - } - case ColorMode::Hdr: + + if (DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType) { + if (mEglConfigF16 == EGL_NO_CONFIG_KHR) { + colorMode = ColorMode::Default; + } else { config = mEglConfigF16; - attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT; - break; - case ColorMode::Hdr10: - config = mEglConfig1010102; - attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT; - break; + } + } + if (EglExtensions.glColorSpace) { + attribs[0] = EGL_GL_COLORSPACE_KHR; + switch (colorMode) { + case ColorMode::Default: + attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; + break; + case ColorMode::WideColorGamut: { + skcms_Matrix3x3 colorGamut; + LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut), + "Could not get gamut matrix from color space"); + if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) { + attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT; + } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) { + attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT; + } else if (memcmp(&colorGamut, &SkNamedGamut::kRec2020, sizeof(colorGamut)) == + 0) { + attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT; + } else { + LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); + } + break; + } + case ColorMode::Hdr: + config = mEglConfigF16; + attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT; + break; + case ColorMode::Hdr10: + config = mEglConfig1010102; + attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT; + break; + case ColorMode::A8: + LOG_ALWAYS_FATAL("Unreachable: A8 doesn't use a color space"); + break; + } } } diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index 69f3ed014c530..fc6b28d2e1ade 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -89,6 +89,7 @@ private: static EGLConfig load8BitsConfig(EGLDisplay display, SwapBehavior swapBehavior); static EGLConfig loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior); static EGLConfig load1010102Config(EGLDisplay display, SwapBehavior swapBehavior); + static EGLConfig loadA8Config(EGLDisplay display, SwapBehavior swapBehavior); void initExtensions(); void createPBufferSurface(); @@ -100,6 +101,7 @@ private: EGLConfig mEglConfig; EGLConfig mEglConfigF16; EGLConfig mEglConfig1010102; + EGLConfig mEglConfigA8; EGLContext mEglContext; EGLSurface mPBufferSurface; EGLSurface mCurrentSurface; diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 9e8a1e141fe10..a9ff2c60fdbe4 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -35,6 +35,9 @@ #include "pipeline/skia/ShaderCache.h" #include "renderstate/RenderState.h" +#undef LOG_TAG +#define LOG_TAG "VulkanManager" + namespace android { namespace uirenderer { namespace renderthread { diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index 611a4d9c8f2c5..7dd3561cb2202 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -24,6 +24,9 @@ #include "VulkanManager.h" #include "utils/Color.h" +#undef LOG_TAG +#define LOG_TAG "VulkanSurface" + namespace android { namespace uirenderer { namespace renderthread { @@ -197,8 +200,9 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType); outWindowInfo->colorspace = colorSpace; outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType); - LOG_ALWAYS_FATAL_IF(outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN, - "Unsupported colorspace"); + LOG_ALWAYS_FATAL_IF( + outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN && colorType != kAlpha_8_SkColorType, + "Unsupported colorspace"); VkFormat vkPixelFormat; switch (colorType) { @@ -211,6 +215,9 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode case kRGBA_1010102_SkColorType: vkPixelFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; break; + case kAlpha_8_SkColorType: + vkPixelFormat = VK_FORMAT_R8_UNORM; + break; default: LOG_ALWAYS_FATAL("Unsupported colorType: %d", (int)colorType); } diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index 9f3be16fcda18..2293ace0bd16b 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -57,6 +57,10 @@ static inline SkImageInfo createImageInfo(int32_t width, int32_t height, int32_t colorType = kRGBA_F16_SkColorType; alphaType = kPremul_SkAlphaType; break; + case AHARDWAREBUFFER_FORMAT_R8_UNORM: + colorType = kAlpha_8_SkColorType; + alphaType = kPremul_SkAlphaType; + break; default: ALOGV("Unsupported format: %d, return unknown by default", format); break; @@ -90,6 +94,8 @@ uint32_t ColorTypeToBufferFormat(SkColorType colorType) { // Hardcoding the value from android::PixelFormat static constexpr uint64_t kRGBA4444 = 7; return kRGBA4444; + case kAlpha_8_SkColorType: + return AHARDWAREBUFFER_FORMAT_R8_UNORM; default: ALOGV("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType); return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;