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