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