• 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 #pragma once
18 
19 #include <aidl/android/hardware/graphics/common/Rect.h>
20 #include <aidl/com/google/hardware/pixel/display/HistogramCapability.h>
21 #include <aidl/com/google/hardware/pixel/display/HistogramConfig.h>
22 #include <aidl/com/google/hardware/pixel/display/HistogramErrorCode.h>
23 #include <aidl/com/google/hardware/pixel/display/HistogramSamplePos.h>
24 #include <aidl/com/google/hardware/pixel/display/Weight.h>
25 #include <android-base/thread_annotations.h>
26 #include <drm/samsung_drm.h>
27 #include <utils/String8.h>
28 
29 #include <condition_variable>
30 #include <mutex>
31 #include <queue>
32 #include <unordered_map>
33 
34 #include "ExynosDisplay.h"
35 #include "ExynosDisplayDrmInterface.h"
36 #include "drmcrtc.h"
37 
38 using namespace android;
39 
40 class HistogramDevice {
41 public:
42     using HistogramCapability = aidl::com::google::hardware::pixel::display::HistogramCapability;
43     using HistogramConfig = aidl::com::google::hardware::pixel::display::HistogramConfig;
44     using HistogramErrorCode = aidl::com::google::hardware::pixel::display::HistogramErrorCode;
45     using HistogramRoiRect = aidl::android::hardware::graphics::common::Rect;
46     using HistogramSamplePos = aidl::com::google::hardware::pixel::display::HistogramSamplePos;
47     using HistogramWeights = aidl::com::google::hardware::pixel::display::Weight;
48     using HistogramChannelIoctl_t = ExynosDisplayDrmInterface::HistogramChannelIoctl_t;
49 
50     /* Histogram weight constraint: weightR + weightG + weightB = WEIGHT_SUM */
51     static constexpr size_t WEIGHT_SUM = 1024;
52 
53     /* Histogram channel status */
54     enum class ChannelStatus_t : uint32_t {
55         /* occupied by the driver for specific usage such as LHBM */
56         RESERVED = 0,
57 
58         /* channel is off */
59         DISABLED,
60 
61         /* channel config is ready and requires to be added into an atomic commit */
62         CONFIG_PENDING,
63 
64         /* channel config (blob) is added to an atomic commit but not committed yet */
65         CONFIG_BLOB_ADDED,
66 
67         /* channel config is committed to drm driver successfully */
68         CONFIG_COMMITTED,
69 
70         /* channel config has error */
71         CONFIG_ERROR,
72 
73         /* channel is released and requires an atomic commit to cleanup completely */
74         DISABLE_PENDING,
75 
76         /* channel is released and the cleanup blob is added but not committed yet */
77         DISABLE_BLOB_ADDED,
78 
79         /* channel disable has error */
80         DISABLE_ERROR,
81     };
82 
83     struct ChannelInfo {
84         /* protect the channel info fields */
85         mutable std::mutex channelInfoMutex;
86 
87         /* protect histDataCollecting variable */
88         mutable std::mutex histDataCollectingMutex;
89 
90         /* track the channel status */
91         ChannelStatus_t status GUARDED_BY(channelInfoMutex);
92 
93         /* token passed in by the histogram client */
94         ndk::SpAIBinder token GUARDED_BY(channelInfoMutex);
95 
96         /* histogram client process id */
97         pid_t pid GUARDED_BY(channelInfoMutex);
98 
99         /* requested roi from the client by registerHistogram or reconfigHistogram */
100         HistogramRoiRect requestedRoi GUARDED_BY(channelInfoMutex);
101 
102         /* histogram config that would be applied to hardware, the requestedRoi may be different
103          * from the roi described in workingConfig due to RRS (Runtime Resolution Switch) */
104         HistogramConfig workingConfig GUARDED_BY(channelInfoMutex);
105 
106         /* histogram threshold that would be applied to the hardware which is used to prevent the
107          * histogram data (16 bits) overflow */
108         int threshold GUARDED_BY(channelInfoMutex);
109 
110         /* histogram data would be stored as part of the channel info */
111         uint16_t histData[HISTOGRAM_BIN_COUNT];
112         bool histDataCollecting; // GUARDED_BY(histDataCollectingMutex);
113         std::condition_variable histDataCollecting_cv;
114 
115         ChannelInfo();
116         ChannelInfo(const ChannelInfo &other);
117     };
118 
119     /* TokenInfo is not only used to stored the corresponding channel id but also passed to the
120      * binderdied callback */
121     struct TokenInfo {
122         /* corresponding channel id of the token */
123         uint8_t channelId;
124 
125         /* pointer to the HistogramDevice, binderdied callback would use this pointer to cleanup the
126          * channel in HistogramDevice by the member function unregisterHistogram */
127         HistogramDevice *histogramDevice;
128 
129         /* binderdied callback would call unregisterHistogram with this token */
130         ndk::SpAIBinder token;
131     };
132 
133     /**
134      * HistogramDevice
135      *
136      * Construct the HistogramDevice to mange histogram channel.
137      *
138      * @display display pointer which would be stored in mDisplay.
139      * @channelCount number of the histogram channels in the system.
140      * @reservedChannels a list of channel id that are reserved by the driver.
141      */
142     explicit HistogramDevice(ExynosDisplay *display, uint8_t channelCount,
143                              std::vector<uint8_t> reservedChannels);
144 
145     /**
146      * ~HistogramDevice
147      *
148      * Destruct the HistogramDevice.
149      */
150     virtual ~HistogramDevice();
151 
152     /**
153      * initDrm
154      *
155      * Get histogram info from crtc property and initialize the mHistogramCapability.
156      *     1. The available histogram channel bitmask.
157      *     2. Determine kernel support multi channel property or not.
158      *
159      * @crtc drm crtc object which would contain histogram related information.
160      */
161     void initDrm(const DrmCrtc &crtc);
162 
163     /**
164      * getHistogramCapability
165      *
166      * Return the histogram capability for the system.
167      *
168      * @histogramCapability: describe the histogram capability for the system.
169      * @return ok() when the interface is supported and arguments are valid, else otherwise.
170      */
171     ndk::ScopedAStatus getHistogramCapability(HistogramCapability *histogramCapability) const;
172 
173     /**
174      * registerHistogram
175      *
176      * Register the histogram sampling config, and allocate a histogram channel if available.
177      * If the display is not turned on, just store the histogram config. Otherwise, trigger the
178      * onRefresh call to force the config take effect, and then the DPU hardware will continuously
179      * sample the histogram data.
180      *
181      * @token binder object created by the client whose lifetime should be equal to the client. When
182      * the binder object is destructed, the unregisterHistogram would be called automatically. Token
183      * serves as the handle in every histogram operation.
184      * @histogramConfig histogram config from the client.
185      * @histogramErrorCode NONE when no error, or else otherwise. Client should retry when failed.
186      * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
187      * is not supported yet.
188      */
189     ndk::ScopedAStatus registerHistogram(const ndk::SpAIBinder &token,
190                                          const HistogramConfig &histogramConfig,
191                                          HistogramErrorCode *histogramErrorCode);
192 
193     /**
194      * queryHistogram
195      *
196      * Query the histogram data from the corresponding channel of the token.
197      *
198      * @token is the handle registered via registerHistogram which would be used to identify the
199      * channel.
200      * @histogramBuffer 256 * 16 bits buffer to store the luma counts return by the histogram
201      * hardware.
202      * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
203      * errorcode.
204      * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
205      * is not supported yet.
206      */
207     ndk::ScopedAStatus queryHistogram(const ndk::SpAIBinder &token,
208                                       std::vector<char16_t> *histogramBuffer,
209                                       HistogramErrorCode *histogramErrorCode);
210 
211     /**
212      * reconfigHistogram
213      *
214      * Change the histogram config for the corresponding channel of the token.
215      *
216      * @token is the handle registered via registerHistogram which would be used to identify the
217      * channel.
218      * @histogramConfig histogram config from the client.
219      * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
220      * errorcode.
221      * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
222      * is not supported yet.
223      */
224     ndk::ScopedAStatus reconfigHistogram(const ndk::SpAIBinder &token,
225                                          const HistogramConfig &histogramConfig,
226                                          HistogramErrorCode *histogramErrorCode);
227 
228     /**
229      * unregisterHistogram
230      *
231      * Release the corresponding channel of the token and add the channel id to free channel list.
232      *
233      * @token is the handle registered via registerHistogram which would be used to identify the
234      * channel.
235      * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
236      * errorcode.
237      * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
238      * is not supported yet.
239      */
240     ndk::ScopedAStatus unregisterHistogram(const ndk::SpAIBinder &token,
241                                            HistogramErrorCode *histogramErrorCode);
242 
243     /**
244      * handleDrmEvent
245      *
246      * Handle the histogram channel drm event (EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT) and copy the
247      * histogram data from event struct to channel info.
248      *
249      * @event histogram channel drm event pointer (struct exynos_drm_histogram_channel_event *)
250      */
251     void handleDrmEvent(void *event);
252 
253     /**
254      * prepareAtomicCommit
255      *
256      * Prepare the histogram atomic commit for each channel (see prepareChannelCommit).
257      *
258      * @drmReq drm atomic request object
259      */
260     void prepareAtomicCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq);
261 
262     /**
263      * postAtomicCommit
264      *
265      * After the atomic commit is done, update the channel status as below.
266      * Channel_Status:
267      *     CONFIG_BLOB_ADDED  -> CONFIG_COMMITTED
268      *     DISABLE_BLOB_ADDED -> DISABLED
269      */
270     void postAtomicCommit();
271 
272     /**
273      * dump
274      *
275      * Dump every histogram channel information.
276      *
277      * @result histogram channel dump information would be appended to this string
278      */
279     void dump(String8 &result) const;
280 
281 protected:
282     HistogramCapability mHistogramCapability;
283 
284 private:
285     mutable std::mutex mAllocatorMutex;
286     std::queue<uint8_t> mFreeChannels GUARDED_BY(mAllocatorMutex); // free channel list
287     std::unordered_map<AIBinder *, TokenInfo> mTokenInfoMap GUARDED_BY(mAllocatorMutex);
288     std::vector<ChannelInfo> mChannels;
289     ExynosDisplay *mDisplay = nullptr;
290 
291     /* Death recipient for the binderdied callback, would be deleted in the destructor */
292     AIBinder_DeathRecipient *mDeathRecipient = nullptr;
293 
294     /**
295      * initChannels
296      *
297      * Allocate channelCount channels and initialize the channel status for every channel.
298      *
299      * @channelCount number of channels in the system including the reserved channels.
300      * @reservedChannels a list of channel id that are reserved by the driver.
301      */
302     void initChannels(uint8_t channelCount, const std::vector<uint8_t> &reservedChannels);
303 
304     /**
305      * initHistogramCapability
306      *
307      * Initialize the histogramCapability which would be queried by the client (see
308      * getHistogramCapability).
309      *
310      * @supportMultiChannel true if the kernel support multi channel property, false otherwise.
311      */
312     void initHistogramCapability(bool supportMultiChannel);
313 
314     /**
315      * initSupportSamplePosList
316      *
317      * Initialize the supported sample position list.
318      */
319     virtual void initSupportSamplePosList();
320 
321     /**
322      * configHistogram
323      *
324      * Implementation of the registerHistogram and reconfigHistogram.
325      *
326      * @token binder object created by the client.
327      * @histogramConfig histogram config requested by the client.
328      * @histogramErrorCode::NONE when success, or else otherwise.
329      * @isReconfig is true if it is not the register request, only need to change the config.
330      * @return ok() when the interface is supported, or else otherwise.
331      */
332     ndk::ScopedAStatus configHistogram(const ndk::SpAIBinder &token,
333                                        const HistogramConfig &histogramConfig,
334                                        HistogramErrorCode *histogramErrorCode, bool isReconfig);
335 
336     /**
337      * getHistogramData
338      *
339      * Get the histogram data by sending ioctl request which will allocate the drm event for
340      * histogram, and wait on the condition variable histDataCollecting_cv until the drm event is
341      * handled or timeout. Copy the histogram data from channel info to histogramBuffer.
342      *
343      * @channelId histogram channel id.
344      * @histogramBuffer AIDL created buffer which will be sent back to the client.
345      * @histogramErrorCode::NONE when success, or else otherwise.
346      */
347     void getHistogramData(uint8_t channelId, std::vector<char16_t> *histogramBuffer,
348                           HistogramErrorCode *histogramErrorCode);
349 
350     /**
351      * parseDrmEvent
352      *
353      * Parse the histogram drm event (struct may vary between different platform), need to be
354      * overrided in the derived HistogramController class if needed. This function should get the
355      * histogram channel id and the histogram buffer address from the event struct.
356      *
357      * @event histogram drm event struct.
358      * @channelId stores the extracted channel id from the event.
359      * @buffer stores the extracted buffer address from the event.
360      * @return NO_ERROR on success, else otherwise.
361      */
362     virtual int parseDrmEvent(void *event, uint8_t &channelId, char16_t *&buffer) const;
363 
364     /**
365      * acquireChannelLocked
366      *
367      * Acquire an available channel from the mFreeChannels, and record the token to channel id
368      * mapping info. Should be called with mAllocatorMutex held.
369      *
370      * @token binder object created by the client.
371      * @channelId store the acquired channel id.
372      * @return HistogramErrorCode::NONE when success, or else otherwise.
373      */
374     HistogramErrorCode acquireChannelLocked(const ndk::SpAIBinder &token, uint8_t &channelId)
375             REQUIRES(mAllocatorMutex);
376 
377     /**
378      * releaseChannelLocked
379      *
380      * Find the corresponding channel id of the token and release the channel. Add the channel id to
381      * the mFreeChannels and cleanup the channel. Should be called with mAllocatorMutex held.
382      *
383      * @channelId the channel id to be cleanup.
384      */
385     void releaseChannelLocked(uint8_t channelId) REQUIRES(mAllocatorMutex);
386 
387     /**
388      * getChannelIdByTokenLocked
389      *
390      * Convert the token to the channel id. Should be called with mAllocatorMutex held.
391      *
392      * @token binder object created by the client.
393      * @return HistogramErrorCode::NONE when success, or else otherwise.
394      */
395     HistogramErrorCode getChannelIdByTokenLocked(const ndk::SpAIBinder &token, uint8_t &channelId)
396             REQUIRES(mAllocatorMutex);
397 
398     /**
399      * cleanupChannelInfo
400      *
401      * Cleanup the channel info and set status to DISABLE_PENDING which means need to wait
402      * for the atomic commit to release the kernel and hardware channel resources.
403      *
404      * @channelId the channel id to be cleanup.
405      */
406     void cleanupChannelInfo(uint8_t channelId);
407 
408     /**
409      * fillupChannelInfo
410      *
411      * Fillup the channel info with the histogramConfig from the client, and set status to
412      * CONFIG_PENDING which means need to wait for the atomic commit to configure the
413      * channel.
414      *
415      * @channelId the channel id to be configured.
416      * @token binder object created by the client.
417      * @histogramConfig histogram config requested by the client.
418      * @threshold histogram threshold calculated from the roi.
419      */
420     void fillupChannelInfo(uint8_t channelId, const ndk::SpAIBinder &token,
421                            const HistogramConfig &histogramConfig, int threshold);
422 
423     /**
424      * prepareChannelCommit
425      *
426      * For the histogram channel needed to be configured, prepare the histogram channel config into
427      * the struct histogram_channel_config which will be used to creating the drm blob in
428      * setDisplayHistogramChannelSetting.
429      * ChannelStatus_t:
430      *     CONFIG_PENDING -> CONFIG_BLOB_ADDED
431      *     CONFIG_DONE (detect roi needs update due to resolution change) -> CONFIG_BLOB_ADDED
432      *
433      * For the histogram channel needed to be disabled, call clearDisplayHistogramChannelSetting to
434      * disable.
435      * ChannelStatus_t:
436      *     DISABLE_PENDING -> DISABLE_BLOB_ADDED
437      *
438      * @drmReq drm atomic request object
439      * @channelId histogram channel id
440      * @return NO_ERROR on success, else otherwise
441      */
442     int prepareChannelCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
443                              uint8_t channelId);
444 
445     /**
446      * createHistogramDrmConfigLocked
447      *
448      * Allocate and initialize the histogram config for the drm driver. Composer would trigger
449      * setDisplayHistogramChannelSetting and create the property blob with this config. The
450      * allcoated config should be deleted via deleteHistogramDrmConfig after the property blob
451      * is created. This function should be called with channelInfoMutex hold.
452      *
453      * @channel histogram channel.
454      * @configPtr shared pointer to the allocated histogram config struct.
455      * @length size of the histogram config.
456      * @return NO_ERROR on success, else otherwise
457      */
458     virtual int createHistogramDrmConfigLocked(const ChannelInfo &channel,
459                                                std::shared_ptr<void> &configPtr,
460                                                size_t &length) const
461             REQUIRES(channel.channelInfoMutex);
462 
463     /**
464      * convertRoiLocked
465      *
466      * Linear transform the requested roi (based on panel full resolution) into the working roi
467      * (active resolution).
468      *
469      * @moduleDisplayInterface the displayInterface which contains the full resolution info
470      * @requestedRoi requested roi
471      * @workingRoi converted roi from the requested roi
472      * @return NO_ERROR on success, else otherwise
473      */
474     int convertRoiLocked(ExynosDisplayDrmInterface *moduleDisplayInterface,
475                          const HistogramRoiRect &requestedRoi, HistogramRoiRect &workingRoi) const;
476 
477     void dumpHistogramCapability(String8 &result) const;
478 
479     HistogramErrorCode validateHistogramConfig(const HistogramConfig &histogramConfig) const;
480     HistogramErrorCode validateHistogramRoi(const HistogramRoiRect &roi) const;
481     HistogramErrorCode validateHistogramWeights(const HistogramWeights &weights) const;
482     HistogramErrorCode validateHistogramSamplePos(const HistogramSamplePos &samplePos) const;
483 
484     static int calculateThreshold(const HistogramRoiRect &roi);
485     static std::string toString(const ChannelStatus_t &status);
486     static std::string toString(const HistogramRoiRect &roi);
487     static std::string toString(const HistogramWeights &weights);
488 };
489