1 /*
2 * Copyright (C) 2019 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 #ifndef _EXYNOSDISPLAYDRMINTERFACE_H
18 #define _EXYNOSDISPLAYDRMINTERFACE_H
19
20 #include <drm/samsung_drm.h>
21 #include <utils/Condition.h>
22 #include <utils/Mutex.h>
23 #include <xf86drmMode.h>
24
25 #include <list>
26 #include <unordered_map>
27
28 #include "ExynosDisplay.h"
29 #include "ExynosDisplayInterface.h"
30 #include "ExynosHWC.h"
31 #include "ExynosMPP.h"
32 #include "drmconnector.h"
33 #include "drmcrtc.h"
34 #include "vsyncworker.h"
35
36 /* Max plane number of buffer object */
37 #define HWC_DRM_BO_MAX_PLANES 4
38
39 #ifndef HWC_FORCE_PANIC_PATH
40 #define HWC_FORCE_PANIC_PATH "/d/dpu/panic"
41 #endif
42
43 using namespace android;
44 using DrmPropertyMap = std::unordered_map<uint32_t, uint64_t>;
45
46 class ExynosDevice;
47
48 using BufHandles = std::array<uint32_t, HWC_DRM_BO_MAX_PLANES>;
49 class FramebufferManager {
50 public:
FramebufferManager()51 FramebufferManager(){};
52 ~FramebufferManager();
53 void init(int drmFd);
54
55 // get buffer for provided config, if a buffer with same config is already cached it will be
56 // reused otherwise one will be allocated. returns fbId that can be used to attach to the
57 // plane, any buffers allocated/reused with this call will be bound to the corresponding
58 // layer. Those fbIds will be cleaned up once the layer was destroyed.
59 int32_t getBuffer(const exynos_win_config_data &config, uint32_t &fbId);
60
61 bool checkShrink();
62
63 void cleanup(const ExynosLayer *layer);
64
65 // The flip function is to help clean up the cached fbIds of destroyed
66 // layers after the previous fdIds were update successfully on the
67 // screen.
68 // This should be called after the frame update.
69 void flip(bool hasSecureFrameBuffer);
70
71 // release all currently tracked buffers, this can be called for example when display is turned
72 // off
73 void releaseAll();
74
75 private:
76 // this struct should contain elements that can be used to identify framebuffer more easily
77 struct Framebuffer {
78 struct BufferDesc {
79 uint64_t bufferId;
80 int drmFormat;
81 bool isSecure;
82 bool operator==(const Framebuffer::BufferDesc &rhs) const {
83 return (bufferId == rhs.bufferId && drmFormat == rhs.drmFormat &&
84 isSecure == rhs.isSecure);
85 }
86 };
87 struct SolidColorDesc {
88 uint32_t width;
89 uint32_t height;
90 bool operator==(const Framebuffer::SolidColorDesc &rhs) const {
91 return (width == rhs.width && height == rhs.height);
92 }
93 };
94
FramebufferFramebuffer95 explicit Framebuffer(int fd, uint32_t fb, BufferDesc desc)
96 : drmFd(fd), fbId(fb), bufferDesc(desc){};
FramebufferFramebuffer97 explicit Framebuffer(int fd, uint32_t fb, SolidColorDesc desc)
98 : drmFd(fd), fbId(fb), colorDesc(desc){};
~FramebufferFramebuffer99 ~Framebuffer() { drmModeRmFB(drmFd, fbId); };
100 int drmFd;
101 uint32_t fbId;
102 union {
103 BufferDesc bufferDesc;
104 SolidColorDesc colorDesc;
105 };
106 };
107 using FBList = std::list<std::unique_ptr<Framebuffer>>;
108
109 template <class UnaryPredicate>
110 uint32_t findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate);
111 int addFB2WithModifiers(uint32_t width, uint32_t height, uint32_t pixel_format,
112 const BufHandles handles, const uint32_t pitches[4],
113 const uint32_t offsets[4], const uint64_t modifier[4], uint32_t *buf_id,
114 uint32_t flags);
115 uint32_t getBufHandleFromFd(int fd);
116 void freeBufHandle(uint32_t handle);
117 void removeFBsThreadRoutine();
118
119 void markInuseLayerLocked(const ExynosLayer *layer) REQUIRES(mMutex);
120 void destroyUnusedLayersLocked() REQUIRES(mMutex);
121 void destroySecureFramebufferLocked() REQUIRES(mMutex);
122
123 int mDrmFd = -1;
124
125 // mCachedLayerBuffers map keep the relationship between Layer and
126 // FBList. The map entry will be deleted once the layer is destroyed.
127 std::map<const ExynosLayer *, FBList> mCachedLayerBuffers;
128
129 // mCleanBuffers list keeps fbIds of destroyed layers. Those fbIds will
130 // be destroyed in mRmFBThread thread.
131 FBList mCleanBuffers;
132
133 // mCacheShrinkPending is set when we want to clean up unused layers
134 // in mCachedLayerBuffers. When the flag is set, mCachedLayersInuse will
135 // keep in-use layers in this frame update. Those unused layers will be
136 // freed at the end of the update.
137 // TODO: have a better way to maintain inuse layers
138 bool mCacheShrinkPending = false;
139 bool mHasSecureFramebuffer = false;
140 std::set<const ExynosLayer *> mCachedLayersInuse;
141
142 std::thread mRmFBThread;
143 bool mRmFBThreadRunning = false;
144 Condition mFlipDone;
145 Mutex mMutex;
146
147 static constexpr size_t MAX_CACHED_LAYERS = 16;
148 static constexpr size_t MAX_CACHED_BUFFERS_PER_LAYER = 32;
149 };
150
isFramebuffer(const ExynosLayer * layer)151 inline bool isFramebuffer(const ExynosLayer *layer) {
152 return layer == nullptr;
153 }
154
155 template <class UnaryPredicate>
findCachedFbId(const ExynosLayer * layer,UnaryPredicate predicate)156 uint32_t FramebufferManager::findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate) {
157 Mutex::Autolock lock(mMutex);
158 markInuseLayerLocked(layer);
159 const auto &cachedBuffers = mCachedLayerBuffers[layer];
160 const auto it = std::find_if(cachedBuffers.begin(), cachedBuffers.end(), predicate);
161 return (it != cachedBuffers.end()) ? (*it)->fbId : 0;
162 }
163
164 class ExynosDisplayDrmInterface :
165 public ExynosDisplayInterface,
166 public VsyncCallback
167 {
168 public:
169 class DrmModeAtomicReq {
170 public:
171 DrmModeAtomicReq(ExynosDisplayDrmInterface *displayInterface);
172 ~DrmModeAtomicReq();
173
174 DrmModeAtomicReq(const DrmModeAtomicReq&) = delete;
175 DrmModeAtomicReq& operator=(const DrmModeAtomicReq&) = delete;
176
pset()177 drmModeAtomicReqPtr pset() { return mPset; };
savePset()178 void savePset() {
179 if (mSavedPset) {
180 drmModeAtomicFree(mSavedPset);
181 }
182 mSavedPset = drmModeAtomicDuplicate(mPset);
183 }
restorePset()184 void restorePset() {
185 if (mPset) {
186 drmModeAtomicFree(mPset);
187 }
188 mPset = mSavedPset;
189 mSavedPset = NULL;
190 }
191
setError(int err)192 void setError(int err) { mError = err; };
getError()193 int getError() { return mError; };
194 int32_t atomicAddProperty(const uint32_t id,
195 const DrmProperty &property,
196 uint64_t value, bool optional = false);
197 String8& dumpAtomicCommitInfo(String8 &result, bool debugPrint = false);
198 int commit(uint32_t flags, bool loggingForDebug = false);
addOldBlob(uint32_t blob_id)199 void addOldBlob(uint32_t blob_id) {
200 mOldBlobs.push_back(blob_id);
201 };
destroyOldBlobs()202 int destroyOldBlobs() {
203 for (auto &blob : mOldBlobs) {
204 int ret = mDrmDisplayInterface->mDrmDevice->DestroyPropertyBlob(blob);
205 if (ret) {
206 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
207 "Failed to destroy old blob after commit %d", ret);
208 return ret;
209 }
210 }
211 mOldBlobs.clear();
212 return NO_ERROR;
213 };
214 private:
215 drmModeAtomicReqPtr mPset;
216 drmModeAtomicReqPtr mSavedPset;
217 int mError = 0;
218 ExynosDisplayDrmInterface *mDrmDisplayInterface = NULL;
219 /* Destroy old blobs after commit */
220 std::vector<uint32_t> mOldBlobs;
drmFd()221 int drmFd() const { return mDrmDisplayInterface->mDrmDevice->fd(); }
222 };
223 class ExynosVsyncCallback {
224 public:
enableVSync(bool enable)225 void enableVSync(bool enable) {
226 mVsyncEnabled = enable;
227 resetVsyncTimeStamp();
228 };
getVSyncEnabled()229 bool getVSyncEnabled() { return mVsyncEnabled; };
setDesiredVsyncPeriod(uint64_t period)230 void setDesiredVsyncPeriod(uint64_t period) {
231 mDesiredVsyncPeriod = period;
232 resetVsyncTimeStamp();
233 };
getDesiredVsyncPeriod()234 uint64_t getDesiredVsyncPeriod() { return mDesiredVsyncPeriod;};
getVsyncTimeStamp()235 uint64_t getVsyncTimeStamp() { return mVsyncTimeStamp; };
getVsyncPeriod()236 uint64_t getVsyncPeriod() { return mVsyncPeriod; };
237 bool Callback(int display, int64_t timestamp);
resetVsyncTimeStamp()238 void resetVsyncTimeStamp() { mVsyncTimeStamp = 0; };
resetDesiredVsyncPeriod()239 void resetDesiredVsyncPeriod() { mDesiredVsyncPeriod = 0;};
240 private:
241 bool mVsyncEnabled = false;
242 uint64_t mVsyncTimeStamp = 0;
243 uint64_t mVsyncPeriod = 0;
244 uint64_t mDesiredVsyncPeriod = 0;
245 };
246 void Callback(int display, int64_t timestamp) override;
247
248 ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay);
249 ~ExynosDisplayDrmInterface();
250 virtual void init(ExynosDisplay *exynosDisplay);
251 virtual int32_t setPowerMode(int32_t mode);
252 virtual int32_t setLowPowerMode() override;
isDozeModeAvailable()253 virtual bool isDozeModeAvailable() const {
254 return mDozeDrmMode.h_display() > 0 && mDozeDrmMode.v_display() > 0;
255 };
256 virtual int32_t setVsyncEnabled(uint32_t enabled);
257 virtual int32_t getDisplayConfigs(
258 uint32_t* outNumConfigs,
259 hwc2_config_t* outConfigs);
260 virtual void dumpDisplayConfigs();
261 virtual bool supportDataspace(int32_t dataspace);
262 virtual int32_t getColorModes(uint32_t* outNumModes, int32_t* outModes);
263 virtual int32_t setColorMode(int32_t mode);
264 virtual int32_t setActiveConfig(hwc2_config_t config);
265 virtual int32_t setCursorPositionAsync(uint32_t x_pos, uint32_t y_pos);
266 virtual int32_t updateHdrCapabilities();
267 virtual int32_t deliverWinConfigData();
268 virtual int32_t clearDisplay(bool needModeClear = false);
269 virtual int32_t disableSelfRefresh(uint32_t disable);
270 virtual int32_t setForcePanic();
getDisplayFd()271 virtual int getDisplayFd() { return mDrmDevice->fd(); };
272 virtual int32_t initDrmDevice(DrmDevice *drmDevice);
273 virtual uint32_t getDrmDisplayId(uint32_t type, uint32_t index);
274 virtual uint32_t getMaxWindowNum();
275 virtual int32_t getReadbackBufferAttributes(int32_t* /*android_pixel_format_t*/ outFormat,
276 int32_t* /*android_dataspace_t*/ outDataspace);
277 virtual int32_t getDisplayIdentificationData(uint8_t* outPort,
278 uint32_t* outDataSize, uint8_t* outData);
279
280 /* For HWC 2.4 APIs */
281 virtual int32_t getDisplayVsyncPeriod(
282 hwc2_vsync_period_t* outVsyncPeriod);
283 virtual int32_t getConfigChangeDuration();
284 virtual int32_t getVsyncAppliedTime(hwc2_config_t config,
285 int64_t* actualChangeTime);
286 virtual int32_t setActiveConfigWithConstraints(
287 hwc2_config_t config, bool test = false);
288
setDisplayColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)289 virtual int32_t setDisplayColorSetting(
290 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
291 { return NO_ERROR;};
setPlaneColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const std::unique_ptr<DrmPlane> & plane,const exynos_win_config_data & config)292 virtual int32_t setPlaneColorSetting(
293 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
294 const std::unique_ptr<DrmPlane> &plane,
295 const exynos_win_config_data& config)
296 { return NO_ERROR;};
297 virtual int32_t updateBrightness(bool syncFrame);
298 virtual float getSdrDimRatio();
299 virtual void destroyLayer(ExynosLayer *layer) override;
300
301 virtual int32_t waitVBlank();
isHbmOn()302 bool isHbmOn() {
303 return mBrightnessCtrl.HbmMode.get() != static_cast<uint32_t>(HbmMode::OFF);
304 }
getDbv()305 uint32_t getDbv() { return mBrightnessLevel.get(); }
getDesiredRefreshRate()306 float getDesiredRefreshRate() { return mDesiredModeState.mode.v_refresh(); }
307 protected:
308 struct ModeState {
309 bool needs_modeset = false;
310 DrmMode mode;
311 uint32_t blob_id = 0;
312 uint32_t old_blob_id = 0;
setModeModeState313 void setMode(const DrmMode newMode, const uint32_t modeBlob,
314 DrmModeAtomicReq &drmReq) {
315 drmReq.addOldBlob(old_blob_id);
316 mode = newMode;
317 old_blob_id = blob_id;
318 blob_id = modeBlob;
319 };
resetModeState320 void reset() {
321 *this = {};
322 };
applyModeState323 void apply(ModeState &toModeState, DrmModeAtomicReq &drmReq) {
324 toModeState.setMode(mode, blob_id, drmReq);
325 drmReq.addOldBlob(old_blob_id);
326 reset();
327 };
328 };
329 int32_t createModeBlob(const DrmMode &mode, uint32_t &modeBlob);
330 int32_t setDisplayMode(DrmModeAtomicReq &drmReq, const uint32_t modeBlob);
331 int32_t clearDisplayMode(DrmModeAtomicReq &drmReq);
332 int32_t chosePreferredConfig();
333 int getDeconChannel(ExynosMPP *otfMPP);
334 static std::tuple<uint64_t, int> halToDrmEnum(
335 const int32_t halData, const DrmPropertyMap &drmEnums);
336 /*
337 * This function adds FB and gets new fb id if fbId is 0,
338 * if fbId is not 0, this reuses fbId.
339 */
340 int32_t setupCommitFromDisplayConfig(DrmModeAtomicReq &drmReq,
341 const exynos_win_config_data &config,
342 const uint32_t configIndex,
343 const std::unique_ptr<DrmPlane> &plane,
344 uint32_t &fbId);
345
346 int32_t setupPartialRegion(DrmModeAtomicReq &drmReq);
347 static void parseEnums(const DrmProperty &property,
348 const std::vector<std::pair<uint32_t, const char *>> &enums,
349 DrmPropertyMap &out_enums);
350 void parseBlendEnums(const DrmProperty &property);
351 void parseStandardEnums(const DrmProperty &property);
352 void parseTransferEnums(const DrmProperty &property);
353 void parseRangeEnums(const DrmProperty &property);
354 void parseColorModeEnums(const DrmProperty &property);
355
356 int32_t setupWritebackCommit(DrmModeAtomicReq &drmReq);
357 int32_t clearWritebackCommit(DrmModeAtomicReq &drmReq);
358
359 private:
360 int32_t updateColorSettings(DrmModeAtomicReq &drmReq, uint64_t dqeEnabled);
361 int32_t getLowPowerDrmModeModeInfo();
362 int32_t setActiveDrmMode(DrmMode const &mode);
363
364 protected:
365 struct PartialRegionState {
366 struct drm_clip_rect partial_rect = {0, 0, 0, 0};
367 uint32_t blob_id = 0;
isUpdatedPartialRegionState368 bool isUpdated(drm_clip_rect rect) {
369 return ((partial_rect.x1 != rect.x1) ||
370 (partial_rect.y1 != rect.y1) ||
371 (partial_rect.x2 != rect.x2) ||
372 (partial_rect.y2 != rect.y2));
373 };
374 };
375
376 class DrmReadbackInfo {
377 public:
378 void init(DrmDevice *drmDevice, uint32_t displayId);
~DrmReadbackInfo()379 ~DrmReadbackInfo() {
380 if (mDrmDevice == NULL)
381 return;
382 if (mOldFbId > 0)
383 drmModeRmFB(mDrmDevice->fd(), mOldFbId);
384 if (mFbId > 0)
385 drmModeRmFB(mDrmDevice->fd(), mFbId);
386 }
getWritebackConnector()387 DrmConnector* getWritebackConnector() { return mWritebackConnector; };
setFbId(uint32_t fbId)388 void setFbId(uint32_t fbId) {
389 if ((mDrmDevice != NULL) && (mOldFbId > 0))
390 drmModeRmFB(mDrmDevice->fd(), mOldFbId);
391 mOldFbId = mFbId;
392 mFbId = fbId;
393 }
394 void pickFormatDataspace();
395 static constexpr uint32_t PREFERRED_READBACK_FORMAT =
396 HAL_PIXEL_FORMAT_RGBA_8888;
397 uint32_t mReadbackFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
398 bool mNeedClearReadbackCommit = false;
399 private:
400 DrmDevice *mDrmDevice = NULL;
401 DrmConnector *mWritebackConnector = NULL;
402 uint32_t mFbId = 0;
403 uint32_t mOldFbId = 0;
404 std::vector<uint32_t> mSupportedFormats;
405 };
406 DrmDevice *mDrmDevice;
407 DrmCrtc *mDrmCrtc;
408 DrmConnector *mDrmConnector;
409 VSyncWorker mDrmVSyncWorker;
410 ExynosVsyncCallback mVsyncCallback;
411 ModeState mActiveModeState;
412 ModeState mDesiredModeState;
413 PartialRegionState mPartialRegionState;
414 /* Mapping plane id to ExynosMPP, key is plane id */
415 std::unordered_map<uint32_t, ExynosMPP*> mExynosMPPsForPlane;
416
417 DrmPropertyMap mBlendEnums;
418 DrmPropertyMap mStandardEnums;
419 DrmPropertyMap mTransferEnums;
420 DrmPropertyMap mRangeEnums;
421 DrmPropertyMap mColorModeEnums;
422
423 DrmReadbackInfo mReadbackInfo;
424
425 private:
426 DrmMode mDozeDrmMode;
427
428 protected:
429 void getBrightnessInterfaceSupport();
430 void setupBrightnessConfig();
431 void parseHbmModeEnums(const DrmProperty &property);
432 void checkHbmSvDimming();
433 void endHbmSvDimming();
434 FILE *mHbmModeFd;
435 FILE *mDimmingOnFd;
436 bool mBrightntessIntfSupported = false;
437 float mBrightnessHbmMax = 1.0f;
438 enum class PanelHbmType {
439 ONE_STEP,
440 CONTINUOUS,
441 };
442 enum BrightnessRange {
443 NORMAL = 0,
444 HBM,
445 MAX,
446 };
447 enum class HbmMode {
448 OFF = 0,
449 ON_IRC_ON,
450 ON_IRC_OFF,
451 };
452
453 DrmPropertyMap mHbmModeEnums;
454 PanelHbmType mPanelHbmType;
455
456 Mutex mBrightnessUpdateMutex;
457 brightnessState_t mBrightnessState;
458 CtrlValue<uint32_t> mBrightnessLevel;
459 float mScaledBrightness;
460 typedef struct brightnessCtrl {
461 CtrlValue<bool> DimmingOn;
462 CtrlValue<uint32_t> HbmMode;
463 CtrlValue<bool> LhbmOn;
resetbrightnessCtrl464 void reset() {
465 DimmingOn.store(false);
466 DimmingOn.clear_dirty();
467 HbmMode.store(0);
468 HbmMode.clear_dirty();
469 LhbmOn.store(false);
470 LhbmOn.clear_dirty();
471 }
472 } brightnessCtrl_t;
473 brightnessCtrl_t mBrightnessCtrl;
474
475 struct BrightnessTable {
476 float mBriStart;
477 float mBriEnd;
478 uint32_t mBklStart;
479 uint32_t mBklEnd;
480 uint32_t mNitsStart;
481 uint32_t mNitsEnd;
BrightnessTableBrightnessTable482 BrightnessTable() {}
BrightnessTableBrightnessTable483 BrightnessTable(const brightness_attribute &attr)
484 : mBriStart(static_cast<float>(attr.percentage.min) / 100.0f),
485 mBriEnd(static_cast<float>(attr.percentage.max) / 100.0f),
486 mBklStart(attr.level.min),
487 mBklEnd(attr.level.max),
488 mNitsStart(attr.nits.min),
489 mNitsEnd(attr.nits.max) {}
490 };
491 struct BrightnessTable mBrightnessTable[BrightnessRange::MAX];
492
493 // TODO: hbm in dual display is not supported. It should support it in
494 // the furture.
495 static constexpr const char *kHbmModeFileNode =
496 "/sys/class/backlight/panel%d-backlight/hbm_mode";
497 static constexpr const char *kDimmingOnFileNode =
498 "/sys/class/backlight/panel%d-backlight/dimming_on";
499
500 static constexpr int32_t kHbmDimmingTimeUs = 5000000;
501
502 FramebufferManager mFBManager;
503
504 /*
505 * BrightnessDimmingUsage:
506 * NORMAL- enable dimming
507 * HBM- enable dimming only for hbm transition
508 * NONE- disable dimming
509 */
510 enum class BrightnessDimmingUsage {
511 NORMAL = 0,
512 HBM,
513 NONE,
514 };
515
516 BrightnessDimmingUsage mBrightnessDimmingUsage;
517 bool mHbmSvDimming;
518 int32_t mHbmDimmingTimeUs;
519 std::thread mDimmingThread;
520 bool mHbmSvDimmingThreadRunning;
521 Condition mHbmSvDimmingCond;
522 Mutex mHbmSvDimmingMutex;
523
524 private:
525 int32_t getDisplayFakeEdid(uint8_t &outPort, uint32_t &outDataSize, uint8_t *outData);
526 };
527
528 #endif
529