• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 "vsoc_composer.h"
18 
19 #include <algorithm>
20 #include <cstdlib>
21 #include <utility>
22 #include <vector>
23 
24 #include <cutils/log.h>
25 #include <hardware/hwcomposer.h>
26 #include <hardware/hwcomposer_defs.h>
27 #include <libyuv.h>
28 #include <system/graphics.h>
29 
30 #include "common/vsoc/lib/screen_region_view.h"
31 
32 #include "geometry_utils.h"
33 #include "hwcomposer_common.h"
34 
35 using vsoc::screen::ScreenRegionView;
36 
37 namespace cvd {
38 
39 namespace {
40 
41 bool LayerNeedsScaling(const vsoc_hwc_layer& layer) {
42   int from_w = layer.sourceCrop.right - layer.sourceCrop.left;
43   int from_h = layer.sourceCrop.bottom - layer.sourceCrop.top;
44   int to_w = layer.displayFrame.right - layer.displayFrame.left;
45   int to_h = layer.displayFrame.bottom - layer.displayFrame.top;
46 
47   bool not_rot_scale = from_w != to_w || from_h != to_h;
48   bool rot_scale = from_w != to_h || from_h != to_w;
49 
50   bool needs_rot = layer.transform & HAL_TRANSFORM_ROT_90;
51 
52   return needs_rot ? rot_scale : not_rot_scale;
53 }
54 
55 bool LayerNeedsBlending(const vsoc_hwc_layer& layer) {
56   return layer.blending != HWC_BLENDING_NONE;
57 }
58 
59 bool LayerNeedsAttenuation(const vsoc_hwc_layer& layer) {
60   return layer.blending == HWC_BLENDING_COVERAGE;
61 }
62 
63 struct BufferSpec;
64 typedef int (*ConverterFunction)(const BufferSpec& src, const BufferSpec& dst,
65                                  bool v_flip);
66 int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
67 int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
68 ConverterFunction GetConverter(uint32_t format) {
69   switch (format) {
70     case HAL_PIXEL_FORMAT_RGBA_8888:
71     case HAL_PIXEL_FORMAT_RGBX_8888:
72     case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
73       return &DoCopy;
74 
75     case HAL_PIXEL_FORMAT_YV12:
76       return &ConvertFromYV12;
77 
78     // Unsupported formats
79     // TODO(jemoreira): Conversion from these formats should be implemented as
80     // we find evidence of its usage.
81     // case HAL_PIXEL_FORMAT_BGRA_8888:
82 
83     // case HAL_PIXEL_FORMAT_RGB_888:
84     // case HAL_PIXEL_FORMAT_RGB_565:
85 
86     // case HAL_PIXEL_FORMAT_sRGB_A_8888:
87     // case HAL_PIXEL_FORMAT_sRGB_X_8888:
88 
89     // case HAL_PIXEL_FORMAT_Y8:
90     // case HAL_PIXEL_FORMAT_Y16:
91 
92     // case HAL_PIXEL_FORMAT_RAW_SENSOR:
93     // case HAL_PIXEL_FORMAT_BLOB:
94 
95     // case HAL_PIXEL_FORMAT_YCbCr_420_888:
96     // case HAL_PIXEL_FORMAT_YCbCr_422_SP:
97     // case HAL_PIXEL_FORMAT_YCrCb_420_SP:
98     // case HAL_PIXEL_FORMAT_YCbCr_422_I:
99     default:
100       ALOGW("Unsupported format: 0x%04x, returning null converter function",
101             format);
102   }
103   return NULL;
104 }
105 
106 // Whether we support a given format
107 bool IsFormatSupported(uint32_t format) { return GetConverter(format) != NULL; }
108 
109 bool CanCompositeLayer(const vsoc_hwc_layer& layer) {
110   if (layer.handle == NULL) {
111     ALOGW("%s received a layer with a null handler", __FUNCTION__);
112     return false;
113   }
114   int format = reinterpret_cast<const private_handle_t*>(layer.handle)->format;
115   if (!IsFormatSupported(format)) {
116     ALOGD("Unsupported pixel format: 0x%x, doing software composition instead",
117           format);
118     return false;
119   }
120   return true;
121 }
122 
123 /*******************************************************************************
124 Libyuv's convert functions only allow the combination of any rotation (multiple
125 of 90 degrees) and a vertical flip, but not horizontal flips.
126 Surfaceflinger's transformations are expressed in terms of a vertical flip, a
127 horizontal flip and/or a single 90 degrees clockwise rotation (see
128 NATIVE_WINDOW_TRANSFORM_HINT documentation on system/window.h for more insight).
129 The following code allows to turn a horizontal flip into a 180 degrees rotation
130 and a vertical flip.
131 *******************************************************************************/
132 libyuv::RotationMode GetRotationFromTransform(uint32_t transform) {
133   uint32_t rotation =
134       (transform & HAL_TRANSFORM_ROT_90) ? 1 : 0;          // 1 * ROT90 bit
135   rotation += (transform & HAL_TRANSFORM_FLIP_H) ? 2 : 0;  // 2 * VFLIP bit
136   return static_cast<libyuv::RotationMode>(90 * rotation);
137 }
138 
139 bool GetVFlipFromTransform(uint32_t transform) {
140   // vertical flip xor horizontal flip
141   return ((transform & HAL_TRANSFORM_FLIP_V) >> 1) ^
142          (transform & HAL_TRANSFORM_FLIP_H);
143 }
144 
145 struct BufferSpec {
146   uint8_t* buffer;
147   size_t size;
148   int width;
149   int height;
150   int stride;
151   int crop_x;
152   int crop_y;
153   int crop_width;
154   int crop_height;
155   uint32_t format;
156 
157   BufferSpec(uint8_t* buffer, size_t size, int width, int height, int stride)
158       : buffer(buffer),
159         size(size),
160         width(width),
161         height(height),
162         stride(stride),
163         crop_x(0),
164         crop_y(0),
165         crop_width(width),
166         crop_height(height),
167         format(HAL_PIXEL_FORMAT_RGBA_8888) {}
168 };
169 
170 int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
171   // use the stride in pixels as the source width
172   int stride_in_pixels = src.stride / formatToBytesPerPixel(src.format);
173 
174   // The following calculation of plane offsets and alignments are based on
175   // swiftshader's Sampler::setTextureLevel() implementation
176   // (Renderer/Sampler.cpp:225)
177   uint8_t* src_y = src.buffer;
178   int stride_y = stride_in_pixels;
179   uint8_t* src_v = src_y + stride_y * src.height;
180   int stride_v = ScreenRegionView::align(stride_y / 2, 16);
181   uint8_t* src_u = src_v + stride_v *  src.height / 2;
182   int stride_u = ScreenRegionView::align(stride_y / 2, 16);
183 
184   // Adjust for crop
185   src_y += src.crop_y * stride_y + src.crop_x;
186   src_v += (src.crop_y / 2) * stride_v + (src.crop_x / 2);
187   src_u += (src.crop_y / 2) * stride_u + (src.crop_x / 2);
188   uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
189                         dst.crop_x * formatToBytesPerPixel(dst.format);
190 
191   // YV12 is the same as I420, with the U and V planes swapped
192   return libyuv::I420ToARGB(src_y, stride_y, src_v, stride_v, src_u, stride_u,
193                             dst_buffer, dst.stride, dst.crop_width,
194                             v_flip ? -dst.crop_height : dst.crop_height);
195 }
196 
197 int DoConversion(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
198   return (*GetConverter(src.format))(src, dst, v_flip);
199 }
200 
201 int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
202   // Point to the upper left corner of the crop rectangle
203   uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
204                         src.crop_x * formatToBytesPerPixel(src.format);
205   uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
206                         dst.crop_x * formatToBytesPerPixel(dst.format);
207   int width = src.crop_width;
208   int height = src.crop_height;
209 
210   if (v_flip) {
211     height = -height;
212   }
213 
214   // HAL formats are named based on the order of the pixel componets on the
215   // byte stream, while libyuv formats are named based on the order of those
216   // pixel components in an integer written from left to right. So
217   // libyuv::FOURCC_ARGB is equivalent to HAL_PIXEL_FORMAT_BGRA_8888.
218   return libyuv::ARGBCopy(src_buffer, src.stride, dst_buffer, dst.stride, width,
219                           height);
220 }
221 
222 int DoRotation(const BufferSpec& src, const BufferSpec& dst,
223                libyuv::RotationMode rotation, bool v_flip) {
224   // Point to the upper left corner of the crop rectangles
225   uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
226                         src.crop_x * formatToBytesPerPixel(src.format);
227   uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
228                         dst.crop_x * formatToBytesPerPixel(dst.format);
229   int width = src.crop_width;
230   int height = src.crop_height;
231 
232   if (v_flip) {
233     height = -height;
234   }
235 
236   return libyuv::ARGBRotate(src_buffer, src.stride, dst_buffer, dst.stride,
237                             width, height, rotation);
238 }
239 
240 int DoScaling(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
241   // Point to the upper left corner of the crop rectangles
242   uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
243                         src.crop_x * formatToBytesPerPixel(src.format);
244   uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
245                         dst.crop_x * formatToBytesPerPixel(dst.format);
246   int src_width = src.crop_width;
247   int src_height = src.crop_height;
248   int dst_width = dst.crop_width;
249   int dst_height = dst.crop_height;
250 
251   if (v_flip) {
252     src_height = -src_height;
253   }
254 
255   return libyuv::ARGBScale(src_buffer, src.stride, src_width, src_height,
256                            dst_buffer, dst.stride, dst_width, dst_height,
257                            libyuv::kFilterBilinear);
258 }
259 
260 int DoAttenuation(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
261   // Point to the upper left corner of the crop rectangles
262   uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
263                         src.crop_x * formatToBytesPerPixel(src.format);
264   uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
265                         dest.crop_x * formatToBytesPerPixel(dest.format);
266   int width = dest.crop_width;
267   int height = dest.crop_height;
268 
269   if (v_flip) {
270     height = -height;
271   }
272 
273   return libyuv::ARGBAttenuate(src_buffer, src.stride, dst_buffer, dest.stride,
274                                width, height);
275 }
276 
277 int DoBlending(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
278   // Point to the upper left corner of the crop rectangles
279   uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
280                         src.crop_x * formatToBytesPerPixel(src.format);
281   uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
282                         dest.crop_x * formatToBytesPerPixel(dest.format);
283   int width = dest.crop_width;
284   int height = dest.crop_height;
285 
286   if (v_flip) {
287     height = -height;
288   }
289 
290   // libyuv's ARGB format is hwcomposer's BGRA format, since blending only cares
291   // for the position of alpha in the pixel and not the position of the colors
292   // this function is perfectly usable.
293   return libyuv::ARGBBlend(src_buffer, src.stride, dst_buffer, dest.stride,
294                            dst_buffer, dest.stride, width, height);
295 }
296 
297 }  // namespace
298 
299 void VSoCComposer::CompositeLayer(vsoc_hwc_layer* src_layer,
300                                   int buffer_idx) {
301   libyuv::RotationMode rotation =
302       GetRotationFromTransform(src_layer->transform);
303 
304   const private_handle_t* src_priv_handle =
305       reinterpret_cast<const private_handle_t*>(src_layer->handle);
306 
307   // TODO(jemoreira): Remove the hardcoded fomat.
308   bool needs_conversion = src_priv_handle->format != HAL_PIXEL_FORMAT_RGBX_8888;
309   bool needs_scaling = LayerNeedsScaling(*src_layer);
310   bool needs_rotation = rotation != libyuv::kRotate0;
311   bool needs_transpose = needs_rotation && rotation != libyuv::kRotate180;
312   bool needs_vflip = GetVFlipFromTransform(src_layer->transform);
313   bool needs_attenuation = LayerNeedsAttenuation(*src_layer);
314   bool needs_blending = LayerNeedsBlending(*src_layer);
315   bool needs_copy = !(needs_conversion || needs_scaling || needs_rotation ||
316                       needs_vflip || needs_attenuation || needs_blending);
317 
318   uint8_t* src_buffer;
319   uint8_t* dst_buffer = reinterpret_cast<uint8_t*>(
320       ScreenRegionView::GetInstance()->GetBuffer(buffer_idx));
321   int retval = gralloc_module_->lock(
322       gralloc_module_, src_layer->handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
323       src_priv_handle->x_res, src_priv_handle->y_res,
324       reinterpret_cast<void**>(&src_buffer));
325   if (retval) {
326     ALOGE("Got error code %d from lock function", retval);
327     return;
328   }
329   if (retval) {
330     ALOGE("Got error code %d from lock function", retval);
331     // TODO(jemoreira): Use a lock_guard-like object.
332     gralloc_module_->unlock(gralloc_module_, src_priv_handle);
333     return;
334   }
335 
336   BufferSpec src_layer_spec(src_buffer, src_priv_handle->total_size,
337                             src_priv_handle->x_res, src_priv_handle->y_res,
338                             src_priv_handle->stride_in_pixels *
339                                 formatToBytesPerPixel(src_priv_handle->format));
340   src_layer_spec.crop_x = src_layer->sourceCrop.left;
341   src_layer_spec.crop_y = src_layer->sourceCrop.top;
342   src_layer_spec.crop_width =
343       src_layer->sourceCrop.right - src_layer->sourceCrop.left;
344   src_layer_spec.crop_height =
345       src_layer->sourceCrop.bottom - src_layer->sourceCrop.top;
346   src_layer_spec.format = src_priv_handle->format;
347 
348   auto screen_view = ScreenRegionView::GetInstance();
349   BufferSpec dst_layer_spec(dst_buffer, screen_view->buffer_size(),
350                             screen_view->x_res(), screen_view->y_res(),
351                             screen_view->line_length());
352   dst_layer_spec.crop_x = src_layer->displayFrame.left;
353   dst_layer_spec.crop_y = src_layer->displayFrame.top;
354   dst_layer_spec.crop_width =
355       src_layer->displayFrame.right - src_layer->displayFrame.left;
356   dst_layer_spec.crop_height =
357       src_layer->displayFrame.bottom - src_layer->displayFrame.top;
358   // TODO(jemoreira): Remove the hardcoded fomat.
359   dst_layer_spec.format = HAL_PIXEL_FORMAT_RGBX_8888;
360 
361   // Add the destination layer to the bottom of the buffer stack
362   std::vector<BufferSpec> dest_buffer_stack(1, dst_layer_spec);
363 
364   // If more than operation is to be performed, a temporary buffer is needed for
365   // each additional operation
366 
367   // N operations need N destination buffers, the destination layer (the
368   // framebuffer) is one of them, so only N-1 temporary buffers are needed.
369   // Vertical flip is not taken into account because it can be done together
370   // with any other operation.
371   int needed_tmp_buffers = (needs_conversion ? 1 : 0) +
372                            (needs_scaling ? 1 : 0) + (needs_rotation ? 1 : 0) +
373                            (needs_attenuation ? 1 : 0) +
374                            (needs_blending ? 1 : 0) + (needs_copy ? 1 : 0) - 1;
375 
376   int x_res = src_layer->displayFrame.right - src_layer->displayFrame.left;
377   int y_res = src_layer->displayFrame.bottom - src_layer->displayFrame.top;
378   size_t output_frame_size =
379       x_res *
380     ScreenRegionView::align(y_res * screen_view->bytes_per_pixel(), 16);
381   while (needed_tmp_buffers > 0) {
382     BufferSpec tmp(RotateTmpBuffer(needed_tmp_buffers), output_frame_size,
383                    x_res, y_res,
384                    ScreenRegionView::align(
385                        x_res * screen_view->bytes_per_pixel(), 16));
386     dest_buffer_stack.push_back(tmp);
387     needed_tmp_buffers--;
388   }
389 
390   // Conversion and scaling should always be the first operations, so that every
391   // other operation works on equally sized frames (garanteed to fit in the tmp
392   // buffers)
393 
394   // TODO(jemoreira): We are converting to ARGB as the first step under the
395   // assumption that scaling ARGB is faster than scaling I420 (the most common).
396   // This should be confirmed with testing.
397   if (needs_conversion) {
398     BufferSpec& dst_buffer_spec = dest_buffer_stack.back();
399     if (needs_scaling || needs_transpose) {
400       // If a rotation or a scaling operation are needed the dimensions at the
401       // top of the buffer stack are wrong (wrong sizes for scaling, swapped
402       // width and height for 90 and 270 rotations).
403       // Make width and height match the crop sizes on the source
404       int src_width = src_layer_spec.crop_width;
405       int src_height = src_layer_spec.crop_height;
406       int dst_stride = ScreenRegionView::align(
407           src_width * screen_view->bytes_per_pixel(), 16);
408       size_t needed_size = dst_stride * src_height;
409       dst_buffer_spec.width = src_width;
410       dst_buffer_spec.height = src_height;
411       // Ajust the stride accordingly
412       dst_buffer_spec.stride = dst_stride;
413       // Crop sizes also need to be adjusted
414       dst_buffer_spec.crop_width = src_width;
415       dst_buffer_spec.crop_height = src_height;
416       dst_buffer_spec.size = needed_size;
417       // crop_x and y are fine at 0, format is already set to match destination
418 
419       // In case of a scale, the source frame may be bigger than the default tmp
420       // buffer size
421       if (needed_size > tmp_buffer_.size() / kNumTmpBufferPieces) {
422         dst_buffer_spec.buffer = GetSpecialTmpBuffer(needed_size);
423       }
424     }
425     retval = DoConversion(src_layer_spec, dst_buffer_spec, needs_vflip);
426     if (retval) {
427       ALOGE("Got error code %d from DoConversion function", retval);
428     }
429     needs_vflip = false;
430     src_layer_spec = dst_buffer_spec;
431     dest_buffer_stack.pop_back();
432   }
433 
434   if (needs_scaling) {
435     BufferSpec& dst_buffer_spec = dest_buffer_stack.back();
436     if (needs_transpose) {
437       // If a rotation is needed, the temporary buffer has the correct size but
438       // needs to be transposed and have its stride updated accordingly. The
439       // crop sizes also needs to be transposed, but not the x and y since they
440       // are both zero in a temporary buffer (and it is a temporary buffer
441       // because a rotation will be performed next).
442       std::swap(dst_buffer_spec.width, dst_buffer_spec.height);
443       std::swap(dst_buffer_spec.crop_width, dst_buffer_spec.crop_height);
444       // TODO (jemoreira): Aligment (To align here may cause the needed size to
445       // be bigger than the buffer, so care should be taken)
446       dst_buffer_spec.stride =
447           dst_buffer_spec.width * screen_view->bytes_per_pixel();
448     }
449     retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
450     needs_vflip = false;
451     if (retval) {
452       ALOGE("Got error code %d from DoScaling function", retval);
453     }
454     src_layer_spec = dst_buffer_spec;
455     dest_buffer_stack.pop_back();
456   }
457 
458   if (needs_rotation) {
459     retval = DoRotation(src_layer_spec, dest_buffer_stack.back(), rotation,
460                         needs_vflip);
461     needs_vflip = false;
462     if (retval) {
463       ALOGE("Got error code %d from DoTransform function", retval);
464     }
465     src_layer_spec = dest_buffer_stack.back();
466     dest_buffer_stack.pop_back();
467   }
468 
469   if (needs_attenuation) {
470     retval =
471         DoAttenuation(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
472     needs_vflip = false;
473     if (retval) {
474       ALOGE("Got error code %d from DoBlending function", retval);
475     }
476     src_layer_spec = dest_buffer_stack.back();
477     dest_buffer_stack.pop_back();
478   }
479 
480   if (needs_copy) {
481     retval = DoCopy(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
482     needs_vflip = false;
483     if (retval) {
484       ALOGE("Got error code %d from DoBlending function", retval);
485     }
486     src_layer_spec = dest_buffer_stack.back();
487     dest_buffer_stack.pop_back();
488   }
489 
490   // Blending (if needed) should always be the last operation, so that it reads
491   // and writes in the destination layer and not some temporary buffer.
492   if (needs_blending) {
493     retval = DoBlending(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
494     needs_vflip = false;
495     if (retval) {
496       ALOGE("Got error code %d from DoBlending function", retval);
497     }
498     // Don't need to assign destination to source in the last one
499     dest_buffer_stack.pop_back();
500   }
501 
502   gralloc_module_->unlock(gralloc_module_, src_priv_handle);
503 }
504 
505 /* static */ const int VSoCComposer::kNumTmpBufferPieces = 2;
506 
507 VSoCComposer::VSoCComposer(int64_t vsync_base_timestamp,
508                            int32_t vsync_period_ns)
509     : BaseComposer(vsync_base_timestamp, vsync_period_ns),
510       tmp_buffer_(kNumTmpBufferPieces *
511                   ScreenRegionView::GetInstance()->buffer_size()) {}
512 
513 VSoCComposer::~VSoCComposer() {}
514 
515 int VSoCComposer::PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
516   int composited_layers_count = 0;
517 
518   // Loop over layers in inverse order of z-index
519   for (size_t layer_index = num_layers; layer_index > 0;) {
520     // Decrement here to be able to compare unsigned integer with 0 in the
521     // loop condition
522     --layer_index;
523     if (IS_TARGET_FRAMEBUFFER(layers[layer_index].compositionType)) {
524       continue;
525     }
526     if (layers[layer_index].flags & HWC_SKIP_LAYER) {
527       continue;
528     }
529     if (layers[layer_index].compositionType == HWC_BACKGROUND) {
530       layers[layer_index].compositionType = HWC_FRAMEBUFFER;
531       continue;
532     }
533     layers[layer_index].compositionType = HWC_OVERLAY;
534     // Hwcomposer cannot draw below software-composed layers, so we need
535     // to mark those HWC_FRAMEBUFFER as well.
536     for (size_t top_idx = layer_index + 1; top_idx < num_layers; ++top_idx) {
537       // layers marked as skip are in a state that makes them unreliable to
538       // read, so it's best to assume they cover the whole screen
539       if (layers[top_idx].flags & HWC_SKIP_LAYER ||
540           (layers[top_idx].compositionType == HWC_FRAMEBUFFER &&
541            LayersOverlap(layers[layer_index], layers[top_idx]))) {
542         layers[layer_index].compositionType = HWC_FRAMEBUFFER;
543         break;
544       }
545     }
546     if (layers[layer_index].compositionType == HWC_OVERLAY &&
547         !CanCompositeLayer(layers[layer_index])) {
548       layers[layer_index].compositionType = HWC_FRAMEBUFFER;
549     }
550     if (layers[layer_index].compositionType == HWC_OVERLAY) {
551       ++composited_layers_count;
552     }
553   }
554   return composited_layers_count;
555 }
556 
557 int VSoCComposer::SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
558   int targetFbs = 0;
559   int buffer_idx = NextScreenBuffer();
560 
561   // The framebuffer target layer should be composed if at least one layers was
562   // marked HWC_FRAMEBUFFER or if it's the only layer in the composition
563   // (unlikely)
564   bool fb_target = true;
565   for (size_t idx = 0; idx < num_layers; idx++) {
566     if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
567       // At least one was found
568       fb_target = true;
569       break;
570     }
571     if (layers[idx].compositionType == HWC_OVERLAY) {
572       // Not the only layer in the composition
573       fb_target = false;
574     }
575   }
576 
577   // When the framebuffer target needs to be composed, it has to go first.
578   if (fb_target) {
579     for (size_t idx = 0; idx < num_layers; idx++) {
580       if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
581         CompositeLayer(&layers[idx], buffer_idx);
582         break;
583       }
584     }
585   }
586 
587   for (size_t idx = 0; idx < num_layers; idx++) {
588     if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
589       ++targetFbs;
590     }
591     if (layers[idx].compositionType == HWC_OVERLAY &&
592         !(layers[idx].flags & HWC_SKIP_LAYER)) {
593       CompositeLayer(&layers[idx], buffer_idx);
594     }
595   }
596   if (targetFbs != 1) {
597     ALOGW("Saw %zu layers, posted=%d", num_layers, targetFbs);
598   }
599   Broadcast(buffer_idx);
600   return 0;
601 }
602 
603 uint8_t* VSoCComposer::RotateTmpBuffer(unsigned int order) {
604   return &tmp_buffer_[(order % kNumTmpBufferPieces) * tmp_buffer_.size() /
605                       kNumTmpBufferPieces];
606 }
607 
608 uint8_t* VSoCComposer::GetSpecialTmpBuffer(size_t needed_size) {
609   special_tmp_buffer_.resize(needed_size);
610   return &special_tmp_buffer_[0];
611 }
612 
613 }  // namespace cvd
614