1 /*
2 * Copyright 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 "GuestFrameComposer.h"
18
19 #include <android-base/parseint.h>
20 #include <android-base/properties.h>
21 #include <android-base/strings.h>
22 #include <android/hardware/graphics/common/1.0/types.h>
23 #include <drm_fourcc.h>
24 #include <libyuv.h>
25 #include <sync/sync.h>
26 #include <ui/GraphicBuffer.h>
27 #include <ui/GraphicBufferAllocator.h>
28 #include <ui/GraphicBufferMapper.h>
29
30 #include "Display.h"
31 #include "DisplayFinder.h"
32 #include "Drm.h"
33 #include "Layer.h"
34
35 namespace aidl::android::hardware::graphics::composer3::impl {
36 namespace {
37
38 using ::android::hardware::graphics::common::V1_0::ColorTransform;
39
AlignToPower2(uint32_t val,uint8_t align_log)40 uint32_t AlignToPower2(uint32_t val, uint8_t align_log) {
41 uint32_t align = 1 << align_log;
42 return ((val + (align - 1)) / align) * align;
43 }
44
LayerNeedsScaling(const Layer & layer)45 bool LayerNeedsScaling(const Layer& layer) {
46 common::Rect crop = layer.getSourceCropInt();
47 common::Rect frame = layer.getDisplayFrame();
48
49 int fromW = crop.right - crop.left;
50 int fromH = crop.bottom - crop.top;
51 int toW = frame.right - frame.left;
52 int toH = frame.bottom - frame.top;
53
54 bool not_rot_scale = fromW != toW || fromH != toH;
55 bool rot_scale = fromW != toH || fromH != toW;
56
57 bool needs_rot = static_cast<int32_t>(layer.getTransform()) &
58 static_cast<int32_t>(common::Transform::ROT_90);
59
60 return needs_rot ? rot_scale : not_rot_scale;
61 }
62
LayerNeedsBlending(const Layer & layer)63 bool LayerNeedsBlending(const Layer& layer) {
64 return layer.getBlendMode() != common::BlendMode::NONE;
65 }
66
LayerNeedsAttenuation(const Layer & layer)67 bool LayerNeedsAttenuation(const Layer& layer) {
68 return layer.getBlendMode() == common::BlendMode::COVERAGE;
69 }
70
71 struct BufferSpec;
72 typedef int (*ConverterFunction)(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
73 int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool vFlip);
74 int ConvertFromRGB565(const BufferSpec& src, const BufferSpec& dst, bool vFlip);
75 int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool vFlip);
76
GetConverterForDrmFormat(uint32_t drmFormat)77 ConverterFunction GetConverterForDrmFormat(uint32_t drmFormat) {
78 switch (drmFormat) {
79 case DRM_FORMAT_ABGR8888:
80 case DRM_FORMAT_XBGR8888:
81 return &DoCopy;
82 case DRM_FORMAT_RGB565:
83 return &ConvertFromRGB565;
84 case DRM_FORMAT_YVU420:
85 return &ConvertFromYV12;
86 }
87 DEBUG_LOG("Unsupported drm format: %d(%s), returning null converter", drmFormat,
88 GetDrmFormatString(drmFormat));
89 return nullptr;
90 }
91
IsDrmFormatSupported(uint32_t drmFormat)92 bool IsDrmFormatSupported(uint32_t drmFormat) {
93 return GetConverterForDrmFormat(drmFormat) != nullptr;
94 }
95
96 // Libyuv's convert functions only allow the combination of any rotation
97 // (multiple of 90 degrees) and a vertical flip, but not horizontal flips.
98 // Surfaceflinger's transformations are expressed in terms of a vertical flip,
99 // a horizontal flip and/or a single 90 degrees clockwise rotation (see
100 // NATIVE_WINDOW_TRANSFORM_HINT documentation on system/window.h for more
101 // insight). The following code allows to turn a horizontal flip into a 180
102 // degrees rotation and a vertical flip.
GetRotationFromTransform(common::Transform transform)103 libyuv::RotationMode GetRotationFromTransform(common::Transform transform) {
104 uint32_t rotation = 0;
105 rotation += (static_cast<int32_t>(transform) & static_cast<int32_t>(common::Transform::ROT_90))
106 ? 1
107 : 0; // 1 * ROT90 bit
108 rotation += (static_cast<int32_t>(transform) & static_cast<int32_t>(common::Transform::FLIP_H))
109 ? 2
110 : 0; // 2 * VFLIP bit
111 return static_cast<libyuv::RotationMode>(90 * rotation);
112 }
113
GetVFlipFromTransform(common::Transform transform)114 bool GetVFlipFromTransform(common::Transform transform) {
115 // vertical flip xor horizontal flip
116 bool hasVFlip =
117 static_cast<int32_t>(transform) & static_cast<int32_t>(common::Transform::FLIP_V);
118 bool hasHFlip =
119 static_cast<int32_t>(transform) & static_cast<int32_t>(common::Transform::FLIP_H);
120 return hasVFlip ^ hasHFlip;
121 }
122
123 struct BufferSpec {
124 uint8_t* buffer;
125 std::optional<android_ycbcr> buffer_ycbcr;
126 uint32_t width;
127 uint32_t height;
128 uint32_t cropX;
129 uint32_t cropY;
130 uint32_t cropWidth;
131 uint32_t cropHeight;
132 uint32_t drmFormat;
133 uint32_t strideBytes;
134 uint32_t sampleBytes;
135
136 BufferSpec() = default;
137
BufferSpecaidl::android::hardware::graphics::composer3::impl::__anon502f7dff0111::BufferSpec138 BufferSpec(uint8_t* buffer, std::optional<android_ycbcr> buffer_ycbcr, uint32_t width,
139 uint32_t height, uint32_t cropX, uint32_t cropY, uint32_t cropWidth,
140 uint32_t cropHeight, uint32_t drmFormat, uint32_t strideBytes, uint32_t sampleBytes)
141 : buffer(buffer),
142 buffer_ycbcr(buffer_ycbcr),
143 width(width),
144 height(height),
145 cropX(cropX),
146 cropY(cropY),
147 cropWidth(cropWidth),
148 cropHeight(cropHeight),
149 drmFormat(drmFormat),
150 strideBytes(strideBytes),
151 sampleBytes(sampleBytes) {}
152
BufferSpecaidl::android::hardware::graphics::composer3::impl::__anon502f7dff0111::BufferSpec153 BufferSpec(uint8_t* buffer, uint32_t width, uint32_t height, uint32_t strideBytes)
154 : BufferSpec(buffer,
155 /*buffer_ycbcr=*/std::nullopt, width, height,
156 /*cropX=*/0,
157 /*cropY=*/0,
158 /*cropWidth=*/width,
159 /*cropHeight=*/height,
160 /*drmFormat=*/DRM_FORMAT_ABGR8888, strideBytes,
161 /*sampleBytes=*/4) {}
162 };
163
DoFill(const BufferSpec & dst,const Color & color)164 int DoFill(const BufferSpec& dst, const Color& color) {
165 ATRACE_CALL();
166
167 const uint8_t r = static_cast<uint8_t>(color.r * 255.0f);
168 const uint8_t g = static_cast<uint8_t>(color.g * 255.0f);
169 const uint8_t b = static_cast<uint8_t>(color.b * 255.0f);
170 const uint8_t a = static_cast<uint8_t>(color.a * 255.0f);
171
172 const uint32_t rgba = static_cast<uint32_t>(r) | static_cast<uint32_t>(g) << 8 |
173 static_cast<uint32_t>(b) << 16 | static_cast<uint32_t>(a) << 24;
174
175 // Point to the upper left corner of the crop rectangle.
176 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
177
178 libyuv::SetPlane(dstBuffer, static_cast<int>(dst.strideBytes), static_cast<int>(dst.cropWidth),
179 static_cast<int>(dst.cropHeight), rgba);
180 return 0;
181 }
182
ConvertFromRGB565(const BufferSpec & src,const BufferSpec & dst,bool vFlip)183 int ConvertFromRGB565(const BufferSpec& src, const BufferSpec& dst, bool vFlip) {
184 ATRACE_CALL();
185
186 // Point to the upper left corner of the crop rectangle
187 uint8_t* srcBuffer = src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
188 const int srcStrideBytes = static_cast<int>(src.strideBytes);
189 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
190 const int dstStrideBytes = static_cast<int>(dst.strideBytes);
191
192 int width = static_cast<int>(src.cropWidth);
193 int height = static_cast<int>(src.cropHeight);
194 if (vFlip) {
195 height = -height;
196 }
197
198 return libyuv::RGB565ToARGB(srcBuffer, srcStrideBytes, //
199 dstBuffer, dstStrideBytes, //
200 width, height);
201 }
202
ConvertFromYV12(const BufferSpec & src,const BufferSpec & dst,bool vFlip)203 int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool vFlip) {
204 ATRACE_CALL();
205
206 // The following calculation of plane offsets and alignments are based on
207 // swiftshader's Sampler::setTextureLevel() implementation
208 // (Renderer/Sampler.cpp:225)
209
210 auto& srcBufferYCbCrOpt = src.buffer_ycbcr;
211 if (!srcBufferYCbCrOpt) {
212 ALOGE("%s called on non ycbcr buffer", __FUNCTION__);
213 return -1;
214 }
215 auto& srcBufferYCbCr = *srcBufferYCbCrOpt;
216
217 // The libyuv::I420ToARGB() function is for tri-planar.
218 if (srcBufferYCbCr.chroma_step != 1) {
219 ALOGE("%s called with bad chroma step", __FUNCTION__);
220 return -1;
221 }
222
223 uint8_t* srcY = reinterpret_cast<uint8_t*>(srcBufferYCbCr.y);
224 const int strideYBytes = static_cast<int>(srcBufferYCbCr.ystride);
225 uint8_t* srcU = reinterpret_cast<uint8_t*>(srcBufferYCbCr.cb);
226 const int strideUBytes = static_cast<int>(srcBufferYCbCr.cstride);
227 uint8_t* srcV = reinterpret_cast<uint8_t*>(srcBufferYCbCr.cr);
228 const int strideVBytes = static_cast<int>(srcBufferYCbCr.cstride);
229
230 // Adjust for crop
231 srcY += src.cropY * srcBufferYCbCr.ystride + src.cropX;
232 srcV += (src.cropY / 2) * srcBufferYCbCr.cstride + (src.cropX / 2);
233 srcU += (src.cropY / 2) * srcBufferYCbCr.cstride + (src.cropX / 2);
234 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
235 const int dstStrideBytes = static_cast<int>(dst.strideBytes);
236
237 int width = static_cast<int>(dst.cropWidth);
238 int height = static_cast<int>(dst.cropHeight);
239
240 if (vFlip) {
241 height = -height;
242 }
243
244 // YV12 is the same as I420, with the U and V planes swapped
245 return libyuv::I420ToARGB(srcY, strideYBytes, //
246 srcV, strideVBytes, //
247 srcU, strideUBytes, //
248 dstBuffer, dstStrideBytes, width, height);
249 }
250
DoConversion(const BufferSpec & src,const BufferSpec & dst,bool v_flip)251 int DoConversion(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
252 ConverterFunction func = GetConverterForDrmFormat(src.drmFormat);
253 if (!func) {
254 // GetConverterForDrmFormat should've logged the issue for us.
255 return -1;
256 }
257 return func(src, dst, v_flip);
258 }
259
DoCopy(const BufferSpec & src,const BufferSpec & dst,bool v_flip)260 int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
261 ATRACE_CALL();
262
263 // Point to the upper left corner of the crop rectangle
264 uint8_t* srcBuffer = src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
265 const int srcStrideBytes = static_cast<int>(src.strideBytes);
266 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
267 const int dstStrideBytes = static_cast<int>(dst.strideBytes);
268 int width = static_cast<int>(src.cropWidth);
269 int height = static_cast<int>(src.cropHeight);
270
271 if (v_flip) {
272 height = -height;
273 }
274
275 // HAL formats are named based on the order of the pixel components on the
276 // byte stream, while libyuv formats are named based on the order of those
277 // pixel components in an integer written from left to right. So
278 // libyuv::FOURCC_ARGB is equivalent to HAL_PIXEL_FORMAT_BGRA_8888.
279 auto ret = libyuv::ARGBCopy(srcBuffer, srcStrideBytes, //
280 dstBuffer, dstStrideBytes, //
281 width, height);
282 return ret;
283 }
284
DoRotation(const BufferSpec & src,const BufferSpec & dst,libyuv::RotationMode rotation,bool v_flip)285 int DoRotation(const BufferSpec& src, const BufferSpec& dst, libyuv::RotationMode rotation,
286 bool v_flip) {
287 ATRACE_CALL();
288
289 // Point to the upper left corner of the crop rectangles
290 uint8_t* srcBuffer = src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
291 const int srcStrideBytes = static_cast<int>(src.strideBytes);
292 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
293 const int dstStrideBytes = static_cast<int>(dst.strideBytes);
294 int width = static_cast<int>(src.cropWidth);
295 int height = static_cast<int>(src.cropHeight);
296
297 if (v_flip) {
298 height = -height;
299 }
300
301 return libyuv::ARGBRotate(srcBuffer, srcStrideBytes, //
302 dstBuffer, dstStrideBytes, //
303 width, height, rotation);
304 }
305
DoScaling(const BufferSpec & src,const BufferSpec & dst,bool v_flip)306 int DoScaling(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
307 ATRACE_CALL();
308
309 // Point to the upper left corner of the crop rectangles
310 uint8_t* srcBuffer = src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
311 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
312 const int srcStrideBytes = static_cast<int>(src.strideBytes);
313 const int dstStrideBytes = static_cast<int>(dst.strideBytes);
314 const int srcWidth = static_cast<int>(src.cropWidth);
315 int srcHeight = static_cast<int>(src.cropHeight);
316 const int dstWidth = static_cast<int>(dst.cropWidth);
317 const int dstHeight = static_cast<int>(dst.cropHeight);
318
319 if (v_flip) {
320 srcHeight = -srcHeight;
321 }
322
323 return libyuv::ARGBScale(srcBuffer, srcStrideBytes, srcWidth, srcHeight, dstBuffer,
324 dstStrideBytes, dstWidth, dstHeight, libyuv::kFilterBilinear);
325 }
326
DoAttenuation(const BufferSpec & src,const BufferSpec & dst,bool v_flip)327 int DoAttenuation(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
328 ATRACE_CALL();
329
330 // Point to the upper left corner of the crop rectangles
331 uint8_t* srcBuffer = src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
332 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
333 const int srcStrideBytes = static_cast<int>(src.strideBytes);
334 const int dstStrideBytes = static_cast<int>(dst.strideBytes);
335 const int width = static_cast<int>(dst.cropWidth);
336 int height = static_cast<int>(dst.cropHeight);
337 if (v_flip) {
338 height = -height;
339 }
340
341 return libyuv::ARGBAttenuate(srcBuffer, srcStrideBytes, //
342 dstBuffer, dstStrideBytes, //
343 width, height);
344 }
345
DoBlending(const BufferSpec & src,const BufferSpec & dst,bool v_flip)346 int DoBlending(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
347 ATRACE_CALL();
348
349 // Point to the upper left corner of the crop rectangles
350 uint8_t* srcBuffer = src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
351 uint8_t* dstBuffer = dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
352 const int srcStrideBytes = static_cast<int>(src.strideBytes);
353 const int dstStrideBytes = static_cast<int>(dst.strideBytes);
354 const int width = static_cast<int>(dst.cropWidth);
355 int height = static_cast<int>(dst.cropHeight);
356 if (v_flip) {
357 height = -height;
358 }
359
360 // libyuv's ARGB format is hwcomposer's BGRA format, since blending only cares
361 // for the position of alpha in the pixel and not the position of the colors
362 // this function is perfectly usable.
363 return libyuv::ARGBBlend(srcBuffer, srcStrideBytes, //
364 dstBuffer, dstStrideBytes, //
365 dstBuffer, dstStrideBytes, //
366 width, height);
367 }
368
GetBufferSpec(GrallocBuffer & buffer,GrallocBufferView & bufferView,const common::Rect & bufferCrop)369 std::optional<BufferSpec> GetBufferSpec(GrallocBuffer& buffer, GrallocBufferView& bufferView,
370 const common::Rect& bufferCrop) {
371 auto bufferFormatOpt = buffer.GetDrmFormat();
372 if (!bufferFormatOpt) {
373 ALOGE("Failed to get gralloc buffer format.");
374 return std::nullopt;
375 }
376 uint32_t bufferFormat = *bufferFormatOpt;
377
378 auto bufferWidthOpt = buffer.GetWidth();
379 if (!bufferWidthOpt) {
380 ALOGE("Failed to get gralloc buffer width.");
381 return std::nullopt;
382 }
383 uint32_t bufferWidth = *bufferWidthOpt;
384
385 auto bufferHeightOpt = buffer.GetHeight();
386 if (!bufferHeightOpt) {
387 ALOGE("Failed to get gralloc buffer height.");
388 return std::nullopt;
389 }
390 uint32_t bufferHeight = *bufferHeightOpt;
391
392 uint8_t* bufferData = nullptr;
393 uint32_t bufferStrideBytes = 0;
394 std::optional<android_ycbcr> bufferYCbCrData;
395
396 if (bufferFormat == DRM_FORMAT_NV12 || bufferFormat == DRM_FORMAT_NV21 ||
397 bufferFormat == DRM_FORMAT_YVU420) {
398 bufferYCbCrData = bufferView.GetYCbCr();
399 if (!bufferYCbCrData) {
400 ALOGE("%s failed to get raw ycbcr from view.", __FUNCTION__);
401 return std::nullopt;
402 }
403 } else {
404 auto bufferDataOpt = bufferView.Get();
405 if (!bufferDataOpt) {
406 ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
407 return std::nullopt;
408 }
409 bufferData = reinterpret_cast<uint8_t*>(*bufferDataOpt);
410
411 auto bufferStrideBytesOpt = buffer.GetMonoPlanarStrideBytes();
412 if (!bufferStrideBytesOpt) {
413 ALOGE("%s failed to get plane stride.", __FUNCTION__);
414 return std::nullopt;
415 }
416 bufferStrideBytes = *bufferStrideBytesOpt;
417 }
418
419 uint32_t bufferCropX = static_cast<uint32_t>(bufferCrop.left);
420 uint32_t bufferCropY = static_cast<uint32_t>(bufferCrop.top);
421 uint32_t bufferCropWidth = static_cast<uint32_t>(bufferCrop.right - bufferCrop.left);
422 uint32_t bufferCropHeight = static_cast<uint32_t>(bufferCrop.bottom - bufferCrop.top);
423
424 return BufferSpec(bufferData, bufferYCbCrData, bufferWidth, bufferHeight, bufferCropX,
425 bufferCropY, bufferCropWidth, bufferCropHeight, bufferFormat,
426 bufferStrideBytes, GetDrmFormatBytesPerPixel(bufferFormat));
427 }
428
429 } // namespace
430
init()431 HWC3::Error GuestFrameComposer::init() {
432 DEBUG_LOG("%s", __FUNCTION__);
433
434 HWC3::Error error = mDrmClient.init();
435 if (error != HWC3::Error::None) {
436 ALOGE("%s: failed to initialize DrmClient", __FUNCTION__);
437 return error;
438 }
439
440 return HWC3::Error::None;
441 }
442
registerOnHotplugCallback(const HotplugCallback & cb)443 HWC3::Error GuestFrameComposer::registerOnHotplugCallback(const HotplugCallback& cb) {
444 return mDrmClient.registerOnHotplugCallback(cb);
445 return HWC3::Error::None;
446 }
447
unregisterOnHotplugCallback()448 HWC3::Error GuestFrameComposer::unregisterOnHotplugCallback() {
449 return mDrmClient.unregisterOnHotplugCallback();
450 }
451
onDisplayCreate(Display * display)452 HWC3::Error GuestFrameComposer::onDisplayCreate(Display* display) {
453 const uint32_t displayId = static_cast<uint32_t>(display->getId());
454 int32_t displayConfigId;
455 int32_t displayWidth;
456 int32_t displayHeight;
457
458 HWC3::Error error = display->getActiveConfig(&displayConfigId);
459 if (error != HWC3::Error::None) {
460 ALOGE("%s: display:%" PRIu32 " has no active config", __FUNCTION__, displayId);
461 return error;
462 }
463
464 error = display->getDisplayAttribute(displayConfigId, DisplayAttribute::WIDTH, &displayWidth);
465 if (error != HWC3::Error::None) {
466 ALOGE("%s: display:%" PRIu32 " failed to get width", __FUNCTION__, displayId);
467 return error;
468 }
469
470 error = display->getDisplayAttribute(displayConfigId, DisplayAttribute::HEIGHT, &displayHeight);
471 if (error != HWC3::Error::None) {
472 ALOGE("%s: display:%" PRIu32 " failed to get height", __FUNCTION__, displayId);
473 return error;
474 }
475
476 auto it = mDisplayInfos.find(displayId);
477 if (it != mDisplayInfos.end()) {
478 ALOGE("%s: display:%" PRIu32 " already created?", __FUNCTION__, displayId);
479 }
480
481 DisplayInfo& displayInfo = mDisplayInfos[displayId];
482
483 displayInfo.swapchain = DrmSwapchain::create(static_cast<uint32_t>(displayWidth),
484 static_cast<uint32_t>(displayHeight),
485 ::android::GraphicBuffer::USAGE_HW_COMPOSER |
486 ::android::GraphicBuffer::USAGE_SW_READ_OFTEN |
487 ::android::GraphicBuffer::USAGE_SW_WRITE_OFTEN,
488 &mDrmClient);
489
490 if (displayId == 0) {
491 auto compositionResult = displayInfo.swapchain->getNextImage();
492 auto [flushError, flushSyncFd] =
493 mDrmClient.flushToDisplay(displayId, compositionResult->getDrmBuffer(), -1);
494 if (flushError != HWC3::Error::None) {
495 ALOGW(
496 "%s: Initial display flush failed. HWComposer assuming that we are "
497 "running in QEMU without a display and disabling presenting.",
498 __FUNCTION__);
499 mPresentDisabled = true;
500 } else {
501 compositionResult->markAsInUse(std::move(flushSyncFd));
502 }
503 }
504
505 std::optional<std::vector<uint8_t>> edid = mDrmClient.getEdid(displayId);
506 if (edid) {
507 display->setEdid(*edid);
508 }
509
510 return HWC3::Error::None;
511 }
512
onDisplayDestroy(Display * display)513 HWC3::Error GuestFrameComposer::onDisplayDestroy(Display* display) {
514 auto displayId = display->getId();
515
516 auto it = mDisplayInfos.find(displayId);
517 if (it == mDisplayInfos.end()) {
518 ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
519 displayId);
520 return HWC3::Error::BadDisplay;
521 }
522 mDisplayInfos.erase(it);
523
524 return HWC3::Error::None;
525 }
526
onDisplayClientTargetSet(Display *)527 HWC3::Error GuestFrameComposer::onDisplayClientTargetSet(Display*) { return HWC3::Error::None; }
528
onActiveConfigChange(Display *)529 HWC3::Error GuestFrameComposer::onActiveConfigChange(Display* /*display*/) {
530 return HWC3::Error::None;
531 };
532
getDisplayConfigsFromSystemProp(std::vector<GuestFrameComposer::DisplayConfig> * configs)533 HWC3::Error GuestFrameComposer::getDisplayConfigsFromSystemProp(
534 std::vector<GuestFrameComposer::DisplayConfig>* configs) {
535 DEBUG_LOG("%s", __FUNCTION__);
536
537 std::vector<int> propIntParts;
538 parseExternalDisplaysFromProperties(propIntParts);
539
540 while (!propIntParts.empty()) {
541 DisplayConfig display_config = {
542 .width = propIntParts[1],
543 .height = propIntParts[2],
544 .dpiX = propIntParts[3],
545 .dpiY = propIntParts[3],
546 .refreshRateHz = 160,
547 };
548
549 configs->push_back(display_config);
550
551 propIntParts.erase(propIntParts.begin(), propIntParts.begin() + 5);
552 }
553
554 return HWC3::Error::None;
555 }
556
validateDisplay(Display * display,DisplayChanges * outChanges)557 HWC3::Error GuestFrameComposer::validateDisplay(Display* display, DisplayChanges* outChanges) {
558 const auto displayId = display->getId();
559 DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
560
561 const std::vector<Layer*>& layers = display->getOrderedLayers();
562
563 bool fallbackToClientComposition = false;
564 for (Layer* layer : layers) {
565 const auto layerId = layer->getId();
566 const auto layerCompositionType = layer->getCompositionType();
567 const auto layerCompositionTypeString = toString(layerCompositionType);
568
569 if (layerCompositionType == Composition::INVALID) {
570 ALOGE("%s display:%" PRIu64 " layer:%" PRIu64 " has Invalid composition", __FUNCTION__,
571 displayId, layerId);
572 continue;
573 }
574
575 if (layerCompositionType == Composition::CLIENT ||
576 layerCompositionType == Composition::CURSOR ||
577 layerCompositionType == Composition::SIDEBAND) {
578 DEBUG_LOG("%s: display:%" PRIu64 " layer:%" PRIu64
579 " has composition type %s, falling back to client composition",
580 __FUNCTION__, displayId, layerId, layerCompositionTypeString.c_str());
581 fallbackToClientComposition = true;
582 break;
583 }
584
585 if (layerCompositionType == Composition::DISPLAY_DECORATION) {
586 return HWC3::Error::Unsupported;
587 }
588
589 if (!canComposeLayer(layer)) {
590 DEBUG_LOG("%s: display:%" PRIu64 " layer:%" PRIu64
591 " composition not supported, falling back to client composition",
592 __FUNCTION__, displayId, layerId);
593 fallbackToClientComposition = true;
594 break;
595 }
596 }
597
598 if (fallbackToClientComposition) {
599 for (Layer* layer : layers) {
600 const auto layerId = layer->getId();
601 const auto layerCompositionType = layer->getCompositionType();
602
603 if (layerCompositionType == Composition::INVALID) {
604 continue;
605 }
606
607 if (layerCompositionType != Composition::CLIENT) {
608 DEBUG_LOG("%s display:%" PRIu64 " layer:%" PRIu64 "composition updated to Client",
609 __FUNCTION__, displayId, layerId);
610
611 outChanges->addLayerCompositionChange(displayId, layerId, Composition::CLIENT);
612 }
613 }
614 }
615
616 // We can not draw below a Client (SurfaceFlinger) composed layer. Change all
617 // layers below a Client composed layer to also be Client composed.
618 if (layers.size() > 1) {
619 for (std::size_t layerIndex = layers.size() - 1; layerIndex > 0; layerIndex--) {
620 auto layer = layers[layerIndex];
621 auto layerCompositionType = layer->getCompositionType();
622
623 if (layerCompositionType == Composition::CLIENT) {
624 for (std::size_t lowerLayerIndex = 0; lowerLayerIndex < layerIndex;
625 lowerLayerIndex++) {
626 auto lowerLayer = layers[lowerLayerIndex];
627 auto lowerLayerId = lowerLayer->getId();
628 auto lowerLayerCompositionType = lowerLayer->getCompositionType();
629
630 if (lowerLayerCompositionType != Composition::CLIENT) {
631 DEBUG_LOG("%s: display:%" PRIu64 " changing layer:%" PRIu64
632 " to Client because"
633 "hwcomposer can not draw below the Client composed "
634 "layer:%" PRIu64,
635 __FUNCTION__, displayId, lowerLayerId, layer->getId());
636
637 outChanges->addLayerCompositionChange(displayId, lowerLayerId,
638 Composition::CLIENT);
639 }
640 }
641 }
642 }
643 }
644
645 return HWC3::Error::None;
646 }
647
presentDisplay(Display * display,::android::base::unique_fd * outDisplayFence,std::unordered_map<int64_t,::android::base::unique_fd> *)648 HWC3::Error GuestFrameComposer::presentDisplay(
649 Display* display, ::android::base::unique_fd* outDisplayFence,
650 std::unordered_map<int64_t, ::android::base::unique_fd>* /*outLayerFences*/) {
651 const uint32_t displayId = static_cast<uint32_t>(display->getId());
652 DEBUG_LOG("%s display:%" PRIu32, __FUNCTION__, displayId);
653
654 if (mPresentDisabled) {
655 return HWC3::Error::None;
656 }
657
658 auto it = mDisplayInfos.find(displayId);
659 if (it == mDisplayInfos.end()) {
660 ALOGE("%s: display:%" PRIu32 " not found", __FUNCTION__, displayId);
661 return HWC3::Error::NoResources;
662 }
663
664 DisplayInfo& displayInfo = it->second;
665
666 auto compositionResult = displayInfo.swapchain->getNextImage();
667 compositionResult->wait();
668
669 if (compositionResult->getBuffer() == nullptr) {
670 ALOGE("%s: display:%" PRIu32 " missing composition result buffer",
671 __FUNCTION__, displayId);
672 return HWC3::Error::NoResources;
673 }
674
675 if (compositionResult->getDrmBuffer() == nullptr) {
676 ALOGE("%s: display:%" PRIu32 " missing composition result drm buffer",
677 __FUNCTION__, displayId);
678 return HWC3::Error::NoResources;
679 }
680
681 std::optional<GrallocBuffer> compositionResultBufferOpt =
682 mGralloc.Import(compositionResult->getBuffer());
683 if (!compositionResultBufferOpt) {
684 ALOGE("%s: display:%" PRIu32 " failed to import buffer", __FUNCTION__, displayId);
685 return HWC3::Error::NoResources;
686 }
687
688 std::optional<uint32_t> compositionResultBufferWidthOpt =
689 compositionResultBufferOpt->GetWidth();
690 if (!compositionResultBufferWidthOpt) {
691 ALOGE("%s: display:%" PRIu32 " failed to query buffer width", __FUNCTION__, displayId);
692 return HWC3::Error::NoResources;
693 }
694
695 std::optional<uint32_t> compositionResultBufferHeightOpt =
696 compositionResultBufferOpt->GetHeight();
697 if (!compositionResultBufferHeightOpt) {
698 ALOGE("%s: display:%" PRIu32 " failed to query buffer height", __FUNCTION__, displayId);
699 return HWC3::Error::NoResources;
700 }
701
702 std::optional<uint32_t> compositionResultBufferStrideOpt =
703 compositionResultBufferOpt->GetMonoPlanarStrideBytes();
704 if (!compositionResultBufferStrideOpt) {
705 ALOGE("%s: display:%" PRIu32 " failed to query buffer stride", __FUNCTION__, displayId);
706 return HWC3::Error::NoResources;
707 }
708
709 std::optional<GrallocBufferView> compositionResultBufferViewOpt =
710 compositionResultBufferOpt->Lock();
711 if (!compositionResultBufferViewOpt) {
712 ALOGE("%s: display:%" PRIu32 " failed to get buffer view", __FUNCTION__, displayId);
713 return HWC3::Error::NoResources;
714 }
715
716 const std::optional<void*> compositionResultBufferDataOpt =
717 compositionResultBufferViewOpt->Get();
718 if (!compositionResultBufferDataOpt) {
719 ALOGE("%s: display:%" PRIu32 " failed to get buffer data", __FUNCTION__, displayId);
720 return HWC3::Error::NoResources;
721 }
722
723 uint32_t compositionResultBufferWidth = *compositionResultBufferWidthOpt;
724 uint32_t compositionResultBufferHeight = *compositionResultBufferHeightOpt;
725 uint32_t compositionResultBufferStride = *compositionResultBufferStrideOpt;
726 uint8_t* compositionResultBufferData =
727 reinterpret_cast<uint8_t*>(*compositionResultBufferDataOpt);
728
729 const std::vector<Layer*>& layers = display->getOrderedLayers();
730
731 const bool noOpComposition = layers.empty();
732 const bool allLayersClientComposed = std::all_of(
733 layers.begin(), //
734 layers.end(), //
735 [](const Layer* layer) { return layer->getCompositionType() == Composition::CLIENT; });
736
737 if (noOpComposition) {
738 ALOGW("%s: display:%" PRIu32 " empty composition", __FUNCTION__, displayId);
739 } else if (allLayersClientComposed) {
740 auto clientTargetBufferOpt = mGralloc.Import(display->waitAndGetClientTargetBuffer());
741 if (!clientTargetBufferOpt) {
742 ALOGE("%s: failed to import client target buffer.", __FUNCTION__);
743 return HWC3::Error::NoResources;
744 }
745 GrallocBuffer& clientTargetBuffer = *clientTargetBufferOpt;
746
747 auto clientTargetBufferViewOpt = clientTargetBuffer.Lock();
748 if (!clientTargetBufferViewOpt) {
749 ALOGE("%s: failed to lock client target buffer.", __FUNCTION__);
750 return HWC3::Error::NoResources;
751 }
752 GrallocBufferView& clientTargetBufferView = *clientTargetBufferViewOpt;
753
754 auto clientTargetPlaneLayoutsOpt = clientTargetBuffer.GetPlaneLayouts();
755 if (!clientTargetPlaneLayoutsOpt) {
756 ALOGE("Failed to get client target buffer plane layouts.");
757 return HWC3::Error::NoResources;
758 }
759 auto& clientTargetPlaneLayouts = *clientTargetPlaneLayoutsOpt;
760
761 if (clientTargetPlaneLayouts.size() != 1) {
762 ALOGE("Unexpected number of plane layouts for client target buffer.");
763 return HWC3::Error::NoResources;
764 }
765
766 std::size_t clientTargetPlaneSize =
767 static_cast<std::size_t>(clientTargetPlaneLayouts[0].totalSizeInBytes);
768
769 auto clientTargetDataOpt = clientTargetBufferView.Get();
770 if (!clientTargetDataOpt) {
771 ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
772 return HWC3::Error::NoResources;
773 }
774 auto* clientTargetData = reinterpret_cast<uint8_t*>(*clientTargetDataOpt);
775
776 std::memcpy(compositionResultBufferData, clientTargetData, clientTargetPlaneSize);
777 } else {
778 for (Layer* layer : layers) {
779 const auto layerId = layer->getId();
780 const auto layerCompositionType = layer->getCompositionType();
781 if (layerCompositionType != Composition::DEVICE &&
782 layerCompositionType != Composition::SOLID_COLOR) {
783 continue;
784 }
785
786 HWC3::Error error = composeLayerInto(displayInfo.compositionIntermediateStorage, //
787 layer, //
788 compositionResultBufferData, //
789 compositionResultBufferWidth, //
790 compositionResultBufferHeight, //
791 compositionResultBufferStride, //
792 4);
793 if (error != HWC3::Error::None) {
794 ALOGE("%s: display:%" PRIu32 " failed to compose layer:%" PRIu64, __FUNCTION__,
795 displayId, layerId);
796 return error;
797 }
798 }
799 }
800
801 if (display->hasColorTransform()) {
802 HWC3::Error error = applyColorTransformToRGBA(display->getColorTransform(), //
803 compositionResultBufferData, //
804 compositionResultBufferWidth, //
805 compositionResultBufferHeight, //
806 compositionResultBufferStride);
807 if (error != HWC3::Error::None) {
808 ALOGE("%s: display:%" PRIu32 " failed to apply color transform", __FUNCTION__,
809 displayId);
810 return error;
811 }
812 }
813
814 DEBUG_LOG("%s display:%" PRIu32 " flushing drm buffer", __FUNCTION__,
815 displayId);
816
817 auto [error, fence] = mDrmClient.flushToDisplay(displayId, compositionResult->getDrmBuffer(), -1);
818 if (error != HWC3::Error::None) {
819 ALOGE("%s: display:%" PRIu32 " failed to flush drm buffer" PRIu64,
820 __FUNCTION__, displayId);
821 }
822
823 *outDisplayFence = std::move(fence);
824 compositionResult->markAsInUse(outDisplayFence->ok()
825 ? ::android::base::unique_fd(dup(*outDisplayFence))
826 : ::android::base::unique_fd());
827 return error;
828 }
829
canComposeLayer(Layer * layer)830 bool GuestFrameComposer::canComposeLayer(Layer* layer) {
831 const auto layerCompositionType = layer->getCompositionType();
832 if (layerCompositionType == Composition::SOLID_COLOR) {
833 return true;
834 }
835
836 if (layerCompositionType != Composition::DEVICE) {
837 return false;
838 }
839
840 buffer_handle_t bufferHandle = layer->getBuffer().getBuffer();
841 if (bufferHandle == nullptr) {
842 ALOGW("%s received a layer with a null handle", __FUNCTION__);
843 return false;
844 }
845
846 auto bufferOpt = mGralloc.Import(bufferHandle);
847 if (!bufferOpt) {
848 ALOGE("Failed to import layer buffer.");
849 return false;
850 }
851 GrallocBuffer& buffer = *bufferOpt;
852
853 auto bufferFormatOpt = buffer.GetDrmFormat();
854 if (!bufferFormatOpt) {
855 ALOGE("Failed to get layer buffer format.");
856 return false;
857 }
858 uint32_t bufferFormat = *bufferFormatOpt;
859
860 if (!IsDrmFormatSupported(bufferFormat)) {
861 return false;
862 }
863
864 return true;
865 }
866
composeLayerInto(AlternatingImageStorage & compositionIntermediateStorage,Layer * srcLayer,std::uint8_t * dstBuffer,std::uint32_t dstBufferWidth,std::uint32_t dstBufferHeight,std::uint32_t dstBufferStrideBytes,std::uint32_t dstBufferBytesPerPixel)867 HWC3::Error GuestFrameComposer::composeLayerInto(
868 AlternatingImageStorage& compositionIntermediateStorage,
869 Layer* srcLayer, //
870 std::uint8_t* dstBuffer, //
871 std::uint32_t dstBufferWidth, //
872 std::uint32_t dstBufferHeight, //
873 std::uint32_t dstBufferStrideBytes, //
874 std::uint32_t dstBufferBytesPerPixel) {
875 ATRACE_CALL();
876
877 libyuv::RotationMode rotation = GetRotationFromTransform(srcLayer->getTransform());
878
879 common::Rect srcLayerCrop = srcLayer->getSourceCropInt();
880 common::Rect srcLayerDisplayFrame = srcLayer->getDisplayFrame();
881
882 BufferSpec srcLayerSpec;
883
884 std::optional<GrallocBuffer> srcBufferOpt;
885 std::optional<GrallocBufferView> srcBufferViewOpt;
886
887 const auto srcLayerCompositionType = srcLayer->getCompositionType();
888 if (srcLayerCompositionType == Composition::DEVICE) {
889 srcBufferOpt = mGralloc.Import(srcLayer->waitAndGetBuffer());
890 if (!srcBufferOpt) {
891 ALOGE("%s: failed to import layer buffer.", __FUNCTION__);
892 return HWC3::Error::NoResources;
893 }
894 GrallocBuffer& srcBuffer = *srcBufferOpt;
895
896 srcBufferViewOpt = srcBuffer.Lock();
897 if (!srcBufferViewOpt) {
898 ALOGE("%s: failed to lock import layer buffer.", __FUNCTION__);
899 return HWC3::Error::NoResources;
900 }
901 GrallocBufferView& srcBufferView = *srcBufferViewOpt;
902
903 auto srcLayerSpecOpt = GetBufferSpec(srcBuffer, srcBufferView, srcLayerCrop);
904 if (!srcLayerSpecOpt) {
905 return HWC3::Error::NoResources;
906 }
907
908 srcLayerSpec = *srcLayerSpecOpt;
909 } else if (srcLayerCompositionType == Composition::SOLID_COLOR) {
910 // srcLayerSpec not used by `needsFill` below.
911 }
912
913 // TODO(jemoreira): Remove the hardcoded fomat.
914 bool needsFill = srcLayerCompositionType == Composition::SOLID_COLOR;
915 bool needsConversion = srcLayerCompositionType == Composition::DEVICE &&
916 srcLayerSpec.drmFormat != DRM_FORMAT_XBGR8888 &&
917 srcLayerSpec.drmFormat != DRM_FORMAT_ABGR8888;
918 bool needsScaling = LayerNeedsScaling(*srcLayer);
919 bool needsRotation = rotation != libyuv::kRotate0;
920 bool needsTranspose = needsRotation && rotation != libyuv::kRotate180;
921 bool needsVFlip = GetVFlipFromTransform(srcLayer->getTransform());
922 bool needsAttenuation = LayerNeedsAttenuation(*srcLayer);
923 bool needsBlending = LayerNeedsBlending(*srcLayer);
924 bool needsCopy = !(needsConversion || needsScaling || needsRotation || needsVFlip ||
925 needsAttenuation || needsBlending);
926
927 BufferSpec dstLayerSpec(
928 dstBuffer,
929 /*buffer_ycbcr=*/std::nullopt, dstBufferWidth, dstBufferHeight,
930 static_cast<uint32_t>(srcLayerDisplayFrame.left),
931 static_cast<uint32_t>(srcLayerDisplayFrame.top),
932 static_cast<uint32_t>(srcLayerDisplayFrame.right - srcLayerDisplayFrame.left),
933 static_cast<uint32_t>(srcLayerDisplayFrame.bottom - srcLayerDisplayFrame.top),
934 DRM_FORMAT_XBGR8888, dstBufferStrideBytes, dstBufferBytesPerPixel);
935
936 // Add the destination layer to the bottom of the buffer stack
937 std::vector<BufferSpec> dstBufferStack(1, dstLayerSpec);
938
939 // If more than operation is to be performed, a temporary buffer is needed for
940 // each additional operation
941
942 // N operations need N destination buffers, the destination layer (the
943 // framebuffer) is one of them, so only N-1 temporary buffers are needed.
944 // Vertical flip is not taken into account because it can be done together
945 // with any other operation.
946 int neededIntermediateImages = (needsFill ? 1 : 0) + (needsConversion ? 1 : 0) +
947 (needsScaling ? 1 : 0) + (needsRotation ? 1 : 0) +
948 (needsAttenuation ? 1 : 0) + (needsBlending ? 1 : 0) +
949 (needsCopy ? 1 : 0) - 1;
950
951 uint32_t mScratchBufferWidth =
952 static_cast<uint32_t>(srcLayerDisplayFrame.right - srcLayerDisplayFrame.left);
953 uint32_t mScratchBufferHeight =
954 static_cast<uint32_t>(srcLayerDisplayFrame.bottom - srcLayerDisplayFrame.top);
955 uint32_t mScratchBufferStrideBytes =
956 AlignToPower2(mScratchBufferWidth * dstBufferBytesPerPixel, 4);
957 uint32_t mScratchBufferSizeBytes = mScratchBufferHeight * mScratchBufferStrideBytes;
958
959 for (uint32_t i = 0; i < neededIntermediateImages; i++) {
960 BufferSpec mScratchBufferspec(
961 compositionIntermediateStorage.getRotatingScratchBuffer(mScratchBufferSizeBytes, i),
962 mScratchBufferWidth, mScratchBufferHeight, mScratchBufferStrideBytes);
963 dstBufferStack.push_back(mScratchBufferspec);
964 }
965
966 // Filling, conversion, and scaling should always be the first operations, so
967 // that every other operation works on equally sized frames (guaranteed to fit
968 // in the scratch buffers) in a common format.
969
970 if (needsFill) {
971 BufferSpec& dstBufferSpec = dstBufferStack.back();
972
973 int retval = DoFill(dstBufferSpec, srcLayer->getColor());
974 if (retval) {
975 ALOGE("Got error code %d from DoFill function", retval);
976 }
977
978 srcLayerSpec = dstBufferSpec;
979 dstBufferStack.pop_back();
980 }
981
982 // TODO(jemoreira): We are converting to ARGB as the first step under the
983 // assumption that scaling ARGB is faster than scaling I420 (the most common).
984 // This should be confirmed with testing.
985 if (needsConversion) {
986 BufferSpec& dstBufferSpec = dstBufferStack.back();
987 if (needsScaling || needsTranspose) {
988 // If a rotation or a scaling operation are needed the dimensions at the
989 // top of the buffer stack are wrong (wrong sizes for scaling, swapped
990 // width and height for 90 and 270 rotations).
991 // Make width and height match the crop sizes on the source
992 uint32_t srcWidth = srcLayerSpec.cropWidth;
993 uint32_t srcHeight = srcLayerSpec.cropHeight;
994 uint32_t dst_stride_bytes = AlignToPower2(srcWidth * dstBufferBytesPerPixel, 4);
995 uint32_t neededSize = dst_stride_bytes * srcHeight;
996 dstBufferSpec.width = srcWidth;
997 dstBufferSpec.height = srcHeight;
998 // Adjust the stride accordingly
999 dstBufferSpec.strideBytes = dst_stride_bytes;
1000 // Crop sizes also need to be adjusted
1001 dstBufferSpec.cropWidth = srcWidth;
1002 dstBufferSpec.cropHeight = srcHeight;
1003 // cropX and y are fine at 0, format is already set to match destination
1004
1005 // In case of a scale, the source frame may be bigger than the default tmp
1006 // buffer size
1007 dstBufferSpec.buffer =
1008 compositionIntermediateStorage.getSpecialScratchBuffer(neededSize);
1009 }
1010
1011 int retval = DoConversion(srcLayerSpec, dstBufferSpec, needsVFlip);
1012 if (retval) {
1013 ALOGE("Got error code %d from DoConversion function", retval);
1014 }
1015 needsVFlip = false;
1016 srcLayerSpec = dstBufferSpec;
1017 dstBufferStack.pop_back();
1018 }
1019
1020 if (needsScaling) {
1021 BufferSpec& dstBufferSpec = dstBufferStack.back();
1022 if (needsTranspose) {
1023 // If a rotation is needed, the temporary buffer has the correct size but
1024 // needs to be transposed and have its stride updated accordingly. The
1025 // crop sizes also needs to be transposed, but not the x and y since they
1026 // are both zero in a temporary buffer (and it is a temporary buffer
1027 // because a rotation will be performed next).
1028 std::swap(dstBufferSpec.width, dstBufferSpec.height);
1029 std::swap(dstBufferSpec.cropWidth, dstBufferSpec.cropHeight);
1030 // TODO (jemoreira): Aligment (To align here may cause the needed size to
1031 // be bigger than the buffer, so care should be taken)
1032 dstBufferSpec.strideBytes = dstBufferSpec.width * dstBufferBytesPerPixel;
1033 }
1034 int retval = DoScaling(srcLayerSpec, dstBufferSpec, needsVFlip);
1035 needsVFlip = false;
1036 if (retval) {
1037 ALOGE("Got error code %d from DoScaling function", retval);
1038 }
1039 srcLayerSpec = dstBufferSpec;
1040 dstBufferStack.pop_back();
1041 }
1042
1043 if (needsRotation) {
1044 int retval = DoRotation(srcLayerSpec, dstBufferStack.back(), rotation, needsVFlip);
1045 needsVFlip = false;
1046 if (retval) {
1047 ALOGE("Got error code %d from DoTransform function", retval);
1048 }
1049 srcLayerSpec = dstBufferStack.back();
1050 dstBufferStack.pop_back();
1051 }
1052
1053 if (needsAttenuation) {
1054 int retval = DoAttenuation(srcLayerSpec, dstBufferStack.back(), needsVFlip);
1055 needsVFlip = false;
1056 if (retval) {
1057 ALOGE("Got error code %d from DoBlending function", retval);
1058 }
1059 srcLayerSpec = dstBufferStack.back();
1060 dstBufferStack.pop_back();
1061 }
1062
1063 if (needsCopy) {
1064 int retval = DoCopy(srcLayerSpec, dstBufferStack.back(), needsVFlip);
1065 needsVFlip = false;
1066 if (retval) {
1067 ALOGE("Got error code %d from DoBlending function", retval);
1068 }
1069 srcLayerSpec = dstBufferStack.back();
1070 dstBufferStack.pop_back();
1071 }
1072
1073 // Blending (if needed) should always be the last operation, so that it reads
1074 // and writes in the destination layer and not some temporary buffer.
1075 if (needsBlending) {
1076 int retval = DoBlending(srcLayerSpec, dstBufferStack.back(), needsVFlip);
1077 needsVFlip = false;
1078 if (retval) {
1079 ALOGE("Got error code %d from DoBlending function", retval);
1080 }
1081 // Don't need to assign destination to source in the last one
1082 dstBufferStack.pop_back();
1083 }
1084
1085 return HWC3::Error::None;
1086 }
1087
1088 namespace {
1089
1090 // Returns a color matrix that can be used with libyuv by converting values
1091 // in -1 to 1 into -64 to 64 and transposing.
ToLibyuvColorMatrix(const std::array<float,16> & in)1092 std::array<std::int8_t, 16> ToLibyuvColorMatrix(const std::array<float, 16>& in) {
1093 std::array<std::int8_t, 16> out;
1094
1095 for (size_t r = 0; r < 4; r++) {
1096 for (size_t c = 0; c < 4; c++) {
1097 size_t indexIn = (4 * r) + c;
1098 size_t indexOut = (4 * c) + r;
1099
1100 out[indexOut] = static_cast<std::int8_t>(
1101 std::max(-128, std::min(127, static_cast<int>(in[indexIn] * 64.0f + 0.5f))));
1102 }
1103 }
1104
1105 return out;
1106 }
1107
1108 } // namespace
1109
applyColorTransformToRGBA(const std::array<float,16> & transfromMatrix,std::uint8_t * buffer,std::uint32_t bufferWidth,std::uint32_t bufferHeight,std::uint32_t bufferStrideBytes)1110 HWC3::Error GuestFrameComposer::applyColorTransformToRGBA(
1111 const std::array<float, 16>& transfromMatrix, //
1112 std::uint8_t* buffer, //
1113 std::uint32_t bufferWidth, //
1114 std::uint32_t bufferHeight, //
1115 std::uint32_t bufferStrideBytes) {
1116 ATRACE_CALL();
1117
1118 const auto transformMatrixLibyuv = ToLibyuvColorMatrix(transfromMatrix);
1119 libyuv::ARGBColorMatrix(buffer, static_cast<int>(bufferStrideBytes), //
1120 buffer, static_cast<int>(bufferStrideBytes), //
1121 transformMatrixLibyuv.data(), //
1122 static_cast<int>(bufferWidth), //
1123 static_cast<int>(bufferHeight));
1124
1125 return HWC3::Error::None;
1126 }
1127
1128 } // namespace aidl::android::hardware::graphics::composer3::impl
1129