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