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