• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "HistogramController.h"
18 
HistogramController(ExynosDisplay * display)19 HistogramController::HistogramController(ExynosDisplay* display)
20       : HistogramDevice(display, 4, {3}) {
21     for (int i = 0; i < mConfigInfos.size(); ++i)
22         mConfigInfos[i] = std::make_shared<ConfigInfo>(mPreemptConfigs[i].config);
23 }
24 
initPlatformHistogramCapability()25 void HistogramController::initPlatformHistogramCapability() {
26     mHistogramCapability.supportSamplePosList.push_back(HistogramSamplePos::PRE_POSTPROC);
27     mHistogramCapability.supportBlockingRoi = true;
28 
29 #if defined(EXYNOS_CONTEXT_HISTOGRAM_EVENT_REQUEST)
30     SCOPED_HIST_LOCK(mHistogramMutex);
31     if ((int)mFreeChannels.size() + (int)mUsedChannels.size() >= (int)mPreemptConfigs.size())
32         mHistogramCapability.supportQueryOpr = true;
33     else
34         mHistogramCapability.supportQueryOpr = false;
35 #else
36     mHistogramCapability.supportQueryOpr = false;
37 #endif
38 }
39 
queryOPR(std::array<double,kOPRConfigsCount> & oprVals)40 ndk::ScopedAStatus HistogramController::queryOPR(std::array<double, kOPRConfigsCount>& oprVals) {
41     ATRACE_CALL();
42 
43     if (waitInitDrmDone() == false) {
44         HIST_LOG(E, "initDrm is not completed yet");
45         // TODO: b/323158344 - add retry error in HistogramErrorCode and return here.
46         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
47     }
48 
49     {
50         std::shared_lock lock(mHistogramCapabilityMutex);
51         if (!mHistogramCapability.supportQueryOpr) {
52             HIST_LOG(W, "supportQueryOpr is false");
53             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
54         }
55     }
56 
57     HistogramErrorCode histogramErrorCode = HistogramErrorCode::NONE;
58 
59     const auto [displayActiveH, displayActiveV] = snapDisplayActiveSize();
60 
61     std::array<uint32_t, kOPRConfigsCount> blobIds;
62     std::array<int, kOPRConfigsCount> channelIds;
63 
64     {
65         SCOPED_HIST_LOCK(mHistogramMutex);
66         if ((histogramErrorCode = getOPRBlobs(blobIds, displayActiveH, displayActiveV)) !=
67             HistogramErrorCode::NONE)
68             return errorToStatus(histogramErrorCode);
69 
70         if ((histogramErrorCode = preemptOPRChannels()) != HistogramErrorCode::NONE)
71             return errorToStatus(histogramErrorCode);
72 
73         scheduler();
74         getOPRChannels(channelIds);
75     }
76 
77     {
78         ATRACE_NAME("HistogramOnRefresh");
79         mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
80     }
81 
82     histogramErrorCode = getOPRVals(blobIds, channelIds, oprVals);
83 
84     bool needRefresh = false;
85     {
86         // Clear configInfo for OPR request
87         SCOPED_HIST_LOCK(mHistogramMutex);
88         for (auto& configInfo : mConfigInfos) resetConfigInfoStatus(configInfo);
89         needRefresh = scheduler();
90     }
91 
92     if (needRefresh) {
93         ATRACE_NAME("HistogramOnRefresh");
94         mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
95     }
96 
97     if (histogramErrorCode != HistogramErrorCode::NONE) return errorToStatus(histogramErrorCode);
98 
99     return ndk::ScopedAStatus::ok();
100 }
101 
getOPRVals(const std::array<uint32_t,kOPRConfigsCount> & blobIds,const std::array<int,kOPRConfigsCount> & channelIds,std::array<double,kOPRConfigsCount> & oprVals)102 HistogramController::HistogramErrorCode HistogramController::getOPRVals(
103         const std::array<uint32_t, kOPRConfigsCount>& blobIds,
104         const std::array<int, kOPRConfigsCount>& channelIds,
105         std::array<double, kOPRConfigsCount>& oprVals) {
106     ATRACE_CALL();
107 
108     std::array<std::vector<char16_t>, kOPRConfigsCount> histogramBuffer;
109     std::array<std::cv_status, kOPRConfigsCount> cv_status;
110     std::array<HistogramErrorCode, kOPRConfigsCount> errorCodes;
111 
112     // Get the moduleDisplayInterface pointer
113     ExynosDisplayDrmInterface* moduleDisplayInterface =
114             static_cast<ExynosDisplayDrmInterface*>(mDisplay->mDisplayInterface.get());
115     if (!moduleDisplayInterface) {
116         HIST_LOG(E, "ENABLE_HIST_ERROR, moduleDisplayInterface is NULL");
117         return HistogramErrorCode::ENABLE_HIST_ERROR;
118     }
119 
120     // Use shared_ptr to keep the blobIdData which will be used by receiveBlobIdData and
121     // receiveBlobIdData.
122     std::array<std::shared_ptr<BlobIdData>, kOPRConfigsCount> blobIdDatas;
123     for (int i = 0; i < kOPRConfigsCount; ++i)
124         searchOrCreateBlobIdData(blobIds[i], true, blobIdDatas[i]);
125 
126     // Request the drmEvent of the blobId, hold only one uniqueLock at a time.
127     for (int i = 0; i < kOPRConfigsCount; ++i) {
128         std::shared_ptr<BlobIdData>& blobIdData = blobIdDatas[i];
129         uint32_t blobId = blobIds[i];
130         int channelId = channelIds[i];
131 
132         std::unique_lock<std::mutex> lock(blobIdData->mDataCollectingMutex);
133         ::android::base::ScopedLockAssertion lock_assertion(blobIdData->mDataCollectingMutex);
134         ATRACE_NAME(String8::format("mDataCollectingMutex(blob#%u)", blobId));
135 
136         errorCodes[i] = HistogramErrorCode::NONE;
137         requestBlobIdData(moduleDisplayInterface, &errorCodes[i], channelId, blobId, blobIdData);
138     }
139 
140     // Receive the drmEvent of the blobId, hold only one uniqueLock at a time.
141     for (int i = 0; i < kOPRConfigsCount; ++i) {
142         // If the requestBlobIdData has some error, not need to receive blobIdData.
143         if (errorCodes[i] != HistogramErrorCode::NONE) continue;
144 
145         std::shared_ptr<BlobIdData>& blobIdData = blobIdDatas[i];
146 
147         std::unique_lock<std::mutex> lock(blobIdData->mDataCollectingMutex);
148         ::android::base::ScopedLockAssertion lock_assertion(blobIdData->mDataCollectingMutex);
149         ATRACE_NAME(String8::format("mDataCollectingMutex(blob#%u)", blobIds[i]));
150 
151         cv_status[i] =
152                 receiveBlobIdData(moduleDisplayInterface, &histogramBuffer[i], &errorCodes[i],
153                                   channelIds[i], blobIds[i], blobIdData, lock);
154     }
155 
156     // Check the query result and clear the buffer if needed (no lock is held now)
157     for (int i = 0; i < blobIdDatas.size(); ++i) {
158         checkQueryResult(&histogramBuffer[i], &errorCodes[i], channelIds[i], blobIds[i],
159                          cv_status[i]);
160     }
161 
162     // Check the histogram error code
163     for (auto& error : errorCodes)
164         if (error != HistogramErrorCode::NONE) return error;
165 
166     for (int i = 0; i < kOPRConfigsCount; ++i) {
167         errorCodes[i] = calculateOPRVal(mPreemptConfigs[i].name, histogramBuffer[i], blobIds[i],
168                                         channelIds[i], oprVals[i]);
169         if (errorCodes[i] != HistogramErrorCode::NONE) return errorCodes[i];
170     }
171 
172     return HistogramErrorCode::NONE;
173 }
174 
calculateOPRVal(const char * configName,const std::vector<char16_t> & histogramBuffer,const uint32_t blobId,const int channelId,double & oprVal) const175 HistogramController::HistogramErrorCode HistogramController::calculateOPRVal(
176         const char* configName, const std::vector<char16_t>& histogramBuffer, const uint32_t blobId,
177         const int channelId, double& oprVal) const {
178     if (histogramBuffer.size() != HISTOGRAM_BINS_SIZE) {
179         HIST_LOG(E, "BAD_HIST_DATA for %s, buffer size is not %lu", configName,
180                  HISTOGRAM_BINS_SIZE);
181         return HistogramErrorCode::BAD_HIST_DATA;
182     }
183 
184     int totalPixels = 0;
185     double totalLuma = 0;
186 
187     for (int i = 0; i < HISTOGRAM_BINS_SIZE; ++i) {
188         // TODO: b/340403552 - More efficient way to convert gamma into linear space.
189         totalPixels += histogramBuffer[i];
190         totalLuma += std::pow((i / (double)(HISTOGRAM_BINS_SIZE - 1)), 2.2) * histogramBuffer[i];
191     }
192 
193     if (!totalPixels) {
194         HIST_BLOB_CH_LOG(E, blobId, channelId, "BAD_HIST_DATA for %s, pixel count is zero",
195                          configName);
196         return HistogramErrorCode::BAD_HIST_DATA;
197     }
198 
199     oprVal = totalLuma / totalPixels;
200     HIST_BLOB_CH_LOG(V, blobId, channelId, "%s channel opr: %lf, pixels count: %d", configName,
201                      oprVal, totalPixels);
202     return HistogramErrorCode::NONE;
203 }
204 
getOPRBlobs(std::array<uint32_t,kOPRConfigsCount> & blobIds,const int displayActiveH,const int displayActiveV)205 HistogramController::HistogramErrorCode HistogramController::getOPRBlobs(
206         std::array<uint32_t, kOPRConfigsCount>& blobIds, const int displayActiveH,
207         const int displayActiveV) {
208     ATRACE_CALL();
209 
210     // Get blobIds for all mPreemptConfigs
211     for (int i = 0; i < kOPRConfigsCount; ++i) {
212         auto& configInfo = mConfigInfos[i];
213         bool isBlobIdChanged = false;
214 
215         uint32_t blobId = getMatchBlobId(configInfo->mBlobsList, displayActiveH, displayActiveV,
216                                          isBlobIdChanged);
217 
218         // Create the blobId for not matched case (first time queryOPR or RRS detected)
219         int ret;
220         if (!blobId) {
221             std::shared_ptr<PropertyBlob> drmConfigBlob;
222             ret = createDrmConfigBlob(configInfo->mRequestedConfig, displayActiveH, displayActiveV,
223                                       drmConfigBlob);
224             if (ret || !drmConfigBlob) {
225                 HIST_LOG(E, "createDrmConfigBlob failed, ret(%d)", ret);
226                 return HistogramErrorCode::CONFIG_HIST_ERROR;
227             }
228 
229             // Attach the histogram drmConfigBlob to the configInfo
230             configInfo->mBlobsList.emplace_front(displayActiveH, displayActiveV, drmConfigBlob);
231             blobId = drmConfigBlob->getId();
232         }
233 
234         blobIds[i] = blobId;
235     }
236 
237     return HistogramErrorCode::NONE;
238 }
239 
getOPRChannels(std::array<int,kOPRConfigsCount> & channelIds) const240 void HistogramController::getOPRChannels(std::array<int, kOPRConfigsCount>& channelIds) const {
241     // Get channelIds
242     for (int i = 0; i < kOPRConfigsCount; ++i) channelIds[i] = mConfigInfos[i]->mChannelId;
243 }
244 
preemptOPRChannels()245 HistogramController::HistogramErrorCode HistogramController::preemptOPRChannels() {
246     ATRACE_CALL();
247 
248     for (auto& configInfo : mConfigInfos) resetConfigInfoStatus(configInfo);
249 
250     int preemptCount = (int)mConfigInfos.size() - (int)mFreeChannels.size();
251     if (preemptCount > (int)mUsedChannels.size()) {
252         HIST_LOG(E, "no channel available for preemption");
253         return HistogramErrorCode::NO_CHANNEL_AVAILABLE;
254     }
255 
256     for (int i = 0; i < preemptCount; ++i) swapOutConfigInfo(*mUsedChannels.begin());
257 
258     for (auto& configInfo : mConfigInfos) addConfigToInactiveList(configInfo, true);
259 
260     return HistogramErrorCode::NONE;
261 }
262 
postAtomicCommitCleanup()263 void HistogramController::postAtomicCommitCleanup() {
264     ATRACE_CALL();
265 
266     bool needRefresh = false;
267 
268     {
269         bool needSchedule = false;
270 
271         SCOPED_HIST_LOCK(mHistogramMutex);
272         for (int i = 0; i < kOPRConfigsCount; ++i) {
273             auto& configInfo = mConfigInfos[i];
274             if (configInfo->mStatus == ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED &&
275                 mChannels[configInfo->mChannelId].mStatus != ChannelStatus_t::CONFIG_PENDING) {
276                 needSchedule = true;
277                 resetConfigInfoStatus(configInfo);
278             }
279         }
280 
281         if (needSchedule) needRefresh = scheduler();
282     }
283 
284     if (needRefresh) {
285         ATRACE_NAME("HistogramOnRefresh");
286         mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
287     }
288 }
289 
dumpInternalConfigs(String8 & result) const290 void HistogramController::dumpInternalConfigs(String8& result) const {
291     for (int i = 0; i < kOPRConfigsCount; ++i) {
292         result.appendFormat("Histogram internal config \"%s\":\n", mPreemptConfigs[i].name);
293         if (mConfigInfos[i]) {
294             mConfigInfos[i]->dump(result, "\t");
295         } else {
296             result.appendFormat("\tconfigInfo: %p\n", mConfigInfos[i].get());
297         }
298     }
299 }
300