diff options
27 files changed, 500 insertions, 302 deletions
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 2768ad8560..73f2147deb 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -142,10 +142,26 @@ cc_library_shared { "android.hardware.configstore-utils", ], + // bufferhub is not used when building libgui for vendors + target: { + vendor: { + cflags: ["-DNO_BUFFERHUB"], + exclude_srcs: [ + "BufferHubConsumer.cpp", + "BufferHubProducer.cpp", + ], + exclude_shared_libs: [ + "libbufferhubqueue", + "libpdx_default_transport", + ], + }, + }, + header_libs: [ "libdvr_headers", "libnativebase_headers", "libgui_headers", + "libpdx_headers", ], export_shared_lib_headers: [ diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 2917f45164..a8da1347cb 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -18,8 +18,11 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#ifndef NO_BUFFERHUB #include <gui/BufferHubConsumer.h> #include <gui/BufferHubProducer.h> +#endif + #include <gui/BufferQueue.h> #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> @@ -103,6 +106,7 @@ void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, *outConsumer = consumer; } +#ifndef NO_BUFFERHUB void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer) { LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); @@ -128,5 +132,6 @@ void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer, *outProducer = producer; *outConsumer = consumer; } +#endif }; // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 777a3e5e9b..0749fde1ad 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -27,7 +27,9 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> +#ifndef NO_BUFFERHUB #include <gui/BufferHubProducer.h> +#endif #include <gui/BufferQueueDefs.h> #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> @@ -706,6 +708,7 @@ sp<IGraphicBufferProducer> IGraphicBufferProducer::createFromParcel(const Parcel } case USE_BUFFER_HUB: { ALOGE("createFromParcel: BufferHub not implemented."); +#ifndef NO_BUFFERHUB dvr::ProducerQueueParcelable producerParcelable; res = producerParcelable.readFromParcel(parcel); if (res != NO_ERROR) { @@ -713,6 +716,9 @@ sp<IGraphicBufferProducer> IGraphicBufferProducer::createFromParcel(const Parcel return nullptr; } return BufferHubProducer::Create(std::move(producerParcelable)); +#else + return nullptr; +#endif } default: { ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic); diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index f175573366..da952744f3 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -79,9 +79,11 @@ public: sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger = false); +#ifndef NO_BUFFERHUB // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub. static void createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer); +#endif BufferQueue() = delete; // Create through createBufferQueue }; diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 1a9fb8bfdf..ff9d19e290 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -84,7 +84,6 @@ cc_library_shared { "libhidlbase", "libhidltransport", "libhwbinder", - "libpdx_default_transport", "libsync", "libutils", "libutilscallstack", @@ -106,6 +105,7 @@ cc_library_shared { "libnativebase_headers", "libhardware_headers", "libui_headers", + "libpdx_headers", ], export_static_lib_headers: [ diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index b38ecc7190..7b5ad44f67 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -56,15 +56,6 @@ cc_library { export_header_lib_headers: [ "libnativebase_headers", ], - vendor_available: false, - vndk: { - enabled: true, - }, - target: { - vendor: { - exclude_srcs: ["detached_buffer.cpp"], - }, - }, } cc_test { diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index eeec9ec49c..9f72c05f0c 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -59,10 +59,6 @@ cc_library_shared { static_libs: staticLibraries, shared_libs: sharedLibraries, header_libs: headerLibraries, - vendor_available: false, - vndk: { - enabled: true, - }, } subdirs = ["benchmarks", "tests"] diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp index d0e34eef43..16906f57cd 100644 --- a/libs/vr/libdvr/Android.bp +++ b/libs/vr/libdvr/Android.bp @@ -16,10 +16,7 @@ cc_library_headers { name: "libdvr_headers", export_include_dirs: ["include"], - vendor_available: false, - vndk: { - enabled: true, - }, + vendor_available: true, } cflags = [ diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp index 9b84d6576b..1a9d7274a1 100644 --- a/libs/vr/libpdx/Android.bp +++ b/libs/vr/libpdx/Android.bp @@ -1,3 +1,9 @@ +cc_library_headers { + name: "libpdx_headers", + export_include_dirs: ["private"], + vendor_available: true, +} + cc_library_static { name: "libpdx", clang: true, @@ -8,8 +14,8 @@ cc_library_static { "-DLOG_TAG=\"libpdx\"", "-DTRACE=0", ], - export_include_dirs: ["private"], - local_include_dirs: ["private"], + header_libs: ["libpdx_headers"], + export_header_lib_headers: ["libpdx_headers"], srcs: [ "client.cpp", "service.cpp", @@ -22,10 +28,6 @@ cc_library_static { "libutils", "liblog", ], - vendor_available: false, - vndk: { - enabled: true, - }, } cc_test { diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index 475eb50f29..74b8c8bd21 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -12,10 +12,6 @@ cc_defaults { name: "pdx_default_transport_lib_defaults", export_include_dirs: ["private"], whole_static_libs: ["libpdx"], - vendor_available: false, - vndk: { - enabled: true, - }, } cc_defaults { @@ -37,10 +33,6 @@ cc_library_shared { "pdx_default_transport_lib_defaults", "pdx_use_transport_uds", ], - vendor_available: false, - vndk: { - enabled: true, - }, shared_libs: [ "libbase", "libbinder", diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp index 79cfdf6324..d64095061e 100644 --- a/libs/vr/libpdx_uds/Android.bp +++ b/libs/vr/libpdx_uds/Android.bp @@ -30,10 +30,6 @@ cc_library_static { whole_static_libs: [ "libselinux", ], - vendor_available: false, - vndk: { - enabled: true, - }, } cc_test { diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 4c3844e130..6feec53257 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -528,11 +528,9 @@ Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime recomputeVisibleRegions = true; } - // Dataspace::V0_SRGB and Dataspace::V0_SRGB_LINEAR are not legacy - // data space, however since framework doesn't distinguish them out of - // legacy SRGB, we have to treat them as the same for now. - // UNKNOWN is treated as legacy SRGB when the connected api is EGL. ui::Dataspace dataSpace = mConsumer->getCurrentDataSpace(); + // treat modern dataspaces as legacy dataspaces whenever possible, until + // we can trust the buffer producers switch (dataSpace) { case ui::Dataspace::V0_SRGB: dataSpace = ui::Dataspace::SRGB; @@ -540,10 +538,17 @@ Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime case ui::Dataspace::V0_SRGB_LINEAR: dataSpace = ui::Dataspace::SRGB_LINEAR; break; - case ui::Dataspace::UNKNOWN: - if (mConsumer->getCurrentApi() == NATIVE_WINDOW_API_EGL) { - dataSpace = ui::Dataspace::SRGB; - } + case ui::Dataspace::V0_JFIF: + dataSpace = ui::Dataspace::JFIF; + break; + case ui::Dataspace::V0_BT601_625: + dataSpace = ui::Dataspace::BT601_625; + break; + case ui::Dataspace::V0_BT601_525: + dataSpace = ui::Dataspace::BT601_525; + break; + case ui::Dataspace::V0_BT709: + dataSpace = ui::Dataspace::BT709; break; default: break; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 00f8cc9c5c..2b1e5775ba 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -80,6 +80,7 @@ DisplayDevice::DisplayDevice( bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, + const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, int initialPowerMode) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), @@ -105,7 +106,11 @@ DisplayDevice::DisplayDevice( mHasHdr10(false), mHasHLG(false), mHasDolbyVision(false), - mSupportedPerFrameMetadata(supportedPerFrameMetadata) + mSupportedPerFrameMetadata(supportedPerFrameMetadata), + mHasBT2100PQColorimetric(false), + mHasBT2100PQEnhance(false), + mHasBT2100HLGColorimetric(false), + mHasBT2100HLGEnhance(false) { // clang-format on std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes(); @@ -145,6 +150,18 @@ DisplayDevice::DisplayDevice( } mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance); + auto iter = hdrAndRenderIntents.find(ColorMode::BT2100_PQ); + if (iter != hdrAndRenderIntents.end()) { + hasToneMapping(iter->second, + &mHasBT2100PQColorimetric, &mHasBT2100PQEnhance); + } + + iter = hdrAndRenderIntents.find(ColorMode::BT2100_HLG); + if (iter != hdrAndRenderIntents.end()) { + hasToneMapping(iter->second, + &mHasBT2100HLGColorimetric, &mHasBT2100HLGEnhance); + } + // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); } @@ -529,6 +546,22 @@ void DisplayDevice::dump(String8& result) const { result.append(surfaceDump); } +void DisplayDevice::hasToneMapping(const std::vector<RenderIntent>& renderIntents, + bool* outColorimetric, bool *outEnhance) { + for (auto intent : renderIntents) { + switch (intent) { + case RenderIntent::TONE_MAP_COLORIMETRIC: + *outColorimetric = true; + break; + case RenderIntent::TONE_MAP_ENHANCE: + *outEnhance = true; + break; + default: + break; + } + } +} + std::atomic<int32_t> DisplayDeviceState::nextDisplayId(1); DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure) diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 1df8c49b1f..d051e33579 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -20,6 +20,7 @@ #include "Transform.h" #include <stdlib.h> +#include <unordered_map> #include <math/mat4.h> @@ -90,6 +91,7 @@ public: bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, + const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, int initialPowerMode); // clang-format on @@ -142,6 +144,7 @@ public: status_t beginFrame(bool mustRecompose) const; status_t prepareFrame(HWComposer& hwc); bool hasWideColorGamut() const { return mHasWideColorGamut; } + // Whether h/w composer has native support for specific HDR type. bool hasHDR10Support() const { return mHasHdr10; } bool hasHLGSupport() const { return mHasHLG; } bool hasDolbyVisionSupport() const { return mHasDolbyVision; } @@ -153,6 +156,14 @@ public: // respectively if hardware composer doesn't return meaningful values. const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; } + // Whether h/w composer has BT2100_PQ color mode. + bool hasBT2100PQColorimetricSupport() const { return mHasBT2100PQColorimetric; } + bool hasBT2100PQEnhanceSupport() const { return mHasBT2100PQEnhance; } + + // Whether h/w composer has BT2100_HLG color mode. + bool hasBT2100HLGColorimetricSupport() const { return mHasBT2100HLGColorimetric; } + bool hasBT2100HLGEnhanceSupport() const { return mHasBT2100HLGEnhance; } + void swapBuffers(HWComposer& hwc) const; // called after h/w composer has completed its set() call @@ -203,6 +214,9 @@ public: void dump(String8& result) const; private: + void hasToneMapping(const std::vector<ui::RenderIntent>& renderIntents, + bool* outColorimetric, bool *outEnhance); + /* * Constants, set during initialization */ @@ -274,6 +288,12 @@ private: bool mHasDolbyVision; HdrCapabilities mHdrCapabilities; const int32_t mSupportedPerFrameMetadata; + // Whether h/w composer has BT2100_PQ and BT2100_HLG color mode with + // colorimetrical tone mapping or enhanced tone mapping. + bool mHasBT2100PQColorimetric; + bool mHasBT2100PQEnhance; + bool mHasBT2100HLGColorimetric; + bool mHasBT2100HLGEnhance; }; struct DisplayDeviceState { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2802fc7b21..9043234132 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1650,9 +1650,10 @@ bool Layer::detachChildren() { return true; } -bool Layer::isLegacySrgbDataSpace() const { - return mDrawingState.dataSpace == ui::Dataspace::SRGB || - mDrawingState.dataSpace == ui::Dataspace::SRGB_LINEAR; +bool Layer::isLegacyDataSpace() const { + // return true when no higher bits are set + return !(mDrawingState.dataSpace & (ui::Dataspace::STANDARD_MASK | + ui::Dataspace::TRANSFER_MASK | ui::Dataspace::RANGE_MASK)); } void Layer::setParent(const sp<Layer>& layer) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 0b15b67062..632efbe23e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -303,8 +303,8 @@ public: // desaturated in order to match what they appears like visually. // With color management, these contents will appear desaturated, thus // needed to be saturated so that they match what they are designed for - // visually. When returns true, legacy SRGB data space is passed to HWC. - bool isLegacySrgbDataSpace() const; + // visually. + bool isLegacyDataSpace() const; // If we have received a new buffer this frame, we will pass its surface // damage down to hardware composer. Otherwise, we must send a region with diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 08cd5b0012..64095ddfb8 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -259,10 +259,8 @@ void GLES20RenderEngine::setupLayerBlackedOut() { mState.setTexture(texture); } -mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) { - mat4 oldTransform = mState.getColorMatrix(); +void GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) { mState.setColorMatrix(colorTransform); - return oldTransform; } void GLES20RenderEngine::disableTexturing() { diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 9acd79bf71..c9e402de8c 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -80,7 +80,7 @@ protected: virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a); - virtual mat4 setupColorTransform(const mat4& colorTransform); + virtual void setupColorTransform(const mat4& colorTransform); virtual void disableTexturing(); virtual void disableBlending(); diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index 89ee64b10d..57a772b047 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -233,103 +233,177 @@ void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) { } // Generate OOTF that modifies the relative scence light to relative display light. -void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { - fs << R"__SHADER__( - highp float CalculateY(const highp vec3 color) { - // BT2020 standard uses the unadjusted KR = 0.2627, - // KB = 0.0593 luminance interpretation for RGB conversion. - return color.r * 0.262700 + color.g * 0.677998 + color.b * 0.059302; - } - )__SHADER__"; - - // Generate OOTF that modifies the relative display light. - switch(needs.getInputTF()) { +void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { + // When HDR and non-HDR contents are mixed, or different types of HDR contents are + // mixed, we will do a transcoding process to transcode the input content to output + // content. Currently, the following conversions handled, they are: + // * SDR -> HLG + // * SDR -> PQ + // * HLG -> PQ + + // Convert relative light to absolute light. + switch (needs.getInputTF()) { case Key::INPUT_TF_ST2084: fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - const float maxLumi = 10000.0; - const float maxMasteringLumi = 1000.0; - const float maxContentLumi = 1000.0; - const float maxInLumi = min(maxMasteringLumi, maxContentLumi); - const float maxOutLumi = displayMaxLuminance; - - // Calculate Y value in XYZ color space. - float colorY = CalculateY(color); - - // convert to nits first - float nits = colorY * maxLumi; - - // clamp to max input luminance - nits = clamp(nits, 0.0, maxInLumi); - - // scale [0.0, maxInLumi] to [0.0, maxOutLumi] - if (maxInLumi <= maxOutLumi) { - nits *= maxOutLumi / maxInLumi; - } else { - // three control points - const float x0 = 10.0; - const float y0 = 17.0; - const float x1 = maxOutLumi * 0.75; - const float y1 = x1; - const float x2 = x1 + (maxInLumi - x1) / 2.0; - const float y2 = y1 + (maxOutLumi - y1) * 0.75; - - // horizontal distances between the last three control points - const float h12 = x2 - x1; - const float h23 = maxInLumi - x2; - // tangents at the last three control points - const float m1 = (y2 - y1) / h12; - const float m3 = (maxOutLumi - y2) / h23; - const float m2 = (m1 + m3) / 2.0; - - if (nits < x0) { - // scale [0.0, x0] to [0.0, y0] linearly - const float slope = y0 / x0; - nits *= slope; - } else if (nits < x1) { - // scale [x0, x1] to [y0, y1] linearly - const float slope = (y1 - y0) / (x1 - x0); - nits = y0 + (nits - x0) * slope; - } else if (nits < x2) { - // scale [x1, x2] to [y1, y2] using Hermite interp - float t = (nits - x1) / h12; - nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + - (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; - } else { - // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp - float t = (nits - x2) / h23; - nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + - (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; - } - } - - // convert back to [0.0, 1.0] - float targetY = nits / maxOutLumi; - return color * (targetY / max(1e-6, colorY)); + highp vec3 ScaleLuminance(color) { + return color * 10000.0; } )__SHADER__"; break; case Key::INPUT_TF_HLG: fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - const float maxOutLumi = 500.0; - const float gamma = 1.2 + 0.42 * log(maxOutLumi / 1000.0) / log(10.0); + highp vec3 ScaleLuminance(color) { // The formula is: // alpha * pow(Y, gamma - 1.0) * color + beta; - // where alpha is 1.0, beta is 0.0 as recommended in - // Rec. ITU-R BT.2100-1 TABLE 5. - return pow(CalculateY(color), gamma - 1.0) * color; + // where alpha is 1000.0, gamma is 1.2, beta is 0.0. + return color * 1000.0 * pow(color.y, 0.2); } )__SHADER__"; break; default: fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { + highp vec3 ScaleLuminance(color) { + return color * displayMaxLuminance; + } + )__SHADER__"; + break; + } + + // Tone map absolute light to display luminance range. + switch (needs.getInputTF()) { + case Key::INPUT_TF_ST2084: + case Key::INPUT_TF_HLG: + switch (needs.getOutputTF()) { + case Key::OUTPUT_TF_HLG: + // Right now when mixed PQ and HLG contents are presented, + // HLG content will always be converted to PQ. However, for + // completeness, we simply clamp the value to [0.0, 1000.0]. + fs << R"__SHADER__( + highp vec3 ToneMap(color) { + return clamp(color, 0.0, 1000.0); + } + )__SHADER__"; + break; + case Key::OUTPUT_TF_ST2084: + fs << R"__SHADER__( + highp vec3 ToneMap(color) { + return color; + } + )__SHADER__"; + break; + default: + fs << R"__SHADER__( + highp vec3 ToneMap(color) { + const float maxMasteringLumi = 1000.0; + const float maxContentLumi = 1000.0; + const float maxInLumi = min(maxMasteringLumi, maxContentLumi); + float maxOutLumi = displayMaxLuminance; + + float nits = color.y; + + // clamp to max input luminance + nits = clamp(nits, 0.0, maxInLumi); + + // scale [0.0, maxInLumi] to [0.0, maxOutLumi] + if (maxInLumi <= maxOutLumi) { + nits *= maxOutLumi / maxInLumi; + } else { + // three control points + const float x0 = 10.0; + const float y0 = 17.0; + float x1 = maxOutLumi * 0.75; + float y1 = x1; + float x2 = x1 + (maxInLumi - x1) / 2.0; + float y2 = y1 + (maxOutLumi - y1) * 0.75; + + // horizontal distances between the last three control points + const float h12 = x2 - x1; + const float h23 = maxInLumi - x2; + // tangents at the last three control points + const float m1 = (y2 - y1) / h12; + const float m3 = (maxOutLumi - y2) / h23; + const float m2 = (m1 + m3) / 2.0; + + if (nits < x0) { + // scale [0.0, x0] to [0.0, y0] linearly + const float slope = y0 / x0; + nits *= slope; + } else if (nits < x1) { + // scale [x0, x1] to [y0, y1] linearly + const float slope = (y1 - y0) / (x1 - x0); + nits = y0 + (nits - x0) * slope; + } else if (nits < x2) { + // scale [x1, x2] to [y1, y2] using Hermite interp + float t = (nits - x1) / h12; + nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + + (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; + } else { + // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp + float t = (nits - x2) / h23; + nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + + (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; + } + } + + return color * (nits / max(1e-6, color.y)); + } + )__SHADER__"; + break; + } + break; + default: + // TODO(73825729) We need to revert the tone mapping in + // hardware composer properly. + fs << R"__SHADER__( + highp vec3 ToneMap(color) { return color; } )__SHADER__"; break; } + + // convert absolute light to relative light. + switch (needs.getOutputTF()) { + case Key::OUTPUT_TF_ST2084: + fs << R"__SHADER__( + highp vec3 NormalizeLuminance(color) { + return color / 10000.0; + } + )__SHADER__"; + break; + case Key::OUTPUT_TF_HLG: + fs << R"__SHADER__( + highp vec3 NormalizeLuminance(color) { + return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); + } + )__SHADER__"; + break; + default: + fs << R"__SHADER__( + highp vec3 NormalizeLuminance(color) { + return color / displayMaxLuminance; + } + )__SHADER__"; + break; + } + + if (needs.getInputTF() == needs.getOutputTF() || + (needs.getInputTF() == Key::INPUT_TF_LINEAR && + needs.getOutputTF() == Key::OUTPUT_TF_SRGB) || + (needs.getInputTF() == Key::INPUT_TF_SRGB && + needs.getOutputTF() == Key::OUTPUT_TF_LINEAR)) { + fs << R"__SHADER__( + highp vec3 OOTF(const highp vec3 color) { + return color; + } + )__SHADER__"; + } else { + fs << R"__SHADER__( + highp vec3 OOTF(const highp vec3 color) { + return NormalizeLuminance(ToneMap(ScaleLuminance(color))); + } + )__SHADER__"; + } } // Generate OETF that converts relative display light to signal values, @@ -448,7 +522,7 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) { // Currently, only the OOTF of BT2020 PQ needs display maximum luminance. if (needs.getInputTF() == Key::INPUT_TF_ST2084) { - fs << "uniform float displayMaxLuminance"; + fs << "uniform float displayMaxLuminance;"; } if (needs.hasInputTransformMatrix()) { diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index df9e6a74a2..d559464eb5 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -112,7 +112,7 @@ public: virtual void setupLayerBlackedOut() = 0; virtual void setupFillWithColor(float r, float g, float b, float a) = 0; - virtual mat4 setupColorTransform(const mat4& /* colorTransform */) = 0; + virtual void setupColorTransform(const mat4& /* colorTransform */) = 0; virtual void disableTexturing() = 0; virtual void disableBlending() = 0; @@ -224,7 +224,7 @@ public: void checkErrors() const override; - mat4 setupColorTransform(const mat4& /* colorTransform */) override { return mat4(); } + void setupColorTransform(const mat4& /* colorTransform */) override {} // internal to RenderEngine EGLDisplay getEGLDisplay() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index cdf7ccaacc..588d24c45f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1019,27 +1019,13 @@ ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) { } void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw, - ColorMode mode, Dataspace dataSpace) { + ColorMode mode, Dataspace dataSpace, + RenderIntent renderIntent) { int32_t type = hw->getDisplayType(); ColorMode currentMode = hw->getActiveColorMode(); Dataspace currentDataSpace = hw->getCompositionDataSpace(); RenderIntent currentRenderIntent = hw->getActiveRenderIntent(); - // Natural Mode means it's color managed and the color must be right, - // thus we pick RenderIntent::COLORIMETRIC as render intent. - // Native Mode means the display is not color managed, and whichever - // render intent is picked doesn't matter, thus return - // RenderIntent::COLORIMETRIC as default here. - RenderIntent renderIntent = RenderIntent::COLORIMETRIC; - - // In Auto Color Mode, we want to strech to panel color space, right now - // only the built-in display supports it. - if (mDisplayColorSetting == DisplayColorSetting::ENHANCED && - mBuiltinDisplaySupportsEnhance && - hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) { - renderIntent = RenderIntent::ENHANCE; - } - if (mode == currentMode && dataSpace == currentDataSpace && renderIntent == currentRenderIntent) { return; @@ -1089,7 +1075,8 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display, ALOGW("Attempt to set active color mode %s %d for virtual display", decodeColorMode(mMode).c_str(), mMode); } else { - mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN); + mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN, + RenderIntent::COLORIMETRIC); } return true; } @@ -1471,13 +1458,12 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { (mPreviousPresentFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING); ATRACE_INT("FrameMissed", static_cast<int>(frameMissed)); - if (mPropagateBackpressure && frameMissed) { - mTimeStats.incrementMissedFrames(true); - signalLayerUpdate(); - break; - } if (frameMissed) { - mTimeStats.incrementMissedFrames(false); + mTimeStats.incrementMissedFrames(); + if (mPropagateBackpressure) { + signalLayerUpdate(); + break; + } } // Now that we're going to make it to the handleMessageTransaction() @@ -1870,38 +1856,41 @@ void SurfaceFlinger::rebuildLayerStacks() { } } -// Returns a dataspace that fits all visible layers. The returned dataspace +// Returns a data space that fits all visible layers. The returned data space // can only be one of -// -// - Dataspace::V0_SRGB +// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced) // - Dataspace::DISPLAY_P3 // - Dataspace::V0_SCRGB_LINEAR -// TODO(b/73825729) Add BT2020 data space. -ui::Dataspace SurfaceFlinger::getBestDataspace( - const sp<const DisplayDevice>& displayDevice) const { - Dataspace bestDataspace = Dataspace::V0_SRGB; +// The returned HDR data space is one of +// - Dataspace::UNKNOWN +// - Dataspace::BT2020_HLG +// - Dataspace::BT2020_PQ +Dataspace SurfaceFlinger::getBestDataspace( + const sp<const DisplayDevice>& displayDevice, Dataspace* outHdrDataSpace) const { + Dataspace bestDataSpace = Dataspace::SRGB; + *outHdrDataSpace = Dataspace::UNKNOWN; + for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) { switch (layer->getDataSpace()) { case Dataspace::V0_SCRGB: case Dataspace::V0_SCRGB_LINEAR: - // return immediately - return Dataspace::V0_SCRGB_LINEAR; + bestDataSpace = Dataspace::V0_SCRGB_LINEAR; + break; case Dataspace::DISPLAY_P3: - bestDataspace = Dataspace::DISPLAY_P3; + if (bestDataSpace == Dataspace::SRGB) { + bestDataSpace = Dataspace::DISPLAY_P3; + } break; - // Historically, HDR dataspaces are ignored by SurfaceFlinger. But - // since SurfaceFlinger simulates HDR support now, it should honor - // them unless there is also native support. case Dataspace::BT2020_PQ: case Dataspace::BT2020_ITU_PQ: - if (!displayDevice->hasHDR10Support()) { - return Dataspace::V0_SCRGB_LINEAR; - } + *outHdrDataSpace = Dataspace::BT2020_PQ; break; case Dataspace::BT2020_HLG: case Dataspace::BT2020_ITU_HLG: - if (!displayDevice->hasHLGSupport()) { - return Dataspace::V0_SCRGB_LINEAR; + // When there's mixed PQ content and HLG content, we set the HDR + // data space to be BT2020_PQ and convert HLG to PQ. + if (*outHdrDataSpace == Dataspace::UNKNOWN) { + *outHdrDataSpace = Dataspace::BT2020_HLG; } break; default: @@ -1909,29 +1898,120 @@ ui::Dataspace SurfaceFlinger::getBestDataspace( } } - return bestDataspace; + return bestDataSpace; } // Pick the ColorMode / Dataspace for the display device. -// TODO(b/73825729) Add BT2020 color mode. void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice, - ColorMode* outMode, Dataspace* outDataSpace) const { + ColorMode* outMode, Dataspace* outDataSpace, + RenderIntent* outRenderIntent) const { if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) { *outMode = ColorMode::NATIVE; *outDataSpace = Dataspace::UNKNOWN; + *outRenderIntent = RenderIntent::COLORIMETRIC; return; } - switch (getBestDataspace(displayDevice)) { - case Dataspace::DISPLAY_P3: - case Dataspace::V0_SCRGB_LINEAR: + Dataspace hdrDataSpace; + Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace); + + if (hdrDataSpace == Dataspace::BT2020_PQ) { + // Hardware composer can handle BT2100 ColorMode only when + // - colorimetrical tone mapping is supported, or + // - Auto mode is turned on and enhanced tone mapping is supported. + if (displayDevice->hasBT2100PQColorimetricSupport() || + (mDisplayColorSetting == DisplayColorSetting::ENHANCED && + displayDevice->hasBT2100PQEnhanceSupport())) { + *outMode = ColorMode::BT2100_PQ; + *outDataSpace = Dataspace::BT2020_PQ; + } else if (displayDevice->hasHDR10Support()) { + // Legacy HDR support. HDR layers are treated as UNKNOWN layers. + hdrDataSpace = Dataspace::UNKNOWN; + } else { + // Simulate PQ through RenderEngine, pick DISPLAY_P3 color mode. *outMode = ColorMode::DISPLAY_P3; *outDataSpace = Dataspace::DISPLAY_P3; - break; + } + } else if (hdrDataSpace == Dataspace::BT2020_HLG) { + if (displayDevice->hasBT2100HLGColorimetricSupport() || + (mDisplayColorSetting == DisplayColorSetting::ENHANCED && + displayDevice->hasBT2100HLGEnhanceSupport())) { + *outMode = ColorMode::BT2100_HLG; + *outDataSpace = Dataspace::BT2020_HLG; + } else if (displayDevice->hasHLGSupport()) { + // Legacy HDR support. HDR layers are treated as UNKNOWN layers. + hdrDataSpace = Dataspace::UNKNOWN; + } else { + // Simulate HLG through RenderEngine, pick DISPLAY_P3 color mode. + *outMode = ColorMode::DISPLAY_P3; + *outDataSpace = Dataspace::DISPLAY_P3; + } + } + + // At this point, there's no HDR layer. + if (hdrDataSpace == Dataspace::UNKNOWN) { + switch (bestDataSpace) { + case Dataspace::DISPLAY_P3: + case Dataspace::V0_SCRGB_LINEAR: + *outMode = ColorMode::DISPLAY_P3; + *outDataSpace = Dataspace::DISPLAY_P3; + break; + default: + *outMode = ColorMode::SRGB; + *outDataSpace = Dataspace::SRGB; + break; + } + } + *outRenderIntent = pickRenderIntent(displayDevice, *outMode); +} + +RenderIntent SurfaceFlinger::pickRenderIntent(const sp<DisplayDevice>& displayDevice, + ColorMode colorMode) const { + // Native Mode means the display is not color managed, and whichever + // render intent is picked doesn't matter, thus return + // RenderIntent::COLORIMETRIC as default here. + if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) { + return RenderIntent::COLORIMETRIC; + } + + // In Auto Color Mode, we want to strech to panel color space, right now + // only the built-in display supports it. + if (mDisplayColorSetting == DisplayColorSetting::ENHANCED && + mBuiltinDisplaySupportsEnhance && + displayDevice->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) { + switch (colorMode) { + case ColorMode::DISPLAY_P3: + case ColorMode::SRGB: + return RenderIntent::ENHANCE; + // In Auto Color Mode, BT2100_PQ and BT2100_HLG will only be picked + // when TONE_MAP_ENHANCE or TONE_MAP_COLORIMETRIC is supported. + // If TONE_MAP_ENHANCE is not supported, fall back to TONE_MAP_COLORIMETRIC. + case ColorMode::BT2100_PQ: + return displayDevice->hasBT2100PQEnhanceSupport() ? + RenderIntent::TONE_MAP_ENHANCE : RenderIntent::TONE_MAP_COLORIMETRIC; + case ColorMode::BT2100_HLG: + return displayDevice->hasBT2100HLGEnhanceSupport() ? + RenderIntent::TONE_MAP_ENHANCE : RenderIntent::TONE_MAP_COLORIMETRIC; + // This statement shouldn't be reached, switch cases will always + // cover all possible ColorMode returned by pickColorMode. + default: + return RenderIntent::COLORIMETRIC; + } + } + + // Either enhance is not supported or we are in natural mode. + + // Natural Mode means it's color managed and the color must be right, + // thus we pick RenderIntent::COLORIMETRIC as render intent for non-HDR + // content and pick RenderIntent::TONE_MAP_COLORIMETRIC for HDR content. + switch (colorMode) { + // In Natural Color Mode, BT2100_PQ and BT2100_HLG will only be picked + // when TONE_MAP_COLORIMETRIC is supported. + case ColorMode::BT2100_PQ: + case ColorMode::BT2100_HLG: + return RenderIntent::TONE_MAP_COLORIMETRIC; default: - *outMode = ColorMode::SRGB; - *outDataSpace = Dataspace::V0_SRGB; - break; + return RenderIntent::COLORIMETRIC; } } @@ -2033,8 +2113,9 @@ void SurfaceFlinger::setUpHWComposer() { if (hasWideColorDisplay) { ColorMode colorMode; Dataspace dataSpace; - pickColorMode(displayDevice, &colorMode, &dataSpace); - setActiveColorModeInternal(displayDevice, colorMode, dataSpace); + RenderIntent renderIntent; + pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent); + setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent); } } @@ -2243,6 +2324,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) { bool hasWideColorGamut = false; + std::unordered_map<ColorMode, std::vector<RenderIntent>> hdrAndRenderIntents; + if (hasWideColorDisplay) { std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId); for (ColorMode colorMode : modes) { @@ -2252,7 +2335,6 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( case ColorMode::DCI_P3: hasWideColorGamut = true; break; - // TODO(lpy) Handle BT2020, BT2100_PQ and BT2100_HLG properly. default: break; } @@ -2267,6 +2349,10 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( } } } + + if (colorMode == ColorMode::BT2100_PQ || colorMode == ColorMode::BT2100_HLG) { + hdrAndRenderIntents.emplace(colorMode, renderIntents); + } } } @@ -2306,7 +2392,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( dispSurface, std::move(renderSurface), displayWidth, displayHeight, hasWideColorGamut, hdrCapabilities, getHwComposer().getSupportedPerFrameMetadata(hwcId), - initialPowerMode); + hdrAndRenderIntents, initialPowerMode); if (maxFrameBufferAcquiredBuffers >= 3) { nativeWindowSurface->preallocateBuffers(); @@ -2318,7 +2404,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( defaultColorMode = ColorMode::SRGB; defaultDataSpace = Dataspace::V0_SRGB; } - setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace); + setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace, + RenderIntent::COLORIMETRIC); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); @@ -2873,18 +2960,13 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev const DisplayRenderArea renderArea(displayDevice); const auto hwcId = displayDevice->getHwcDisplayId(); const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId); - const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId); - const bool skipClientColorTransform = getBE().mHwc->hasCapability( - HWC2::Capability::SkipClientColorTransform); ATRACE_INT("hasClientComposition", hasClientComposition); - mat4 oldColorMatrix; - mat4 legacySrgbSaturationMatrix = mLegacySrgbSaturationMatrix; - const bool applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform; - if (applyColorMatrix) { - oldColorMatrix = getRenderEngine().setupColorTransform(mDrawingState.colorMatrix); - legacySrgbSaturationMatrix = mDrawingState.colorMatrix * legacySrgbSaturationMatrix; - } + bool applyColorMatrix = false; + bool applyLegacyColorMatrix = false; + mat4 colorMatrix; + mat4 legacyColorMatrix; + const mat4* currentColorMatrix = nullptr; if (hasClientComposition) { ALOGV("hasClientComposition"); @@ -2897,6 +2979,26 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev getBE().mRenderEngine->setDisplayMaxLuminance( displayDevice->getHdrCapabilities().getDesiredMaxLuminance()); + const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId); + const bool skipClientColorTransform = getBE().mHwc->hasCapability( + HWC2::Capability::SkipClientColorTransform); + + applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform; + if (applyColorMatrix) { + colorMatrix = mDrawingState.colorMatrix; + } + + applyLegacyColorMatrix = (mDisplayColorSetting == DisplayColorSetting::ENHANCED && + outputDataspace != Dataspace::UNKNOWN && + outputDataspace != Dataspace::SRGB); + if (applyLegacyColorMatrix) { + if (applyColorMatrix) { + legacyColorMatrix = colorMatrix * mLegacySrgbSaturationMatrix; + } else { + legacyColorMatrix = mLegacySrgbSaturationMatrix; + } + } + if (!displayDevice->makeCurrent()) { ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", displayDevice->getDisplayName().string()); @@ -2958,69 +3060,59 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev ALOGV("Rendering client layers"); const Transform& displayTransform = displayDevice->getTransform(); - if (hwcId >= 0) { - // we're using h/w composer - bool firstLayer = true; - for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - const Region clip(bounds.intersect( - displayTransform.transform(layer->visibleRegion))); - ALOGV("Layer: %s", layer->getName().string()); - ALOGV(" Composition type: %s", - to_string(layer->getCompositionType(hwcId)).c_str()); - if (!clip.isEmpty()) { - switch (layer->getCompositionType(hwcId)) { - case HWC2::Composition::Cursor: - case HWC2::Composition::Device: - case HWC2::Composition::Sideband: - case HWC2::Composition::SolidColor: { - const Layer::State& state(layer->getDrawingState()); - if (layer->getClearClientTarget(hwcId) && !firstLayer && - layer->isOpaque(state) && (state.color.a == 1.0f) - && hasClientComposition) { - // never clear the very first layer since we're - // guaranteed the FB is already cleared - layer->clearWithOpenGL(renderArea); - } - break; + bool firstLayer = true; + for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { + const Region clip(bounds.intersect( + displayTransform.transform(layer->visibleRegion))); + ALOGV("Layer: %s", layer->getName().string()); + ALOGV(" Composition type: %s", + to_string(layer->getCompositionType(hwcId)).c_str()); + if (!clip.isEmpty()) { + switch (layer->getCompositionType(hwcId)) { + case HWC2::Composition::Cursor: + case HWC2::Composition::Device: + case HWC2::Composition::Sideband: + case HWC2::Composition::SolidColor: { + const Layer::State& state(layer->getDrawingState()); + if (layer->getClearClientTarget(hwcId) && !firstLayer && + layer->isOpaque(state) && (state.color.a == 1.0f) + && hasClientComposition) { + // never clear the very first layer since we're + // guaranteed the FB is already cleared + layer->clearWithOpenGL(renderArea); } - case HWC2::Composition::Client: { - // Only apply saturation matrix layer that is legacy SRGB dataspace - // when auto color mode is on. - bool restore = false; - mat4 savedMatrix; - if (mDisplayColorSetting == DisplayColorSetting::ENHANCED && - layer->isLegacySrgbDataSpace()) { - savedMatrix = - getRenderEngine().setupColorTransform(legacySrgbSaturationMatrix); - restore = true; + break; + } + case HWC2::Composition::Client: { + // switch color matrices lazily + if (layer->isLegacyDataSpace()) { + if (applyLegacyColorMatrix && currentColorMatrix != &legacyColorMatrix) { + // TODO(b/78891890) Legacy sRGB saturation matrix should be set + // separately. + getRenderEngine().setupColorTransform(legacyColorMatrix); + currentColorMatrix = &legacyColorMatrix; } - layer->draw(renderArea, clip); - if (restore) { - getRenderEngine().setupColorTransform(savedMatrix); + } else { + if (applyColorMatrix && currentColorMatrix != &colorMatrix) { + getRenderEngine().setupColorTransform(colorMatrix); + currentColorMatrix = &colorMatrix; } - break; } - default: - break; + + layer->draw(renderArea, clip); + break; } - } else { - ALOGV(" Skipping for empty clip"); - } - firstLayer = false; - } - } else { - // we're not using h/w composer - for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - const Region clip(bounds.intersect( - displayTransform.transform(layer->visibleRegion))); - if (!clip.isEmpty()) { - layer->draw(renderArea, clip); + default: + break; } + } else { + ALOGV(" Skipping for empty clip"); } + firstLayer = false; } - if (applyColorMatrix) { - getRenderEngine().setupColorTransform(oldColorMatrix); + if (applyColorMatrix || applyLegacyColorMatrix) { + getRenderEngine().setupColorTransform(mat4()); } // disable scissor at the end of the frame diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 54cf63c950..d9cf9461ca 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -481,7 +481,8 @@ private: // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode, - ui::Dataspace dataSpace); + ui::Dataspace dataSpace, + ui::RenderIntent renderIntent); // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -653,12 +654,18 @@ private: nsecs_t compositeToPresentLatency); void rebuildLayerStacks(); - // Given a dataSpace, returns the appropriate color_mode to use - // to display that dataSpace. - ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice) const; + ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice, + ui::Dataspace* outHdrDataSpace) const; + + // Returns the appropriate ColorMode, Dataspace and RenderIntent for the + // DisplayDevice. The function only returns the supported ColorMode, + // Dataspace and RenderIntent. void pickColorMode(const sp<DisplayDevice>& displayDevice, ui::ColorMode* outMode, - ui::Dataspace* outDataSpace) const; + ui::Dataspace* outDataSpace, + ui::RenderIntent* outRenderIntent) const; + ui::RenderIntent pickRenderIntent(const sp<DisplayDevice>& displayDevice, + ui::ColorMode colorMode) const; void setUpHWComposer(); void doComposition(); diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 5f2dd32182..a6833a5b5d 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -87,15 +87,12 @@ void TimeStats::incrementTotalFrames() { timeStats.totalFrames++; } -void TimeStats::incrementMissedFrames(bool propagateBackpressure) { +void TimeStats::incrementMissedFrames() { if (!mEnabled.load()) return; ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - if (propagateBackpressure) { - timeStats.totalFrames--; - } timeStats.missedFrames++; } diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 2410265a0d..f76a62ede0 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -64,7 +64,7 @@ public: static TimeStats& getInstance(); void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, String8& result); void incrementTotalFrames(); - void incrementMissedFrames(bool propagateBackpressure); + void incrementMissedFrames(); void incrementClientCompositionFrames(); void setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index bb6ca39023..08da1a2c17 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -47,10 +47,10 @@ using testing::SetArgPointee; using android::hardware::graphics::common::V1_0::Hdr; using android::hardware::graphics::common::V1_1::ColorMode; +using android::hardware::graphics::common::V1_1::RenderIntent; using android::Hwc2::Error; using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; -using android::Hwc2::RenderIntent; using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; @@ -494,33 +494,6 @@ struct WideColorP3ColorimetricSupportedVariant { } }; -// For this variant, SurfaceFlinger should configure itself with wide color -// display support, and the display should respond with an non-empty list of -// supported color modes. -template <typename Display> -struct WideColorP3EnhanceSupportedVariant { - static constexpr bool WIDE_COLOR_SUPPORTED = true; - - static void injectConfigChange(DisplayTransactionTest* test) { - test->mFlinger.mutableHasWideColorDisplay() = true; - test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::ENHANCED; - } - - static void setupComposerCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _)) - .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})), - Return(Error::NONE))); - EXPECT_CALL(*test->mComposer, - getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _)) - .WillOnce( - DoAll(SetArgPointee<2>(std::vector<RenderIntent>({RenderIntent::ENHANCE})), - Return(Error::NONE))); - EXPECT_CALL(*test->mComposer, - setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB, RenderIntent::ENHANCE)) - .WillOnce(Return(Error::NONE)); - } -}; - // For this variant, SurfaceFlinger should configure itself with wide display // support, but the display should respond with an empty list of supported color // modes. Wide-color support for the display should not be configured. @@ -638,9 +611,6 @@ using HwcVirtualDisplayCase = using WideColorP3ColorimetricDisplayCase = Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>, HdrNotSupportedVariant<PrimaryDisplayVariant>>; -using WideColorP3EnhanceDisplayCase = - Case<PrimaryDisplayVariant, WideColorP3EnhanceSupportedVariant<PrimaryDisplayVariant>, - HdrNotSupportedVariant<PrimaryDisplayVariant>>; using Hdr10DisplayCase = Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>, Hdr10SupportedVariant<PrimaryDisplayVariant>>; @@ -1043,10 +1013,6 @@ TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) { setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>(); } -TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3EnhanceDisplay) { - setupNewDisplayDeviceInternalTest<WideColorP3EnhanceDisplayCase>(); -} - TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) { setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>(); } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index f6895371f6..a4e73613cd 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -289,10 +289,12 @@ public: } sp<DisplayDevice> inject() { + std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hdrAndRenderIntents; sp<DisplayDevice> device = new DisplayDevice(mFlinger.mFlinger.get(), mType, mHwcId, mSecure, mDisplayToken, mNativeWindow, mDisplaySurface, std::move(mRenderSurface), 0, - 0, false, HdrCapabilities(), 0, HWC_POWER_MODE_NORMAL); + 0, false, HdrCapabilities(), 0, hdrAndRenderIntents, + HWC_POWER_MODE_NORMAL); mFlinger.mutableDisplays().add(mDisplayToken, device); DisplayDeviceState state(mType, mSecure); diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h index 29cd2d545a..93769a53e4 100644 --- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h +++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h @@ -60,7 +60,7 @@ public: MOCK_METHOD1(setupLayerTexturing, void(const Texture&)); MOCK_METHOD0(setupLayerBlackedOut, void()); MOCK_METHOD4(setupFillWithColor, void(float, float, float, float)); - MOCK_METHOD1(setupColorTransform, mat4(const mat4&)); + MOCK_METHOD1(setupColorTransform, void(const mat4&)); MOCK_METHOD0(disableTexturing, void()); MOCK_METHOD0(disableBlending, void()); MOCK_METHOD1(setSourceY410BT2020, void(bool)); |