1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import android.os.SystemClock;
20 
21 import com.android.graphics.hwui.flags.Flags;
22 
23 import java.util.function.Consumer;
24 
25 /** @hide */
26 class HdrRenderState implements Consumer<Display> {
27     // Targeting an animation from 1x to 5x over 400ms means we need to increase by 0.01/ms
28     private static final float TRANSITION_PER_MS = 0.01f;
29 
30     private static final boolean FLAG_ANIMATE_ENABLED = Flags.animateHdrTransitions();
31 
32     private final ViewRootImpl mViewRoot;
33 
34     private boolean mIsHdrEnabled = false;
35     private boolean mIsListenerRegistered = false;
36     private boolean mUpdateHdrSdrRatioInfo = false;
37     private float mDesiredHdrSdrRatio = 1f;
38     private float mTargetDesiredHdrSdrRatio = 1f;
39     private float mTargetHdrSdrRatio = 1f;
40     private float mRenderHdrSdrRatio = 1f;
41     private float mPreviousRenderRatio = 1f;
42     private long mLastUpdateMillis = -1;
43 
HdrRenderState(ViewRootImpl viewRoot)44     HdrRenderState(ViewRootImpl viewRoot) {
45         mViewRoot = viewRoot;
46     }
47 
48     @Override
accept(Display display)49     public void accept(Display display) {
50         forceUpdateHdrSdrRatio();
51         mViewRoot.invalidate();
52     }
53 
isHdrEnabled()54     boolean isHdrEnabled() {
55         return mIsHdrEnabled;
56     }
57 
stopListening()58     void stopListening() {
59         if (mIsListenerRegistered) {
60             mViewRoot.mDisplay.unregisterHdrSdrRatioChangedListener(this);
61             mIsListenerRegistered = false;
62         }
63     }
64 
startListening()65     void startListening() {
66         if (isHdrEnabled() && !mIsListenerRegistered && mViewRoot.mDisplay != null) {
67             mViewRoot.mDisplay.registerHdrSdrRatioChangedListener(mViewRoot.mExecutor, this);
68             mIsListenerRegistered = true;
69         }
70     }
71 
72     /** @return true if something changed, else false */
updateForFrame(long frameTimeMillis)73     boolean updateForFrame(long frameTimeMillis) {
74         boolean hasUpdate = mUpdateHdrSdrRatioInfo;
75         mUpdateHdrSdrRatioInfo = false;
76         mRenderHdrSdrRatio = mTargetHdrSdrRatio;
77         long timeDelta = Math.max(Math.min(32, frameTimeMillis - mLastUpdateMillis), 8);
78         final float maxStep = timeDelta * TRANSITION_PER_MS;
79         mLastUpdateMillis = frameTimeMillis;
80         if (hasUpdate && FLAG_ANIMATE_ENABLED) {
81             if (isHdrEnabled()) {
82                 float delta = mTargetHdrSdrRatio - mPreviousRenderRatio;
83                 if (delta > maxStep) {
84                     mRenderHdrSdrRatio = mPreviousRenderRatio + maxStep;
85                     mUpdateHdrSdrRatioInfo = true;
86                     mViewRoot.invalidate();
87                 }
88                 mPreviousRenderRatio = mRenderHdrSdrRatio;
89 
90                 if (mTargetDesiredHdrSdrRatio < mDesiredHdrSdrRatio) {
91                     mDesiredHdrSdrRatio = Math.max(mTargetDesiredHdrSdrRatio,
92                             mDesiredHdrSdrRatio - maxStep);
93                     if (mDesiredHdrSdrRatio != mTargetDesiredHdrSdrRatio) {
94                         mUpdateHdrSdrRatioInfo = true;
95                         mViewRoot.invalidate();
96                     }
97                 }
98 
99             } else {
100                 mPreviousRenderRatio = mTargetHdrSdrRatio;
101                 mDesiredHdrSdrRatio = mTargetDesiredHdrSdrRatio;
102             }
103         }
104         return hasUpdate;
105     }
106 
getDesiredHdrSdrRatio()107     float getDesiredHdrSdrRatio() {
108         return mDesiredHdrSdrRatio;
109     }
110 
getRenderHdrSdrRatio()111     float getRenderHdrSdrRatio() {
112         return mRenderHdrSdrRatio;
113     }
114 
forceUpdateHdrSdrRatio()115     void forceUpdateHdrSdrRatio() {
116         if (isHdrEnabled()) {
117             mTargetHdrSdrRatio = Math.min(mDesiredHdrSdrRatio,
118                     mViewRoot.mDisplay.getHdrSdrRatio());
119         } else {
120             mTargetHdrSdrRatio = 1.0f;
121         }
122         mUpdateHdrSdrRatioInfo = true;
123     }
124 
setDesiredHdrSdrRatio(boolean isHdrEnabled, float desiredRatio)125     void setDesiredHdrSdrRatio(boolean isHdrEnabled, float desiredRatio) {
126         mIsHdrEnabled = isHdrEnabled;
127         mLastUpdateMillis = SystemClock.uptimeMillis();
128         if (desiredRatio != mTargetDesiredHdrSdrRatio) {
129             mTargetDesiredHdrSdrRatio = desiredRatio;
130             if (mTargetDesiredHdrSdrRatio > mDesiredHdrSdrRatio || !FLAG_ANIMATE_ENABLED) {
131                 mDesiredHdrSdrRatio = mTargetDesiredHdrSdrRatio;
132             }
133             forceUpdateHdrSdrRatio();
134             mViewRoot.invalidate();
135 
136             if (isHdrEnabled()) {
137                 startListening();
138             } else {
139                 stopListening();
140             }
141         }
142     }
143 }
144