• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 "Backend.h"
18 
19 #include <climits>
20 
21 #include "BackendManager.h"
22 #include "bufferinfo/BufferInfoGetter.h"
23 #include "hardware/hwcomposer2.h"
24 
25 namespace android {
26 
27 namespace {
28 
HasCursorLayer(const std::vector<HwcLayer * > & layers)29 bool HasCursorLayer(const std::vector<HwcLayer *> &layers) {
30   return std::find_if(layers.begin(), layers.end(), [&](auto *layer) -> bool {
31            return layer->GetSfType() == HWC2::Composition::Cursor;
32          }) != layers.end();
33 }
34 
35 }  // namespace
36 
ValidateDisplay(HwcDisplay * display,uint32_t * num_types,uint32_t * num_requests)37 HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
38                                      uint32_t *num_requests) {
39   *num_types = 0;
40   *num_requests = 0;
41 
42   auto layers = display->GetOrderLayersByZPos();
43 
44   int client_start = -1;
45   size_t client_size = 0;
46 
47   auto flatcon = display->GetFlatCon();
48   if (flatcon) {
49     bool should_flatten = false;
50     if (layers.size() <= 1)
51       flatcon->Disable();
52     else
53       should_flatten = flatcon->NewFrame();
54 
55     if (should_flatten) {
56       display->total_stats().frames_flattened_++;
57       MarkValidated(layers, 0, layers.size());
58       *num_types = layers.size();
59       return HWC2::Error::HasChanges;
60     }
61   }
62 
63   std::tie(client_start, client_size) = GetClientLayers(display, layers);
64 
65   MarkValidated(layers, client_start, client_size);
66 
67   auto testing_needed = client_start != 0 || client_size != layers.size();
68 
69   AtomicCommitArgs a_args = {.test_only = true};
70 
71   if (testing_needed &&
72       display->CreateComposition(a_args) != HWC2::Error::None) {
73     ++display->total_stats().failed_kms_validate_;
74     client_start = 0;
75     client_size = layers.size();
76 
77     // Expand the client range to include all layers except the cursor layer (if
78     // there is one) and retry.
79     auto [_, cursor_plane] = display->GetPipe().GetUsablePlanes();
80     if (cursor_plane && HasCursorLayer(layers)) {
81       --client_size;
82       MarkValidated(layers, 0, client_size);
83 
84       testing_needed = display->CreateComposition(a_args) != HWC2::Error::None;
85 
86       // If testing is still needed, expand the client range to include the
87       // cursor layer for the next retry.
88       if (testing_needed) {
89         ++client_size;
90         ++display->total_stats().failed_kms_validate_;
91       }
92     }
93 
94     if (testing_needed) {
95       MarkValidated(layers, 0, client_size);
96     }
97   }
98 
99   *num_types = client_size;
100 
101   display->total_stats().gpu_pixops_ += CalcPixOps(layers, client_start,
102                                                    client_size);
103   display->total_stats().total_pixops_ += CalcPixOps(layers, 0, layers.size());
104 
105   return *num_types != 0 ? HWC2::Error::HasChanges : HWC2::Error::None;
106 }
107 
GetClientLayers(HwcDisplay * display,const std::vector<HwcLayer * > & layers)108 std::tuple<int, size_t> Backend::GetClientLayers(
109     HwcDisplay *display, const std::vector<HwcLayer *> &layers) {
110   int client_start = -1;
111   size_t client_size = 0;
112 
113   for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
114     if (IsClientLayer(display, layers[z_order])) {
115       if (client_start < 0)
116         client_start = (int)z_order;
117       client_size = (z_order - client_start) + 1;
118     }
119   }
120 
121   return GetExtraClientRange(display, layers, client_start, client_size);
122 }
123 
IsClientLayer(HwcDisplay * display,HwcLayer * layer)124 bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) {
125   return !HardwareSupportsLayerType(layer->GetSfType()) ||
126          !layer->IsLayerUsableAsDevice() || display->CtmByGpu() ||
127          (layer->GetLayerData().pi.RequireScalingOrPhasing() &&
128           display->GetHwc()->GetResMan().ForcedScalingWithGpu());
129 }
130 
HardwareSupportsLayerType(HWC2::Composition comp_type)131 bool Backend::HardwareSupportsLayerType(HWC2::Composition comp_type) {
132   return comp_type == HWC2::Composition::Device ||
133          comp_type == HWC2::Composition::Cursor;
134 }
135 
CalcPixOps(const std::vector<HwcLayer * > & layers,size_t first_z,size_t size)136 uint32_t Backend::CalcPixOps(const std::vector<HwcLayer *> &layers,
137                              size_t first_z, size_t size) {
138   uint32_t pixops = 0;
139   for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
140     if (z_order >= first_z && z_order < first_z + size) {
141       auto &df = layers[z_order]->GetLayerData().pi.display_frame;
142       if (df.i_rect) {
143         pixops += (df.i_rect->right - df.i_rect->left) *
144                   (df.i_rect->bottom - df.i_rect->top);
145       }
146     }
147   }
148   return pixops;
149 }
150 
MarkValidated(std::vector<HwcLayer * > & layers,size_t client_first_z,size_t client_size)151 void Backend::MarkValidated(std::vector<HwcLayer *> &layers,
152                             size_t client_first_z, size_t client_size) {
153   for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
154     if (z_order >= client_first_z && z_order < client_first_z + client_size) {
155       layers[z_order]->SetValidatedType(HWC2::Composition::Client);
156     } else if (layers[z_order]->GetSfType() == HWC2::Composition::Cursor) {
157       layers[z_order]->SetValidatedType(HWC2::Composition::Cursor);
158     } else {
159       layers[z_order]->SetValidatedType(HWC2::Composition::Device);
160     }
161   }
162 }
163 
GetExtraClientRange(HwcDisplay * display,const std::vector<HwcLayer * > & layers,int client_start,size_t client_size)164 std::tuple<int, int> Backend::GetExtraClientRange(
165     HwcDisplay *display, const std::vector<HwcLayer *> &layers,
166     int client_start, size_t client_size) {
167   auto [planes, cursor_plane] = display->GetPipe().GetUsablePlanes();
168   size_t avail_planes = planes.size();
169   size_t layers_size = layers.size();
170 
171   // |cursor_plane| is not counted among |avail_planes|, so the cursor layer
172   // shouldn't be counted in |layers_size|.
173   if (cursor_plane && HasCursorLayer(layers)) {
174     --layers_size;
175   }
176 
177   /*
178    * If more layers than planes, save one plane
179    * for client composited layers
180    */
181   if (avail_planes < layers_size) {
182     avail_planes--;
183   }
184 
185   const int extra_client = int(layers_size - client_size) - int(avail_planes);
186 
187   if (extra_client > 0) {
188     int start = 0;
189     size_t steps = 0;
190     if (client_size != 0) {
191       const int prepend = std::min(client_start, extra_client);
192       const int append = std::min(int(layers_size) -
193                                       int(client_start + client_size),
194                                   extra_client);
195       start = client_start - (int)prepend;
196       client_size += extra_client;
197       steps = 1 + std::min(std::min(append, prepend),
198                            int(layers_size) - int(start + client_size));
199     } else {
200       client_size = extra_client;
201       steps = 1 + layers_size - extra_client;
202     }
203 
204     uint32_t gpu_pixops = UINT32_MAX;
205     for (size_t i = 0; i < steps; i++) {
206       const uint32_t po = CalcPixOps(layers, start + i, client_size);
207       if (po < gpu_pixops) {
208         gpu_pixops = po;
209         client_start = start + int(i);
210       }
211     }
212   }
213 
214   return std::make_tuple(client_start, client_size);
215 }
216 
217 // clang-format off
218 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, cert-err58-cpp)
219 REGISTER_BACKEND("generic", Backend);
220 // clang-format on
221 
222 }  // namespace android
223