1 /*
2  * Copyright (C) 2022 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 "ExynosResourceManagerModule.h"
18 
19 #include <cutils/properties.h>
20 
21 #include <list>
22 #include <utility>
23 
24 #include "ExynosLayer.h"
25 
26 using namespace zuma;
27 
28 constexpr uint32_t TDM_OVERLAP_MARGIN = 68;
29 
30 constexpr uint32_t kSramSBWCWidthAlign = 32;
31 constexpr uint32_t kSramSBWCWidthMargin = kSramSBWCWidthAlign - 1;
32 constexpr uint32_t kSramSBWCRotWidthAlign = 4;
33 constexpr uint32_t kSramAFBC8B4BAlign = 8;
34 constexpr uint32_t kSramAFBC8B4BMargin = kSramAFBC8B4BAlign - 1;
35 constexpr uint32_t kSramAFBC2BAlign = 16;
36 constexpr uint32_t kSramAFBC2BMargin = kSramAFBC2BAlign - 1;
37 
ExynosResourceManagerModule(ExynosDevice * device)38 ExynosResourceManagerModule::ExynosResourceManagerModule(ExynosDevice *device)
39 : gs201::ExynosResourceManagerModule(device)
40 {
41     // HW Resource Table for TDM based allocation
42     mHWResourceTables = &HWResourceTables;
43 
44     char value[PROPERTY_VALUE_MAX];
45     property_get("ro.boot.hw.soc.rev", value, "2");
46     const int socRev = atoi(value);
47     mConstraintRev = socRev < 2 ? CONSTRAINT_A0 : CONSTRAINT_B0;
48     HWAttrs.at(TDM_ATTR_WCG).loadSharing =
49             (mConstraintRev == CONSTRAINT_A0) ? LS_DPUF : LS_DPUF_AXI;
50     ALOGD("%s(): ro.boot.hw.soc.rev=%s ConstraintRev=%d", __func__, value, mConstraintRev);
51 }
52 
~ExynosResourceManagerModule()53 ExynosResourceManagerModule::~ExynosResourceManagerModule() {}
54 
checkTDMResource(ExynosDisplay * display,ExynosMPP * currentMPP,ExynosMPPSource * mppSrc)55 bool ExynosResourceManagerModule::checkTDMResource(ExynosDisplay *display, ExynosMPP *currentMPP,
56                                                    ExynosMPPSource *mppSrc) {
57     std::array<uint32_t, TDM_ATTR_MAX> accumulatedDPUFAmount{};
58     std::array<uint32_t, TDM_ATTR_MAX> accumulatedDPUFAXIAmount{};
59     const uint32_t blkId = currentMPP->getHWBlockId();
60     const uint32_t axiId = currentMPP->getAXIPortId();
61     HDEBUGLOGD(eDebugTDM, "%s : %p trying to assign to %s, compare with layers", __func__,
62                mppSrc->mSrcImg.bufferHandle, currentMPP->mName.c_str());
63     ExynosLayer *layer = (mppSrc->mSourceType == MPP_SOURCE_LAYER) ? (ExynosLayer *)mppSrc : nullptr;
64 
65     for (auto compLayer : display->mLayers) {
66         ExynosMPP *otfMPP = compLayer->mOtfMPP;
67         if (!otfMPP || layer == compLayer) continue;
68         getAmounts(display, blkId, axiId, otfMPP, mppSrc, compLayer,
69                    accumulatedDPUFAmount, accumulatedDPUFAXIAmount);
70     }
71 
72     if (display->mExynosCompositionInfo.mHasCompositionLayer) {
73         HDEBUGLOGD(eDebugTDM,
74                    "%s : %p trying to assign to %s, compare with ExynosComposition Target buffer",
75                    __func__, mppSrc->mSrcImg.bufferHandle, currentMPP->mName.c_str());
76         ExynosMPP *otfMPP = display->mExynosCompositionInfo.mOtfMPP;
77         if (otfMPP)
78             getAmounts(display, blkId, axiId, otfMPP, mppSrc, &display->mExynosCompositionInfo,
79                        accumulatedDPUFAmount, accumulatedDPUFAXIAmount);
80     }
81 
82     if (display->mClientCompositionInfo.mHasCompositionLayer) {
83         HDEBUGLOGD(eDebugTDM,
84                    "%s : %p trying to assign to %s, compare with ClientComposition Target buffer",
85                    __func__, mppSrc->mSrcImg.bufferHandle, currentMPP->mName.c_str());
86         ExynosMPP *otfMPP = display->mClientCompositionInfo.mOtfMPP;
87         if (otfMPP)
88             getAmounts(display, blkId, axiId, otfMPP, mppSrc, &display->mClientCompositionInfo,
89                        accumulatedDPUFAmount, accumulatedDPUFAXIAmount);
90     }
91 
92     for (auto attr = HWAttrs.begin(); attr != HWAttrs.end(); attr++) {
93         const LoadSharing_t &loadSharing = attr->second.loadSharing;
94         uint32_t currentAmount = mppSrc->getHWResourceAmount(attr->first);
95         auto &accumulatedAmount =
96                 (loadSharing == LS_DPUF) ? accumulatedDPUFAmount : accumulatedDPUFAXIAmount;
97         const auto &TDMInfoIdx =
98                 std::make_pair(blkId,
99                                (loadSharing == LS_DPUF) ? AXI_DONT_CARE : axiId);
100         int32_t totalAmount =
101                 display->mDisplayTDMInfo[TDMInfoIdx].getAvailableAmount(attr->first).totalAmount;
102         HDEBUGLOGD(eDebugTDM,
103                    "%s, layer[%p] -> %s attr[%s],ls=%d,accumulated:%d,current:%d,total: %d",
104                    __func__, mppSrc->mSrcImg.bufferHandle, currentMPP->mName.c_str(),
105                    attr->second.name.c_str(), loadSharing, accumulatedAmount[attr->first],
106                    currentAmount, totalAmount);
107         if (accumulatedAmount[attr->first] + currentAmount > totalAmount) {
108             HDEBUGLOGD(eDebugTDM, "%s, %s could not assigned by attr[%s]", __func__,
109                        currentMPP->mName.c_str(), attr->second.name.c_str());
110             return false;
111         }
112     }
113 
114     HDEBUGLOGD(eDebugTDM, "%s : %p trying to assign to %s successfully", __func__,
115                mppSrc->mSrcImg.bufferHandle, currentMPP->mName.c_str());
116     return true;
117 }
118 
isHWResourceAvailable(ExynosDisplay * display,ExynosMPP * currentMPP,ExynosMPPSource * mppSrc)119 bool ExynosResourceManagerModule::isHWResourceAvailable(ExynosDisplay *display,
120                                                         ExynosMPP *currentMPP,
121                                                         ExynosMPPSource *mppSrc) {
122     if (!checkTDMResource(display, currentMPP, mppSrc)) {
123         return false;
124     }
125 
126     std::list<ExynosLayer *> overlappedLayers;
127     uint32_t currentBlockId = currentMPP->getHWBlockId();
128     for (auto layer : display->mLayers) {
129         ExynosMPP *otfMPP = layer->mOtfMPP;
130         if (!otfMPP || dynamic_cast<ExynosMPPSource *>(layer) == mppSrc) continue;
131 
132         if ((currentBlockId == otfMPP->getHWBlockId()) && isOverlapped(display, mppSrc, layer))
133             overlappedLayers.push_back(layer);
134     }
135 
136     if (overlappedLayers.size()) {
137         HDEBUGLOGD(eDebugTDM,
138                    "%s : %p trying to assign to %s, check its overlapped layers(%zu) status",
139                    __func__, mppSrc->mSrcImg.bufferHandle, currentMPP->mName.c_str(),
140                    overlappedLayers.size());
141 
142         for (auto &overlappedLayer : overlappedLayers) {
143             HDEBUGLOGD(eDebugTDM, "%s : %p overlapped %p", __func__, mppSrc->mSrcImg.bufferHandle,
144                        overlappedLayer->mLayerBuffer);
145             if (!checkTDMResource(display, overlappedLayer->mOtfMPP, overlappedLayer)) {
146                 return false;
147             }
148         }
149     }
150     return true;
151 }
152 
setupHWResource(const tdm_attr_t & tdmAttrId,const String8 & name,const DPUblockId_t & blkId,const AXIPortId_t & axiId,ExynosDisplay * mainDisp,ExynosDisplay * minorDisp,const ConstraintRev_t & constraintsRev)153 void ExynosResourceManagerModule::setupHWResource(const tdm_attr_t& tdmAttrId, const String8& name,
154                                                   const DPUblockId_t& blkId,
155                                                   const AXIPortId_t& axiId, ExynosDisplay* mainDisp,
156                                                   ExynosDisplay* minorDisp,
157                                                   const ConstraintRev_t& constraintsRev) {
158     const auto& resourceIdx = HWResourceIndexes(tdmAttrId, blkId, axiId, constraintsRev);
159     const auto &iter = mHWResourceTables->find(resourceIdx);
160     if (iter != mHWResourceTables->end()) {
161         auto &hwResource = iter->second;
162         const auto &TDMInfoIdx = (HWAttrs.at(tdmAttrId).loadSharing == LS_DPUF)
163                 ? std::make_pair(blkId, AXI_DONT_CARE)
164                 : std::make_pair(blkId, axiId);
165         if (mainDisp != nullptr) {
166             const uint32_t mainAmount = (minorDisp != nullptr)
167                     ? hwResource.mainAmount
168                     : hwResource.mainAmount + hwResource.minorAmount;
169             mainDisp->mDisplayTDMInfo[TDMInfoIdx]
170                     .initTDMInfo(DisplayTDMInfo::ResourceAmount_t{mainAmount}, tdmAttrId);
171         }
172         if (minorDisp != nullptr) {
173             const uint32_t minorAmount = hwResource.minorAmount;
174             minorDisp->mDisplayTDMInfo[TDMInfoIdx]
175                     .initTDMInfo(DisplayTDMInfo::ResourceAmount_t{minorAmount}, tdmAttrId);
176         }
177     } else {
178         ALOGW("(%s): cannot find resource for %s", resourceIdx.toString8().c_str(), name.c_str());
179     }
180 }
181 
setDisplaysTDMInfo(ExynosDisplay * mainDisp,ExynosDisplay * minorDisp)182 uint32_t ExynosResourceManagerModule::setDisplaysTDMInfo(ExynosDisplay* mainDisp,
183                                                          ExynosDisplay* minorDisp) {
184     /*
185      * Update main/minor display resource amount
186      * If only one display exists, all TDM resources are allocated for the only display.
187      */
188     for (auto attr = HWAttrs.begin(); attr != HWAttrs.end(); attr++) {
189         for (auto blockId = DPUBlocks.begin(); blockId != DPUBlocks.end(); blockId++) {
190             if (attr->second.loadSharing == LS_DPUF) {
191                 setupHWResource(attr->first, attr->second.name, blockId->first, AXI_DONT_CARE,
192                                 mainDisp, minorDisp, mConstraintRev);
193             } else if (attr->second.loadSharing == LS_DPUF_AXI) {
194                 for (auto axi = AXIPorts.begin(); axi != AXIPorts.end(); ++axi) {
195                     setupHWResource(attr->first, attr->second.name, blockId->first, axi->first,
196                                     mainDisp, minorDisp, mConstraintRev);
197                 }
198             }
199             else {
200                 ALOGE("%s attr[%s] wrong load sharing=%d", __func__, attr->second.name.c_str(),
201                                                            attr->second.loadSharing);
202                 return BAD_TYPE;
203             }
204         }
205     }
206 
207     if (hwcCheckDebugMessages(eDebugTDM)) {
208         for (auto &display : mDisplays) {
209             if (!(display->mPlugState == true && display->mPowerModeState.has_value() &&
210                   display->mPowerModeState.value() != (hwc2_power_mode_t)HWC_POWER_MODE_OFF))
211                 continue;
212             for (auto attr = HWAttrs.begin(); attr != HWAttrs.end(); attr++) {
213                 for (auto blockId = DPUBlocks.begin(); blockId != DPUBlocks.end(); blockId++) {
214                     if (attr->second.loadSharing == LS_DPUF) {
215                         const auto &TDMInfoId = std::make_pair(blockId->first, AXI_DONT_CARE);
216                         int32_t amount = display->mDisplayTDMInfo[TDMInfoId]
217                                                  .getAvailableAmount(attr->first)
218                                                  .totalAmount;
219                         HDEBUGLOGD(eDebugTDM, "%s : [%s] display:%d,block:%d, amount : %d(%s)",
220                                    __func__, attr->second.name.c_str(), display->mDisplayId,
221                                    blockId->first, amount,
222                                    display->isEnabled() ? "used" : "not used");
223                     } else {
224                         for (auto axi = AXIPorts.begin(); axi != AXIPorts.end(); ++axi) {
225                             const auto &TDMInfoId = std::make_pair(blockId->first, axi->first);
226                             int32_t amount = display->mDisplayTDMInfo[TDMInfoId]
227                                                      .getAvailableAmount(attr->first)
228                                                      .totalAmount;
229                             HDEBUGLOGD(eDebugTDM,
230                                        "%s : [%s] display:%d,block:%d,axi:%d, amount:%d(%s)",
231                                        __func__, attr->second.name.c_str(), display->mType,
232                                        blockId->first, axi->first, amount,
233                                        display->isEnabled() ? "used" : "not used");
234                         }
235                     }
236                 }
237             }
238         }
239     }
240 
241     return NO_ERROR;
242 }
243 
getSramAmount(tdm_attr_t attr,uint32_t formatProperty,lbWidthIndex_t widthIndex)244 uint32_t getSramAmount(tdm_attr_t attr, uint32_t formatProperty, lbWidthIndex_t widthIndex) {
245     auto it = sramAmountMap.find(sramAmountParams(attr, formatProperty, widthIndex));
246     return (it != sramAmountMap.end()) ? it->second : 0;
247 }
248 
calculateHWResourceAmount(ExynosDisplay * display,ExynosMPPSource * mppSrc)249 uint32_t ExynosResourceManagerModule::calculateHWResourceAmount(ExynosDisplay *display,
250                                                                 ExynosMPPSource *mppSrc)
251 {
252     uint32_t SRAMtotal = 0;
253 
254     if (mppSrc == nullptr) return SRAMtotal;
255 
256     if (mppSrc->mSourceType == MPP_SOURCE_LAYER) {
257         ExynosLayer *layer = static_cast<ExynosLayer *>(mppSrc->mSource);
258         if (layer == nullptr) {
259             ALOGE("%s: cannot cast ExynosLayer", __func__);
260             return SRAMtotal;
261         }
262         exynos_image src_img;
263         exynos_image dst_img;
264         layer->setSrcExynosImage(&src_img);
265         layer->setDstExynosImage(&dst_img);
266         layer->setExynosImage(src_img, dst_img);
267     }
268 
269     int32_t transform = mppSrc->mSrcImg.transform;
270     int32_t compressType = mppSrc->mSrcImg.compressionInfo.type;
271     bool rotation = (transform & HAL_TRANSFORM_ROT_90) ? true : false;
272 
273     int32_t width = mppSrc->mSrcImg.w;
274     int32_t height = mppSrc->mSrcImg.h;
275     uint32_t format = mppSrc->mSrcImg.format;
276     uint32_t formatBPP = 0;
277     if (isFormat10Bit(format))
278         formatBPP = BIT10;
279     else if (isFormat8Bit(format))
280         formatBPP = BIT8;
281 
282     /** To find index **/
283     uint32_t formatIndex = 0;
284 
285     lbWidthIndex_t widthIndex = LB_W_3073_INF;
286 
287     auto findWidthIndex = [&](int32_t w) -> lbWidthIndex_t {
288         for (auto it = LB_WIDTH_INDEX_MAP.begin(); it != LB_WIDTH_INDEX_MAP.end(); it++) {
289             if (w >= it->second.widthDownto && w <= it->second.widthUpto) {
290                 return it->first;
291             }
292         }
293         return LB_W_3073_INF;
294     };
295 
296     /* Caluclate SRAM amount */
297     if (rotation) {
298         width = height;
299         /* Rotation amount, Only YUV rotation is supported */
300         if (compressType == COMP_TYPE_SBWC) {
301             /* Y and UV width should be aligned and should get sram for each Y and UV */
302             int32_t width_y = pixel_align(width + kSramSBWCRotWidthAlign, kSramSBWCRotWidthAlign);
303             int32_t width_c =
304                     pixel_align(width / 2 + kSramSBWCRotWidthAlign, kSramSBWCRotWidthAlign);
305             SRAMtotal += getSramAmount(TDM_ATTR_ROT_90, SBWC_Y, findWidthIndex(width_y));
306             SRAMtotal += getSramAmount(TDM_ATTR_ROT_90, SBWC_UV, findWidthIndex(width_c * 2));
307         } else {
308             /* sramAmountMap has SRAM for both Y and UV */
309             widthIndex = findWidthIndex(width);
310             SRAMtotal += getSramAmount(TDM_ATTR_ROT_90, NON_SBWC_Y | formatBPP, widthIndex);
311             SRAMtotal += getSramAmount(TDM_ATTR_ROT_90, NON_SBWC_UV | formatBPP, widthIndex);
312         }
313         HDEBUGLOGD(eDebugTDM, "+ rotation : %d", SRAMtotal);
314     } else {
315         if (compressType == COMP_TYPE_SBWC) {
316             width = pixel_align(width + kSramSBWCWidthMargin, kSramSBWCWidthAlign);
317         } else if (compressType == COMP_TYPE_AFBC) {
318             /* Align for 8,4Byte/pixel formats */
319             if (formatToBpp(format) > 16) {
320                 width = pixel_align(width + kSramAFBC8B4BMargin, kSramAFBC8B4BAlign);
321             } else {
322                 /* Align for 2Byte/pixel formats */
323                 width = pixel_align(width + kSramAFBC2BMargin, kSramAFBC2BAlign);
324             }
325         }
326         widthIndex = findWidthIndex(width);
327 
328         /* AFBC amount */
329         if (compressType == COMP_TYPE_AFBC) {
330             formatIndex = (isFormatRgb(format) ? RGB : 0) | formatBPP;
331             SRAMtotal += getSramAmount(TDM_ATTR_AFBC, formatIndex, widthIndex);
332             HDEBUGLOGD(eDebugTDM, "+ AFBC : %d", SRAMtotal);
333         }
334 
335         /* SBWC amount */
336         if (compressType == COMP_TYPE_SBWC) {
337             SRAMtotal += getSramAmount(TDM_ATTR_SBWC, SBWC_Y, widthIndex);
338             SRAMtotal += getSramAmount(TDM_ATTR_SBWC, SBWC_UV, widthIndex);
339             HDEBUGLOGD(eDebugTDM, "+ SBWC : %d", SRAMtotal);
340         }
341     }
342 
343     /* ITP (CSC) amount */
344     if (isFormatYUV(format)) {
345         /** ITP has no size difference, Use width index as LB_W_3073_INF **/
346         SRAMtotal += getSramAmount(TDM_ATTR_ITP, formatBPP, LB_W_3073_INF);
347         HDEBUGLOGD(eDebugTDM, "+ YUV : %d", SRAMtotal);
348     }
349 
350     /* Scale amount */
351     int srcW = mppSrc->mSrcImg.w;
352     int srcH = mppSrc->mSrcImg.h;
353     int dstW = mppSrc->mDstImg.w;
354     int dstH = mppSrc->mDstImg.h;
355 
356     if (!!(transform & HAL_TRANSFORM_ROT_90)) {
357         int tmp = dstW;
358         dstW = dstH;
359         dstH = tmp;
360     }
361 
362     bool isScaled = ((srcW != dstW) || (srcH != dstH));
363 
364     if (isScaled) {
365         if (formatHasAlphaChannel(format))
366             formatIndex = FORMAT_RGB_MASK;
367         else
368             formatIndex = FORMAT_YUV_MASK;
369 
370         /** Scale has no size difference, Use width index as LB_W_3073_INF **/
371         SRAMtotal += getSramAmount(TDM_ATTR_SCALE, formatIndex, LB_W_3073_INF);
372         HDEBUGLOGD(eDebugTDM, "+ Scale : %d", SRAMtotal);
373     }
374 
375     for (auto it = HWAttrs.begin(); it != HWAttrs.end(); it++) {
376         uint32_t amount = 0;
377         if (it->first == TDM_ATTR_SRAM_AMOUNT) {
378             amount = SRAMtotal;
379         } else {
380             amount = needHWResource(display, mppSrc->mSrcImg, mppSrc->mDstImg, it->first);
381         }
382         mppSrc->setHWResourceAmount(it->first, amount);
383     }
384 
385     HDEBUGLOGD(eDebugTDM,
386                "mppSrc(%p) needed SRAM(%d), SCALE(%d), AFBC(%d), CSC(%d), SBWC(%d), WCG(%d), "
387                "ROT(%d)",
388                mppSrc->mSrcImg.bufferHandle, SRAMtotal,
389                needHWResource(display, mppSrc->mSrcImg, mppSrc->mDstImg, TDM_ATTR_SCALE),
390                needHWResource(display, mppSrc->mSrcImg, mppSrc->mDstImg, TDM_ATTR_AFBC),
391                needHWResource(display, mppSrc->mSrcImg, mppSrc->mDstImg, TDM_ATTR_ITP),
392                needHWResource(display, mppSrc->mSrcImg, mppSrc->mDstImg, TDM_ATTR_SBWC),
393                needHWResource(display, mppSrc->mSrcImg, mppSrc->mDstImg, TDM_ATTR_WCG),
394                needHWResource(display, mppSrc->mSrcImg, mppSrc->mDstImg, TDM_ATTR_ROT_90));
395 
396     return SRAMtotal;
397 }
398 
otfMppReordering(ExynosDisplay * display,ExynosMPPVector & otfMPPs,struct exynos_image & src,struct exynos_image & dst)399 int32_t ExynosResourceManagerModule::otfMppReordering(ExynosDisplay *display,
400                                                       ExynosMPPVector &otfMPPs,
401                                                       struct exynos_image &src,
402                                                       struct exynos_image &dst)
403 {
404     int orderingType = isAFBCCompressed(src.bufferHandle)
405             ? ORDER_AFBC
406             : (needHdrProcessing(display, src, dst) ? ORDER_WCG : ORDER_AXI);
407 
408     int usedAFBCCount[DPU_BLOCK_CNT] = {0};
409     int usedWCGCount[DPU_BLOCK_CNT * AXI_PORT_MAX_CNT] = {0};
410     int usedBlockCount[DPU_BLOCK_CNT] = {0};
411     int usedAXIPortCount[AXI_PORT_MAX_CNT] = {0};
412 
413     auto orderPolicy = [&](const void *lhs, const void *rhs) -> bool {
414         if (lhs == NULL || rhs == NULL) {
415             return 0;
416         }
417 
418         const ExynosMPPModule *l = (ExynosMPPModule *)lhs;
419         const ExynosMPPModule *r = (ExynosMPPModule *)rhs;
420 
421         uint32_t assignedStateL = l->mAssignedState & MPP_ASSIGN_STATE_ASSIGNED;
422         uint32_t assignedStateR = r->mAssignedState & MPP_ASSIGN_STATE_ASSIGNED;
423 
424         if (assignedStateL != assignedStateR) return assignedStateL < assignedStateR;
425 
426         if (l->mPhysicalType != r->mPhysicalType) return l->mPhysicalType < r->mPhysicalType;
427 
428         if (orderingType == ORDER_AFBC) {
429             /* AFBC balancing */
430             if ((l->mAttr & MPP_ATTR_AFBC) != (r->mAttr & MPP_ATTR_AFBC))
431                 return (l->mAttr & MPP_ATTR_AFBC) > (r->mAttr & MPP_ATTR_AFBC);
432             if (l->mAttr & MPP_ATTR_AFBC) {
433                 /* If layer is AFBC, DPU block that AFBC HW block belongs
434                  * which has not been used much should be placed in the front */
435                 if (usedAFBCCount[l->mHWBlockId] != usedAFBCCount[r->mHWBlockId])
436                     return usedAFBCCount[l->mHWBlockId] < usedAFBCCount[r->mHWBlockId];
437             }
438         } else if (orderingType == ORDER_WCG) {
439             /* WCG balancing */
440             if ((l->mAttr & MPP_ATTR_WCG) != (r->mAttr & MPP_ATTR_WCG))
441                 return (l->mAttr & MPP_ATTR_WCG) > (r->mAttr & MPP_ATTR_WCG);
442             if (l->mAttr & MPP_ATTR_WCG) {
443                 /* If layer is WCG, DPU block that WCG HW block belongs
444                  * which has not been used much should be placed in the front */
445                 if (usedWCGCount[l->mHWBlockId * AXI_PORT_MAX_CNT + l->mAXIPortId] !=
446                     usedWCGCount[r->mHWBlockId * AXI_PORT_MAX_CNT + r->mAXIPortId])
447                     return usedWCGCount[l->mHWBlockId * AXI_PORT_MAX_CNT + l->mAXIPortId] <
448                         usedWCGCount[r->mHWBlockId * AXI_PORT_MAX_CNT + r->mAXIPortId];
449             }
450         }
451 
452         /* AXI bus balancing */
453         /* AXI port which has not been used much should be placed in the front */
454         if (usedAXIPortCount[l->mAXIPortId] != usedAXIPortCount[r->mAXIPortId]) {
455             return usedAXIPortCount[l->mAXIPortId] < usedAXIPortCount[r->mAXIPortId];
456         }
457         /* IF MPP connected same AXI port, Block balancing should be regarded after */
458         if (usedBlockCount[l->mHWBlockId] != usedBlockCount[r->mHWBlockId])
459             return usedBlockCount[l->mHWBlockId] < usedBlockCount[r->mHWBlockId];
460 
461         return l->mPhysicalIndex < r->mPhysicalIndex;
462     };
463 
464     for (auto it : otfMPPs) {
465         ExynosMPPModule *mpp = (ExynosMPPModule *)it;
466         uint32_t bId = mpp->getHWBlockId();
467         uint32_t aId = mpp->getAXIPortId();
468         bool isAFBC = false;
469         bool isWCG = false;
470 
471         if (mpp->mAssignedState & MPP_ASSIGN_STATE_ASSIGNED) {
472             ExynosMPPSource *mppSrc = mpp->mAssignedSources[0];
473             if ((mppSrc->mSourceType == MPP_SOURCE_LAYER) &&
474                 (mppSrc->mSrcImg.bufferHandle != nullptr)) {
475                 if ((mpp->mAttr & MPP_ATTR_AFBC) &&
476                     (isAFBCCompressed(mppSrc->mSrcImg.bufferHandle))) {
477                     isAFBC = true;
478                     usedAFBCCount[bId]++;
479                 } else if ((mpp->mAttr & MPP_ATTR_WCG) &&
480                            (needHdrProcessing(display, mppSrc->mSrcImg, mppSrc->mDstImg))) {
481                     isWCG = true;
482                     usedWCGCount[bId]++;
483                 }
484             } else if (mppSrc->mSourceType == MPP_SOURCE_COMPOSITION_TARGET) {
485                 ExynosCompositionInfo *info = (ExynosCompositionInfo *)mppSrc;
486                 // ESTEVAN_TBD
487                 // if ((mpp->mAttr & MPP_ATTR_AFBC) && (info->mCompressionInfo.type ==
488                 // COMP_TYPE_AFBC)) {
489                 if ((mpp->mAttr & MPP_ATTR_AFBC) &&
490                     (isAFBCCompressed(mppSrc->mSrcImg.bufferHandle))) {
491                     isAFBC = true;
492                     usedAFBCCount[bId]++;
493                 } else if ((mpp->mAttr & MPP_ATTR_WCG) &&
494                            (needHdrProcessing(display, info->mSrcImg, info->mDstImg))) {
495                     isWCG = true;
496                     usedWCGCount[bId]++;
497                 }
498             }
499 
500             HDEBUGLOGD(eDebugLoadBalancing, "%s: %s is assigned (AFBC:%d, WCG:%d), is %s", __func__,
501                        mpp->mName.c_str(), isAFBC, isWCG,
502                        (mppSrc->mSourceType == MPP_SOURCE_LAYER) ? "Layer" : "Client Target");
503             usedBlockCount[bId]++;
504             usedAXIPortCount[aId]++;
505         }
506     }
507 
508     HDEBUGLOGD(eDebugLoadBalancing,
509                "Sorting by %s ordering, AFBC(used DPUF0:%d, DPUF1:%d), AXI(used AXI0:%d, AXI1:%d), "
510                "BLOCK(used DPUF0:%d, DPUF1:%d)",
511                (orderingType == ORDER_AFBC) ? "AFBC" : "_AXI", usedAFBCCount[DPUF0],
512                usedAFBCCount[DPUF1], usedAXIPortCount[AXI0], usedAXIPortCount[AXI1],
513                usedBlockCount[DPUF0], usedBlockCount[DPUF1]);
514 
515     std::sort(otfMPPs.begin(), otfMPPs.end(), orderPolicy);
516 
517     if (hwcCheckDebugMessages(eDebugLoadBalancing)) {
518         String8 after;
519         for (uint32_t i = 0; i < otfMPPs.size(); i++) {
520             ExynosMPPModule *mpp = (ExynosMPPModule *)otfMPPs[i];
521             after.appendFormat("(%s) -> ", mpp->mName.c_str());
522         }
523 
524         ALOGD("%s %p, %s", __func__, src.bufferHandle, after.c_str());
525     }
526 
527     return 0;
528 }
529 
isOverlapped(ExynosDisplay * display,ExynosMPPSource * current,ExynosMPPSource * compare)530 bool ExynosResourceManagerModule::isOverlapped(ExynosDisplay *display, ExynosMPPSource *current,
531                                                ExynosMPPSource *compare) {
532     int CT = current->mDstImg.y - TDM_OVERLAP_MARGIN;
533     CT = (CT < 0) ? 0 : CT;
534     int CB = current->mDstImg.y + current->mDstImg.h + TDM_OVERLAP_MARGIN;
535     CB = (CB > display->mYres) ? display->mYres : CB;
536     int LT = compare->mDstImg.y;
537     int LB = compare->mDstImg.y + compare->mDstImg.h;
538 
539     if (((LT <= CT && CT <= LB) || (LT <= CB && CB <= LB)) ||
540         ((CT <= LT && LT <= CB) || (CT < LB && LB <= CB))) {
541         HDEBUGLOGD(eDebugTDM, "%s, current %p and compare %p is overlaped", __func__,
542                    current->mSrcImg.bufferHandle, compare->mSrcImg.bufferHandle);
543         return true;
544     }
545 
546     return false;
547 }
548 
getAmounts(ExynosDisplay * display,uint32_t currentBlockId,uint32_t currentAXIId,ExynosMPP * compOtfMPP,ExynosMPPSource * curSrc,ExynosMPPSource * compSrc,std::array<uint32_t,TDM_ATTR_MAX> & DPUFAmounts,std::array<uint32_t,TDM_ATTR_MAX> & AXIAmounts)549 uint32_t ExynosResourceManagerModule::getAmounts(ExynosDisplay* display, uint32_t currentBlockId,
550                                                  uint32_t currentAXIId, ExynosMPP* compOtfMPP,
551                                                  ExynosMPPSource* curSrc, ExynosMPPSource* compSrc,
552                                                  std::array<uint32_t, TDM_ATTR_MAX>& DPUFAmounts,
553                                                  std::array<uint32_t, TDM_ATTR_MAX>& AXIAmounts) {
554     const uint32_t blockId = compOtfMPP->getHWBlockId();
555     const uint32_t AXIId = compOtfMPP->getAXIPortId();
556     if (currentBlockId == blockId && isOverlapped(display, curSrc, compSrc)) {
557         String8 log;
558         if (hwcCheckDebugMessages(eDebugTDM)) {
559             log.appendFormat("%s", compOtfMPP->mName.c_str());
560         }
561         for (auto attr = HWAttrs.begin(); attr != HWAttrs.end(); attr++) {
562             uint32_t compareAmount = compSrc->getHWResourceAmount(attr->first);
563             if (hwcCheckDebugMessages(eDebugTDM)) {
564                 log.appendFormat(", attr %s DPUF-%d(+ %d)", attr->second.name.c_str(),
565                                  DPUFAmounts[attr->first], compareAmount);
566             }
567             DPUFAmounts[attr->first] += compareAmount;
568             if (attr->second.loadSharing == LS_DPUF_AXI && currentAXIId == AXIId) {
569                 if (hwcCheckDebugMessages(eDebugTDM)) {
570                     log.appendFormat(",AXI-%d(+ %d)", AXIAmounts[attr->first], compareAmount);
571                 }
572                 AXIAmounts[attr->first] += compareAmount;
573             }
574         }
575         HDEBUGLOGD(eDebugTDM, "%s %s", __func__, log.c_str());
576     }
577 
578     return 0;
579 }
580 
isAssignable(ExynosMPP * candidateMPP,ExynosDisplay * display,struct exynos_image & src,struct exynos_image & dst,ExynosMPPSource * mppSrc)581 bool ExynosResourceManagerModule::isAssignable(ExynosMPP* candidateMPP, ExynosDisplay* display,
582                                                struct exynos_image& src, struct exynos_image& dst,
583                                                ExynosMPPSource* mppSrc) {
584     if (display != nullptr && candidateMPP != nullptr &&
585         display->mType == HWC_DISPLAY_EXTERNAL &&
586         !(candidateMPP->mPhysicalType == MPP_DPP_VGRFS && candidateMPP->mPhysicalIndex == 0)) {
587         return false;
588     }
589     return gs201::ExynosResourceManagerModule::isAssignable(candidateMPP, display, src, dst,
590                                                             mppSrc);
591 }
592