summaryrefslogtreecommitdiff
path: root/libhwc2.1/libdevice/HistogramDevice.h
blob: ee74cae7c567c144ce41856f4285fe812b40076a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
/*
 * Copyright (C) 2023 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 <aidl/android/hardware/graphics/common/Rect.h>
#include <aidl/com/google/hardware/pixel/display/HistogramCapability.h>
#include <aidl/com/google/hardware/pixel/display/HistogramConfig.h>
#include <aidl/com/google/hardware/pixel/display/HistogramErrorCode.h>
#include <aidl/com/google/hardware/pixel/display/HistogramSamplePos.h>
#include <aidl/com/google/hardware/pixel/display/Weight.h>
#include <android-base/thread_annotations.h>
#include <drm/samsung_drm.h>
#include <utils/String8.h>

#include <condition_variable>
#include <mutex>
#include <queue>
#include <unordered_map>

#include "ExynosDisplay.h"
#include "ExynosDisplayDrmInterface.h"
#include "drmcrtc.h"

using namespace android;

class HistogramDevice {
public:
    using HistogramCapability = aidl::com::google::hardware::pixel::display::HistogramCapability;
    using HistogramConfig = aidl::com::google::hardware::pixel::display::HistogramConfig;
    using HistogramErrorCode = aidl::com::google::hardware::pixel::display::HistogramErrorCode;
    using HistogramRoiRect = aidl::android::hardware::graphics::common::Rect;
    using HistogramSamplePos = aidl::com::google::hardware::pixel::display::HistogramSamplePos;
    using HistogramWeights = aidl::com::google::hardware::pixel::display::Weight;
    using HistogramChannelIoctl_t = ExynosDisplayDrmInterface::HistogramChannelIoctl_t;

    /* Histogram weight constraint: weightR + weightG + weightB = WEIGHT_SUM */
    static constexpr size_t WEIGHT_SUM = 1024;

    /* Histogram channel status */
    enum class ChannelStatus_t : uint32_t {
        /* occupied by the driver for specific usage such as LHBM */
        RESERVED = 0,

        /* channel is off */
        DISABLED,

        /* channel config is ready and requires to be added into an atomic commit */
        CONFIG_PENDING,

        /* channel config (blob) is added to an atomic commit but not committed yet */
        CONFIG_BLOB_ADDED,

        /* channel config is committed to drm driver successfully */
        CONFIG_COMMITTED,

        /* channel config has error */
        CONFIG_ERROR,

        /* channel is released and requires an atomic commit to cleanup completely */
        DISABLE_PENDING,

        /* channel is released and the cleanup blob is added but not committed yet */
        DISABLE_BLOB_ADDED,

        /* channel disable has error */
        DISABLE_ERROR,
    };

    struct ChannelInfo {
        /* protect the channel info fields */
        mutable std::mutex channelInfoMutex;

        /* protect histDataCollecting variable */
        mutable std::mutex histDataCollectingMutex;

        /* track the channel status */
        ChannelStatus_t status GUARDED_BY(channelInfoMutex);

        /* token passed in by the histogram client */
        ndk::SpAIBinder token GUARDED_BY(channelInfoMutex);

        /* histogram client process id */
        pid_t pid GUARDED_BY(channelInfoMutex);

        /* requested roi from the client by registerHistogram or reconfigHistogram */
        HistogramRoiRect requestedRoi GUARDED_BY(channelInfoMutex);

        /* histogram config that would be applied to hardware, the requestedRoi may be different
         * from the roi described in workingConfig due to RRS (Runtime Resolution Switch) */
        HistogramConfig workingConfig GUARDED_BY(channelInfoMutex);

        /* histogram threshold that would be applied to the hardware which is used to prevent the
         * histogram data (16 bits) overflow */
        int threshold GUARDED_BY(channelInfoMutex);

        /* histogram data would be stored as part of the channel info */
        uint16_t histData[HISTOGRAM_BIN_COUNT];
        bool histDataCollecting; // GUARDED_BY(histDataCollectingMutex);
        std::condition_variable histDataCollecting_cv;

        ChannelInfo();
        ChannelInfo(const ChannelInfo &other);
    };

    /* TokenInfo is not only used to stored the corresponding channel id but also passed to the
     * binderdied callback */
    struct TokenInfo {
        /* corresponding channel id of the token */
        uint8_t channelId;

        /* pointer to the HistogramDevice, binderdied callback would use this pointer to cleanup the
         * channel in HistogramDevice by the member function unregisterHistogram */
        HistogramDevice *histogramDevice;

        /* binderdied callback would call unregisterHistogram with this token */
        ndk::SpAIBinder token;
    };

    /**
     * HistogramDevice
     *
     * Construct the HistogramDevice to mange histogram channel.
     *
     * @display display pointer which would be stored in mDisplay.
     * @channelCount number of the histogram channels in the system.
     * @reservedChannels a list of channel id that are reserved by the driver.
     */
    explicit HistogramDevice(ExynosDisplay *display, uint8_t channelCount,
                             std::vector<uint8_t> reservedChannels);

    /**
     * ~HistogramDevice
     *
     * Destruct the HistogramDevice.
     */
    virtual ~HistogramDevice();

    /**
     * initDrm
     *
     * Get histogram info from crtc property and initialize the mHistogramCapability.
     *     1. The available histogram channel bitmask.
     *     2. Determine kernel support multi channel property or not.
     *
     * @crtc drm crtc object which would contain histogram related information.
     */
    void initDrm(const DrmCrtc &crtc);

    /**
     * getHistogramCapability
     *
     * Return the histogram capability for the system.
     *
     * @histogramCapability: describe the histogram capability for the system.
     * @return ok() when the interface is supported and arguments are valid, else otherwise.
     */
    ndk::ScopedAStatus getHistogramCapability(HistogramCapability *histogramCapability) const;

    /**
     * registerHistogram
     *
     * Register the histogram sampling config, and allocate a histogram channel if available.
     * If the display is not turned on, just store the histogram config. Otherwise, trigger the
     * onRefresh call to force the config take effect, and then the DPU hardware will continuously
     * sample the histogram data.
     *
     * @token binder object created by the client whose lifetime should be equal to the client. When
     * the binder object is destructed, the unregisterHistogram would be called automatically. Token
     * serves as the handle in every histogram operation.
     * @histogramConfig histogram config from the client.
     * @histogramErrorCode NONE when no error, or else otherwise. Client should retry when failed.
     * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
     * is not supported yet.
     */
    ndk::ScopedAStatus registerHistogram(const ndk::SpAIBinder &token,
                                         const HistogramConfig &histogramConfig,
                                         HistogramErrorCode *histogramErrorCode);

    /**
     * queryHistogram
     *
     * Query the histogram data from the corresponding channel of the token.
     *
     * @token is the handle registered via registerHistogram which would be used to identify the
     * channel.
     * @histogramBuffer 256 * 16 bits buffer to store the luma counts return by the histogram
     * hardware.
     * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
     * errorcode.
     * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
     * is not supported yet.
     */
    ndk::ScopedAStatus queryHistogram(const ndk::SpAIBinder &token,
                                      std::vector<char16_t> *histogramBuffer,
                                      HistogramErrorCode *histogramErrorCode);

    /**
     * reconfigHistogram
     *
     * Change the histogram config for the corresponding channel of the token.
     *
     * @token is the handle registered via registerHistogram which would be used to identify the
     * channel.
     * @histogramConfig histogram config from the client.
     * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
     * errorcode.
     * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
     * is not supported yet.
     */
    ndk::ScopedAStatus reconfigHistogram(const ndk::SpAIBinder &token,
                                         const HistogramConfig &histogramConfig,
                                         HistogramErrorCode *histogramErrorCode);

    /**
     * unregisterHistogram
     *
     * Release the corresponding channel of the token and add the channel id to free channel list.
     *
     * @token is the handle registered via registerHistogram which would be used to identify the
     * channel.
     * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
     * errorcode.
     * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
     * is not supported yet.
     */
    ndk::ScopedAStatus unregisterHistogram(const ndk::SpAIBinder &token,
                                           HistogramErrorCode *histogramErrorCode);

    /**
     * handleDrmEvent
     *
     * Handle the histogram channel drm event (EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT) and copy the
     * histogram data from event struct to channel info.
     *
     * @event histogram channel drm event pointer (struct exynos_drm_histogram_channel_event *)
     */
    void handleDrmEvent(void *event);

    /**
     * prepareAtomicCommit
     *
     * Prepare the histogram atomic commit for each channel (see prepareChannelCommit).
     *
     * @drmReq drm atomic request object
     */
    void prepareAtomicCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq);

    /**
     * postAtomicCommit
     *
     * After the atomic commit is done, update the channel status as below.
     * Channel_Status:
     *     CONFIG_BLOB_ADDED  -> CONFIG_COMMITTED
     *     DISABLE_BLOB_ADDED -> DISABLED
     */
    void postAtomicCommit();

    /**
     * dump
     *
     * Dump every histogram channel information.
     *
     * @result histogram channel dump information would be appended to this string
     */
    void dump(String8 &result) const;

