diff options
author | 2018-07-02 18:33:32 -0700 | |
---|---|---|
committer | 2018-07-09 10:16:25 -0700 | |
commit | 9ce2bf7e0c47fdf178c528b3a5594756e49e071e (patch) | |
tree | 7926a9c7ad0b14935666753c5604c948402b3cf1 /libs/hwui | |
parent | 8225c85200802198dae6fa05ccf87757365efb68 (diff) |
Auto-dark mode prototype
Experimental force_dark prototype mode. Enabled
by setting debug.hwui.force_dark to true.
Test: verified nothing changes without prop being set
Change-Id: Ib02f3f1a9c591cab1f312b827451f04c782c2f41
Diffstat (limited to 'libs/hwui')
-rw-r--r-- | libs/hwui/Android.bp | 1 | ||||
-rw-r--r-- | libs/hwui/CanvasTransform.cpp | 113 | ||||
-rw-r--r-- | libs/hwui/CanvasTransform.h | 40 | ||||
-rw-r--r-- | libs/hwui/Properties.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 3 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 11 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 1 |
8 files changed, 180 insertions, 1 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 0db779906545..111094bb6a2b 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -198,6 +198,7 @@ cc_defaults { "AnimatorManager.cpp", "Caches.cpp", "CanvasState.cpp", + "CanvasTransform.cpp", "ClipArea.cpp", "DamageAccumulator.cpp", "DeferredLayerUpdater.cpp", diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp new file mode 100644 index 000000000000..bac7a4d17a49 --- /dev/null +++ b/libs/hwui/CanvasTransform.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CanvasTransform.h" +#include "Properties.h" + +#include <SkColorFilter.h> +#include <SkPaint.h> +#include <log/log.h> + +namespace android::uirenderer { + +static SkColor makeLight(SkColor color) { + SkScalar hsv[3]; + SkColorToHSV(color, hsv); + if (hsv[1] > .2f) return color; + // hsv[1] *= .85f; + // hsv[2] = std::min(1.0f, std::max(hsv[2], 1 - hsv[2]) * 1.3f); + hsv[2] = std::max(hsv[2], 1.1f - hsv[2]); + return SkHSVToColor(SkColorGetA(color), hsv); +} + +static SkColor makeDark(SkColor color) { + SkScalar hsv[3]; + SkColorToHSV(color, hsv); + if (hsv[1] > .2f) return color; + // hsv[1] *= .85f; + // hsv[2] = std::max(0.0f, std::min(hsv[2], 1 - hsv[2]) * .7f); + hsv[2] = std::min(hsv[2], 1.1f - hsv[2]); + return SkHSVToColor(SkColorGetA(color), hsv); +} + +static SkColor transformColor(ColorTransform transform, SkColor color) { + switch (transform) { + case ColorTransform::Light: + return makeLight(color); + case ColorTransform::Dark: + return makeDark(color); + default: + return color; + } +} + +static void applyColorTransform(ColorTransform transform, SkPaint& paint) { + if (transform == ColorTransform::None) return; + + SkColor newColor = transformColor(transform, paint.getColor()); + paint.setColor(newColor); + + if (paint.getColorFilter()) { + SkBlendMode mode; + SkColor color; + // TODO: LRU this or something to avoid spamming new color mode filters + if (paint.getColorFilter()->asColorMode(&color, &mode)) { + color = transformColor(transform, color); + paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode)); + } + } +} + +class ColorFilterCanvas : public SkPaintFilterCanvas { +public: + ColorFilterCanvas(ColorTransform transform, SkCanvas* canvas) + : SkPaintFilterCanvas(canvas), mTransform(transform) {} + + bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const override { + if (*paint) { + applyColorTransform(mTransform, *(paint->writable())); + } + return true; + } + +private: + ColorTransform mTransform; +}; + +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform) { + switch (transform) { + case ColorTransform::Light: + return std::make_unique<ColorFilterCanvas>(ColorTransform::Light, inCanvas); + case ColorTransform::Dark: + return std::make_unique<ColorFilterCanvas>(ColorTransform::Dark, inCanvas); + default: + return nullptr; + } +} + +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint) { + if (Properties::forceDarkMode) { + switch (usageHint) { + case UsageHint::Unknown: + return makeTransformCanvas(inCanvas, ColorTransform::Light); + case UsageHint::Background: + return makeTransformCanvas(inCanvas, ColorTransform::Dark); + } + } + return nullptr; +} + +}; // namespace android::uirenderer
\ No newline at end of file diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h new file mode 100644 index 000000000000..f71fdfaf3fba --- /dev/null +++ b/libs/hwui/CanvasTransform.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <SkCanvas.h> +#include <SkPaintFilterCanvas.h> + +#include <memory> + +namespace android::uirenderer { + +enum class UsageHint { + Unknown = 0, + Background = 1, +}; + +enum class ColorTransform { + None, + Light, + Dark, +}; + +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform); +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint); + +} // namespace android::uirenderer;
\ No newline at end of file diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 0338a3aba97d..17bec1934490 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -60,6 +60,7 @@ bool Properties::forceDrawFrame = false; bool Properties::filterOutTestOverhead = false; bool Properties::disableVsync = false; bool Properties::skpCaptureEnabled = false; +bool Properties::forceDarkMode = false; bool Properties::enableRTAnimations = true; bool Properties::runningInEmulator = false; @@ -146,6 +147,8 @@ bool Properties::load() { runningInEmulator = property_get_bool(PROPERTY_QEMU_KERNEL, false); + forceDarkMode = property_get_bool(PROPERTY_FORCE_DARK, false); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) || (prevDebugStencilClip != debugStencilClip); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index d640c749d829..ea017a72cd74 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -190,6 +190,8 @@ enum DebugLevel { */ #define PROPERTY_QEMU_KERNEL "ro.kernel.qemu" +#define PROPERTY_FORCE_DARK "debug.hwui.force_dark" + /////////////////////////////////////////////////////////////////////////////// // Misc /////////////////////////////////////////////////////////////////////////////// @@ -263,6 +265,7 @@ public: static bool disableVsync; static bool skpCaptureEnabled; + static bool forceDarkMode; // For experimentation b/68769804 ANDROID_API static bool enableRTAnimations; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index dc962f307903..8393288d2ffd 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -28,6 +28,7 @@ #include <androidfw/ResourceTypes.h> #include "AnimatorManager.h" +#include "CanvasTransform.h" #include "Debug.h" #include "DisplayList.h" #include "Matrix.h" @@ -208,6 +209,14 @@ public: void output(std::ostream& output, uint32_t level); + void setUsageHint(UsageHint usageHint) { + mUsageHint = usageHint; + } + + UsageHint usageHint() const { + return mUsageHint; + } + private: void computeOrderingImpl(RenderNodeOp* opState, std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, @@ -263,6 +272,8 @@ private: sp<PositionListener> mPositionListener; + UsageHint mUsageHint = UsageHint::Unknown; + // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER public: /** diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index f0da660f17b0..6fb2ee03cb50 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -17,6 +17,7 @@ #include "SkiaRecordingCanvas.h" #include <SkImagePriv.h> +#include "CanvasTransform.h" #include "Layer.h" #include "LayerDrawable.h" #include "NinePatchUtils.h" @@ -44,13 +45,19 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in } mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height)); - SkiaCanvas::reset(&mRecorder); + SkCanvas* canvas = &mRecorder; + mWrappedCanvas = makeTransformCanvas(&mRecorder, renderNode->usageHint()); + if (mWrappedCanvas) { + canvas = mWrappedCanvas.get(); + } + SkiaCanvas::reset(canvas); } uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() { // close any existing chunks if necessary insertReorderBarrier(false); mRecorder.restoreToCount(1); + mWrappedCanvas = nullptr; return mDisplayList.release(); } diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index 93807a5476e6..b69acbf2ffb8 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -78,6 +78,7 @@ public: private: SkLiteRecorder mRecorder; std::unique_ptr<SkiaDisplayList> mDisplayList; + std::unique_ptr<SkCanvas> mWrappedCanvas; StartReorderBarrierDrawable* mCurrentBarrier; /** |