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