protected:
    HistogramCapability mHistogramCapability;

private:
    mutable std::mutex mAllocatorMutex;
    std::queue<uint8_t> mFreeChannels GUARDED_BY(mAllocatorMutex); // free channel list
    std::unordered_map<AIBinder *, TokenInfo> mTokenInfoMap GUARDED_BY(mAllocatorMutex);
    std::vector<ChannelInfo> mChannels;
    ExynosDisplay *mDisplay = nullptr;

    /* Death recipient for the binderdied callback, would be deleted in the destructor */
    AIBinder_DeathRecipient *mDeathRecipient = nullptr;

    /**
     * initChannels
     *
     * Allocate channelCount channels and initialize the channel status for every channel.
     *
     * @channelCount number of channels in the system including the reserved channels.
     * @reservedChannels a list of channel id that are reserved by the driver.
     */
    void initChannels(uint8_t channelCount, const std::vector<uint8_t> &reservedChannels);

    /**
     * initHistogramCapability
     *
     * Initialize the histogramCapability which would be queried by the client (see
     * getHistogramCapability).
     *
     * @supportMultiChannel true if the kernel support multi channel property, false otherwise.
     */
    void initHistogramCapability(bool supportMultiChannel);

    /**
     * initSupportSamplePosList
     *
     * Initialize the supported sample position list.
     */
    virtual void initSupportSamplePosList();

    /**
     * configHistogram
     *
     * Implementation of the registerHistogram and reconfigHistogram.
     *
     * @token binder object created by the client.
     * @histogramConfig histogram config requested by the client.
     * @histogramErrorCode::NONE when success, or else otherwise.
     * @isReconfig is true if it is not the register request, only need to change the config.
     * @return ok() when the interface is supported, or else otherwise.
     */
    ndk::ScopedAStatus configHistogram(const ndk::SpAIBinder &token,
                                       const HistogramConfig &histogramConfig,
                                       HistogramErrorCode *histogramErrorCode, bool isReconfig);

    /**
     * getHistogramData
     *
     * Get the histogram data by sending ioctl request which will allocate the drm event for
     * histogram, and wait on the condition variable histDataCollecting_cv until the drm event is
     * handled or timeout. Copy the histogram data from channel info to histogramBuffer.
     *
     * @channelId histogram channel id.
     * @histogramBuffer AIDL created buffer which will be sent back to the client.
     * @histogramErrorCode::NONE when success, or else otherwise.
     */
    void getHistogramData(uint8_t channelId, std::vector<char16_t> *histogramBuffer,
                          HistogramErrorCode *histogramErrorCode);

    /**
     * parseDrmEvent
     *
     * Parse the histogram drm event (struct may vary between different platform), need to be
     * overrided in the derived HistogramController class if needed. This function should get the
     * histogram channel id and the histogram buffer address from the event struct.
     *
     * @event histogram drm event struct.
     * @channelId stores the extracted channel id from the event.
     * @buffer stores the extracted buffer address from the event.
     * @return NO_ERROR on success, else otherwise.
     */
    virtual int parseDrmEvent(void *event, uint8_t &channelId, char16_t *&buffer) const;

    /**
     * acquireChannelLocked
     *
     * Acquire an available channel from the mFreeChannels, and record the token to channel id
     * mapping info. Should be called with mAllocatorMutex held.
     *
     * @token binder object created by the client.
     * @channelId store the acquired channel id.
     * @return HistogramErrorCode::NONE when success, or else otherwise.
     */
    HistogramErrorCode acquireChannelLocked(const ndk::SpAIBinder &token, uint8_t &channelId)
            REQUIRES(mAllocatorMutex);

    /**
     * releaseChannelLocked
     *
     * Find the corresponding channel id of the token and release the channel. Add the channel id to
     * the mFreeChannels and cleanup the channel. Should be called with mAllocatorMutex held.
     *
     * @channelId the channel id to be cleanup.
     */
    void releaseChannelLocked(uint8_t channelId) REQUIRES(mAllocatorMutex);

    /**
     * getChannelIdByTokenLocked
     *
     * Convert the token to the channel id. Should be called with mAllocatorMutex held.
     *
     * @token binder object created by the client.
     * @return HistogramErrorCode::NONE when success, or else otherwise.
     */
    HistogramErrorCode getChannelIdByTokenLocked(const ndk::SpAIBinder &token, uint8_t &channelId)
            REQUIRES(mAllocatorMutex);

    /**
     * cleanupChannelInfo
     *
     * Cleanup the channel info and set status to DISABLE_PENDING which means need to wait
     * for the atomic commit to release the kernel and hardware channel resources.
     *
     * @channelId the channel id to be cleanup.
     */
    void cleanupChannelInfo(uint8_t channelId);

    /**
     * fillupChannelInfo
     *
     * Fillup the channel info with the histogramConfig from the client, and set status to
     * CONFIG_PENDING which means need to wait for the atomic commit to configure the
     * channel.
     *
     * @channelId the channel id to be configured.
     * @token binder object created by the client.
     * @histogramConfig histogram config requested by the client.
     * @threshold histogram threshold calculated from the roi.
     */
    void fillupChannelInfo(uint8_t channelId, const ndk::SpAIBinder &token,
                           const HistogramConfig &histogramConfig, int threshold);

    /**
     * prepareChannelCommit
     *
     * For the histogram channel needed to be configured, prepare the histogram channel config into
     * the struct histogram_channel_config which will be used to creating the drm blob in
     * setDisplayHistogramChannelSetting.
     * ChannelStatus_t:
     *     CONFIG_PENDING -> CONFIG_BLOB_ADDED
     *     CONFIG_DONE (detect roi needs update due to resolution change) -> CONFIG_BLOB_ADDED
     *
     * For the histogram channel needed to be disabled, call clearDisplayHistogramChannelSetting to
     * disable.
     * ChannelStatus_t:
     *     DISABLE_PENDING -> DISABLE_BLOB_ADDED
     *
     * @drmReq drm atomic request object
     * @channelId histogram channel id
     * @return NO_ERROR on success, else otherwise
     */
    int prepareChannelCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
                             uint8_t channelId);

    /**
     * createHistogramDrmConfigLocked
     *
     * Allocate and initialize the histogram config for the drm driver. Composer would trigger
     * setDisplayHistogramChannelSetting and create the property blob with this config. The
     * allcoated config should be deleted via deleteHistogramDrmConfig after the property blob
     * is created. This function should be called with channelInfoMutex hold.
     *
     * @channel histogram channel.
     * @configPtr shared pointer to the allocated histogram config struct.
     * @length size of the histogram config.
     * @return NO_ERROR on success, else otherwise
     */
    virtual int createHistogramDrmConfigLocked(const ChannelInfo &channel,
                                               std::shared_ptr<void> &configPtr,
                                               size_t &length) const
            REQUIRES(channel.channelInfoMutex);

    /**
     * convertRoiLocked
     *
     * Linear transform the requested roi (based on panel full resolution) into the working roi
     * (active resolution).
     *
     * @moduleDisplayInterface the displayInterface which contains the full resolution info
     * @requestedRoi requested roi
     * @workingRoi converted roi from the requested roi
     * @return NO_ERROR on success, else otherwise
     */
    int convertRoiLocked(ExynosDisplayDrmInterface *moduleDisplayInterface,
                         const HistogramRoiRect &requestedRoi, HistogramRoiRect &workingRoi) const;

    void dumpHistogramCapability(String8 &result) const;

    HistogramErrorCode validateHistogramConfig(const HistogramConfig &histogramConfig) const;
    HistogramErrorCode validateHistogramRoi(const HistogramRoiRect &roi) const;
    HistogramErrorCode validateHistogramWeights(const HistogramWeights &weights) const;
    HistogramErrorCode validateHistogramSamplePos(const HistogramSamplePos &samplePos) const;

    static int calculateThreshold(const HistogramRoiRect &roi);
    static std::string toString(const ChannelStatus_t &status);
    static std::string toString(const HistogramRoiRect &roi);
    static std::string toString(const HistogramWeights &weights);
};