1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <limits>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/test/null_task_runner.h"
10 #include "base/time/time.h"
11 #include "base/timer/lap_timer.h"
12 #include "components/viz/common/display/renderer_settings.h"
13 #include "components/viz/common/quads/compositor_frame.h"
14 #include "components/viz/common/quads/compositor_render_pass.h"
15 #include "components/viz/common/quads/draw_quad.h"
16 #include "components/viz/common/quads/texture_draw_quad.h"
17 #include "components/viz/common/surfaces/frame_sink_id.h"
18 #include "components/viz/service/display/aggregated_frame.h"
19 #include "components/viz/service/display/display.h"
20 #include "components/viz/service/display/display_scheduler.h"
21 #include "components/viz/service/display/output_surface.h"
22 #include "components/viz/service/display/overlay_processor_stub.h"
23 #include "components/viz/service/display/shared_bitmap_manager.h"
24 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
25 #include "components/viz/test/fake_output_surface.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "testing/perf/perf_result_reporter.h"
28
29 namespace viz {
30 namespace {
31
32 static const int kTimeLimitMillis = 3000;
33 static const int kWarmupRuns = 5;
34 static const int kTimeCheckInterval = 10;
35 static const int kHeight = 1000;
36 static const int kWidth = 1000;
37
38 constexpr char kMetricPrefixRemoveOverdrawQuad[] = "RemoveOverdrawQuad.";
39 constexpr char kMetricOverlapThroughputRunsPerS[] = "overlap_throughput";
40 constexpr char kMetricIsolatedThroughputRunsPerS[] = "isolated_throughput";
41 constexpr char kMetricPartialOverlapThroughputRunsPerS[] =
42 "partial_overlap_throughput";
43 constexpr char kMetricAdjacentThroughputRunsPerS[] = "adjacent_throughput";
44
SetUpRemoveOverdrawQuadReporter(const std::string & story)45 perf_test::PerfResultReporter SetUpRemoveOverdrawQuadReporter(
46 const std::string& story) {
47 perf_test::PerfResultReporter reporter(kMetricPrefixRemoveOverdrawQuad,
48 story);
49 reporter.RegisterImportantMetric(kMetricOverlapThroughputRunsPerS, "runs/s");
50 reporter.RegisterImportantMetric(kMetricIsolatedThroughputRunsPerS, "runs/s");
51 reporter.RegisterImportantMetric(kMetricPartialOverlapThroughputRunsPerS,
52 "runs/s");
53 reporter.RegisterImportantMetric(kMetricAdjacentThroughputRunsPerS, "runs/s");
54 return reporter;
55 }
56
57 class RemoveOverdrawQuadPerfTest : public testing::Test {
58 public:
RemoveOverdrawQuadPerfTest()59 RemoveOverdrawQuadPerfTest()
60 : timer_(kWarmupRuns,
61 base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
62 kTimeCheckInterval),
63 task_runner_(base::MakeRefCounted<base::NullTaskRunner>()) {}
64
CreateDisplay()65 std::unique_ptr<Display> CreateDisplay() {
66 FrameSinkId frame_sink_id(3, 3);
67
68 auto scheduler = std::make_unique<DisplayScheduler>(&begin_frame_source_,
69 task_runner_.get(), 1);
70
71 std::unique_ptr<FakeOutputSurface> output_surface =
72 FakeOutputSurface::Create3d();
73
74 auto overlay_processor = std::make_unique<OverlayProcessorStub>();
75 // Normally display will need to take ownership of a
76 // gpu::GpuTaskschedulerhelper in order to keep it alive to share between
77 // the output surface and the overlay processor. In this case the overlay
78 // processor is a stub and the output surface is test only as well, so there
79 // is no need to pass in a real gpu::GpuTaskSchedulerHelper.
80 // TODO(weiliangc): Figure out a better way to set up test without passing
81 // in nullptr.
82 auto display = std::make_unique<Display>(
83 &bitmap_manager_, RendererSettings(), &debug_settings_, frame_sink_id,
84 nullptr /* gpu::GpuTaskSchedulerHelper */, std::move(output_surface),
85 std::move(overlay_processor), std::move(scheduler), task_runner_.get());
86 return display;
87 }
88
89 // Create an arbitrary SharedQuadState for the given |render_pass|.
CreateSharedQuadState(AggregatedRenderPass * render_pass,gfx::Rect rect)90 SharedQuadState* CreateSharedQuadState(AggregatedRenderPass* render_pass,
91 gfx::Rect rect) {
92 gfx::Transform quad_transform = gfx::Transform();
93 bool is_clipped = false;
94 bool are_contents_opaque = true;
95 float opacity = 1.f;
96 int sorting_context_id = 65536;
97 SkBlendMode blend_mode = SkBlendMode::kSrcOver;
98
99 SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
100 state->SetAll(quad_transform, rect, rect,
101 /*mask_filter_info=*/gfx::MaskFilterInfo(), rect, is_clipped,
102 are_contents_opaque, opacity, blend_mode, sorting_context_id);
103 return state;
104 }
105
106 // Append draw quads to a given |shared_quad_state|.
AppendQuads(SharedQuadState * shared_quad_state,int quad_height,int quad_width)107 void AppendQuads(SharedQuadState* shared_quad_state,
108 int quad_height,
109 int quad_width) {
110 bool needs_blending = false;
111 ResourceId resource_id = 1;
112 bool premultiplied_alpha = true;
113 gfx::PointF uv_top_left(0, 0);
114 gfx::PointF uv_bottom_right(1, 1);
115 SkColor background_color = SK_ColorRED;
116 float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f};
117 bool y_flipped = false;
118 bool nearest_neighbor = true;
119
120 int x_left = shared_quad_state->visible_quad_layer_rect.x();
121 int x_right = x_left + shared_quad_state->visible_quad_layer_rect.width();
122 int y_top = shared_quad_state->visible_quad_layer_rect.y();
123 int y_bottom = y_top + shared_quad_state->visible_quad_layer_rect.height();
124 int i = x_left;
125 int j = y_top;
126 while (i + quad_width <= x_right) {
127 while (j + quad_height <= y_bottom) {
128 auto* quad = frame_.render_pass_list.front()
129 ->CreateAndAppendDrawQuad<TextureDrawQuad>();
130 gfx::Rect rect(i, j, quad_width, quad_height);
131 quad->SetNew(shared_quad_state, rect, rect, needs_blending, resource_id,
132 premultiplied_alpha, uv_top_left, uv_bottom_right,
133 background_color, vertex_opacity, y_flipped,
134 nearest_neighbor, /*secure_output_only=*/false,
135 gfx::ProtectedVideoType::kClear);
136 j += quad_height;
137 }
138 j = y_top;
139 i += quad_width;
140 }
141 }
142
143 // All SharedQuadState are overlapping the same region.
144 // +--------+
145 // | s1/2/3 |
146 // +--------+
IterateOverlapShareQuadStates(const std::string & story,int shared_quad_state_count,int quad_count)147 void IterateOverlapShareQuadStates(const std::string& story,
148 int shared_quad_state_count,
149 int quad_count) {
150 frame_.render_pass_list.push_back(std::make_unique<AggregatedRenderPass>());
151 CreateOverlapShareQuadStates(shared_quad_state_count, quad_count);
152 std::unique_ptr<Display> display = CreateDisplay();
153
154 timer_.Reset();
155 do {
156 display->RemoveOverdrawQuads(&frame_);
157 timer_.NextLap();
158 } while (!timer_.HasTimeLimitExpired());
159
160 auto reporter = SetUpRemoveOverdrawQuadReporter(story);
161 reporter.AddResult(kMetricOverlapThroughputRunsPerS,
162 timer_.LapsPerSecond());
163 frame_ = AggregatedFrame{};
164 }
165
CreateOverlapShareQuadStates(int shared_quad_state_count,int quad_count)166 void CreateOverlapShareQuadStates(int shared_quad_state_count,
167 int quad_count) {
168 int quad_height = kHeight / quad_count;
169 int quad_width = kWidth / quad_count;
170 int total_shared_quad_state =
171 shared_quad_state_count * shared_quad_state_count;
172 for (int i = 0; i < total_shared_quad_state; i++) {
173 gfx::Rect rect(0, 0, kHeight, kWidth);
174 SharedQuadState* new_shared_state(
175 CreateSharedQuadState(frame_.render_pass_list.front().get(), rect));
176 AppendQuads(new_shared_state, quad_height, quad_width);
177 }
178 }
179
180 // SharedQuadState are non-overlapped as shown in the figure below.
181 // +---+
182 // |s1 |
183 // +---+---+
184 // |s2 |
185 // +---+---+
186 // |s3 |
187 // +---+
IterateIsolatedSharedQuadStates(const std::string & story,int shared_quad_state_count,int quad_count)188 void IterateIsolatedSharedQuadStates(const std::string& story,
189 int shared_quad_state_count,
190 int quad_count) {
191 frame_.render_pass_list.push_back(std::make_unique<AggregatedRenderPass>());
192 CreateIsolatedSharedQuadStates(shared_quad_state_count, quad_count);
193 std::unique_ptr<Display> display = CreateDisplay();
194 timer_.Reset();
195 do {
196 display->RemoveOverdrawQuads(&frame_);
197 timer_.NextLap();
198 } while (!timer_.HasTimeLimitExpired());
199
200 auto reporter = SetUpRemoveOverdrawQuadReporter(story);
201 reporter.AddResult(kMetricIsolatedThroughputRunsPerS,
202 timer_.LapsPerSecond());
203 frame_ = AggregatedFrame{};
204 }
205
CreateIsolatedSharedQuadStates(int shared_quad_state_count,int quad_count)206 void CreateIsolatedSharedQuadStates(int shared_quad_state_count,
207 int quad_count) {
208 int shared_quad_state_height =
209 kHeight / (shared_quad_state_count * shared_quad_state_count);
210 int shared_quad_state_width =
211 kWidth / (shared_quad_state_count * shared_quad_state_count);
212 int quad_height = shared_quad_state_height / quad_count;
213 int quad_width = shared_quad_state_width / quad_count;
214 int i = 0;
215 int j = 0;
216 while (i + shared_quad_state_height <= kWidth ||
217 j + shared_quad_state_height <= kHeight) {
218 gfx::Rect rect(i, j, shared_quad_state_height, shared_quad_state_width);
219 SharedQuadState* new_shared_state(
220 CreateSharedQuadState(frame_.render_pass_list.front().get(), rect));
221 AppendQuads(new_shared_state, quad_height, quad_width);
222 j += shared_quad_state_height;
223 i += shared_quad_state_width;
224 }
225 }
226
227 // SharedQuadState are overlapped as shown in the figure below.
228 // +----+
229 // | +----+
230 // | | +----+
231 // +-| | +----+
232 // +--| | |
233 // +--| |
234 // +----+
IteratePartiallyOverlapSharedQuadStates(const std::string & story,int shared_quad_state_count,float percentage_overlap,int quad_count)235 void IteratePartiallyOverlapSharedQuadStates(const std::string& story,
236 int shared_quad_state_count,
237 float percentage_overlap,
238 int quad_count) {
239 frame_.render_pass_list.push_back(std::make_unique<AggregatedRenderPass>());
240 CreatePartiallyOverlapSharedQuadStates(shared_quad_state_count,
241 percentage_overlap, quad_count);
242 std::unique_ptr<Display> display = CreateDisplay();
243 timer_.Reset();
244 do {
245 display->RemoveOverdrawQuads(&frame_);
246 timer_.NextLap();
247 } while (!timer_.HasTimeLimitExpired());
248
249 auto reporter = SetUpRemoveOverdrawQuadReporter(story);
250 reporter.AddResult(kMetricPartialOverlapThroughputRunsPerS,
251 timer_.LapsPerSecond());
252 frame_ = AggregatedFrame{};
253 }
254
CreatePartiallyOverlapSharedQuadStates(int shared_quad_state_count,float percentage_overlap,int quad_count)255 void CreatePartiallyOverlapSharedQuadStates(int shared_quad_state_count,
256 float percentage_overlap,
257 int quad_count) {
258 int shared_quad_state_height =
259 kHeight / (shared_quad_state_count * shared_quad_state_count);
260 int shared_quad_state_width =
261 kWidth / (shared_quad_state_count * shared_quad_state_count);
262 int quad_height = shared_quad_state_height / quad_count;
263 int quad_width = shared_quad_state_width / quad_count;
264 int i = 0;
265 int j = 0;
266 for (int count = 0; count < shared_quad_state_count; count++) {
267 gfx::Rect rect(i, j, shared_quad_state_height, shared_quad_state_width);
268 SharedQuadState* new_shared_state(
269 CreateSharedQuadState(frame_.render_pass_list.front().get(), rect));
270 AppendQuads(new_shared_state, quad_height, quad_width);
271 i += shared_quad_state_width * percentage_overlap;
272 j += shared_quad_state_height * percentage_overlap;
273 }
274 }
275
276 // SharedQuadState are all adjacent to each other and added as the order shown
277 // in the figure below.
278 // +----+----+
279 // | s1 | s3 |
280 // +----+----+
281 // | s2 | s4 |
282 // +----+----+
IterateAdjacentSharedQuadStates(const std::string & story,int shared_quad_state_count,int quad_count)283 void IterateAdjacentSharedQuadStates(const std::string& story,
284 int shared_quad_state_count,
285 int quad_count) {
286 frame_.render_pass_list.push_back(std::make_unique<AggregatedRenderPass>());
287 CreateAdjacentSharedQuadStates(shared_quad_state_count, quad_count);
288 std::unique_ptr<Display> display = CreateDisplay();
289
290 timer_.Reset();
291 do {
292 display->RemoveOverdrawQuads(&frame_);
293 timer_.NextLap();
294 } while (!timer_.HasTimeLimitExpired());
295
296 auto reporter = SetUpRemoveOverdrawQuadReporter(story);
297 reporter.AddResult(kMetricAdjacentThroughputRunsPerS,
298 timer_.LapsPerSecond());
299 frame_ = AggregatedFrame{};
300 }
301
CreateAdjacentSharedQuadStates(int shared_quad_state_count,int quad_count)302 void CreateAdjacentSharedQuadStates(int shared_quad_state_count,
303 int quad_count) {
304 int shared_quad_state_height = kHeight / shared_quad_state_count;
305 int shared_quad_state_width = kWidth / shared_quad_state_count;
306 int quad_height = shared_quad_state_height / quad_count;
307 int quad_width = shared_quad_state_width / quad_count;
308 int i = 0;
309 int j = 0;
310 while (i + shared_quad_state_height <= kWidth) {
311 while (j + shared_quad_state_width <= kHeight) {
312 gfx::Rect rect(i, j, shared_quad_state_height, shared_quad_state_width);
313 SharedQuadState* new_shared_state =
314 CreateSharedQuadState(frame_.render_pass_list.front().get(), rect);
315 AppendQuads(new_shared_state, quad_height, quad_width);
316 j += shared_quad_state_height;
317 }
318 j = 0;
319 i += shared_quad_state_width;
320 }
321 }
322
323 private:
324 DebugRendererSettings debug_settings_;
325 AggregatedFrame frame_;
326 base::LapTimer timer_;
327 StubBeginFrameSource begin_frame_source_;
328 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
329 ServerSharedBitmapManager bitmap_manager_;
330 };
331
TEST_F(RemoveOverdrawQuadPerfTest,IterateOverlapShareQuadStates)332 TEST_F(RemoveOverdrawQuadPerfTest, IterateOverlapShareQuadStates) {
333 IterateOverlapShareQuadStates("4_sqs_with_4_quads", 2, 2);
334 IterateOverlapShareQuadStates("4_sqs_with_100_quads", 2, 10);
335 IterateOverlapShareQuadStates("100_sqs_with_4_quads", 10, 2);
336 IterateOverlapShareQuadStates("100_sqs_with_100_quads", 10, 10);
337 }
338
TEST_F(RemoveOverdrawQuadPerfTest,IterateIsolatedSharedQuadStates)339 TEST_F(RemoveOverdrawQuadPerfTest, IterateIsolatedSharedQuadStates) {
340 IterateIsolatedSharedQuadStates("2_sqs_with_4_quads", 2, 2);
341 IterateIsolatedSharedQuadStates("2_sqs_with_100_quads", 2, 10);
342 IterateIsolatedSharedQuadStates("10_sqs_with_4_quads", 10, 2);
343 IterateIsolatedSharedQuadStates("10_sqs_with_100_quads", 10, 10);
344 }
345
TEST_F(RemoveOverdrawQuadPerfTest,IteratePartiallyOverlapSharedQuadStates)346 TEST_F(RemoveOverdrawQuadPerfTest, IteratePartiallyOverlapSharedQuadStates) {
347 IteratePartiallyOverlapSharedQuadStates("2_sqs_with_4_quads", 2, 0.5, 2);
348 IteratePartiallyOverlapSharedQuadStates("2_sqs_with_100_quads", 2, 0.5, 10);
349 IteratePartiallyOverlapSharedQuadStates("10_sqs_with_4_quads", 10, 0.5, 2);
350 IteratePartiallyOverlapSharedQuadStates("10_sqs_with_100_quads", 10, 0.5, 10);
351 }
352
TEST_F(RemoveOverdrawQuadPerfTest,IterateAdjacentSharedQuadStates)353 TEST_F(RemoveOverdrawQuadPerfTest, IterateAdjacentSharedQuadStates) {
354 IterateAdjacentSharedQuadStates("4_sqs_with_4_quads", 2, 2);
355 IterateAdjacentSharedQuadStates("4_sqs_with_100_quads", 2, 10);
356 IterateAdjacentSharedQuadStates("100_sqs_with_4_quads", 10, 2);
357 IterateAdjacentSharedQuadStates("100_sqs_with_100_quads", 10, 10);
358 }
359
360 } // namespace
361 } // namespace viz
362