OLD | NEW |
| (Empty) |
1 // Copyright 2012 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 "cc/output/software_renderer.h" | |
6 | |
7 #include "base/run_loop.h" | |
8 #include "cc/output/compositor_frame_metadata.h" | |
9 #include "cc/output/copy_output_request.h" | |
10 #include "cc/output/copy_output_result.h" | |
11 #include "cc/output/software_output_device.h" | |
12 #include "cc/quads/render_pass.h" | |
13 #include "cc/quads/render_pass_draw_quad.h" | |
14 #include "cc/quads/solid_color_draw_quad.h" | |
15 #include "cc/quads/tile_draw_quad.h" | |
16 #include "cc/test/animation_test_common.h" | |
17 #include "cc/test/fake_output_surface.h" | |
18 #include "cc/test/fake_output_surface_client.h" | |
19 #include "cc/test/geometry_test_utils.h" | |
20 #include "cc/test/render_pass_test_common.h" | |
21 #include "cc/test/render_pass_test_utils.h" | |
22 #include "cc/test/test_shared_bitmap_manager.h" | |
23 #include "testing/gmock/include/gmock/gmock.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 #include "third_party/skia/include/core/SkCanvas.h" | |
26 | |
27 namespace cc { | |
28 namespace { | |
29 | |
30 class SoftwareRendererTest : public testing::Test, public RendererClient { | |
31 public: | |
32 void InitializeRenderer( | |
33 scoped_ptr<SoftwareOutputDevice> software_output_device) { | |
34 output_surface_ = FakeOutputSurface::CreateSoftware( | |
35 software_output_device.Pass()); | |
36 CHECK(output_surface_->BindToClient(&output_surface_client_)); | |
37 | |
38 shared_bitmap_manager_.reset(new TestSharedBitmapManager()); | |
39 resource_provider_ = ResourceProvider::Create(output_surface_.get(), | |
40 shared_bitmap_manager_.get(), | |
41 NULL, | |
42 NULL, | |
43 0, | |
44 false, | |
45 1); | |
46 renderer_ = SoftwareRenderer::Create( | |
47 this, &settings_, output_surface_.get(), resource_provider()); | |
48 } | |
49 | |
50 ResourceProvider* resource_provider() const { | |
51 return resource_provider_.get(); | |
52 } | |
53 | |
54 SoftwareRenderer* renderer() const { return renderer_.get(); } | |
55 | |
56 // RendererClient implementation. | |
57 void SetFullRootLayerDamage() override {} | |
58 | |
59 scoped_ptr<SkBitmap> DrawAndCopyOutput(RenderPassList* list, | |
60 float device_scale_factor, | |
61 gfx::Rect device_viewport_rect) { | |
62 scoped_ptr<SkBitmap> bitmap_result; | |
63 base::RunLoop loop; | |
64 | |
65 list->back()->copy_requests.push_back( | |
66 CopyOutputRequest::CreateBitmapRequest( | |
67 base::Bind(&SoftwareRendererTest::SaveBitmapResult, | |
68 base::Unretained(&bitmap_result), | |
69 loop.QuitClosure()))); | |
70 | |
71 renderer()->DrawFrame(list, | |
72 device_scale_factor, | |
73 device_viewport_rect, | |
74 device_viewport_rect, | |
75 false); | |
76 loop.Run(); | |
77 return bitmap_result.Pass(); | |
78 } | |
79 | |
80 static void SaveBitmapResult(scoped_ptr<SkBitmap>* bitmap_result, | |
81 const base::Closure& quit_closure, | |
82 scoped_ptr<CopyOutputResult> result) { | |
83 DCHECK(result->HasBitmap()); | |
84 *bitmap_result = result->TakeBitmap(); | |
85 quit_closure.Run(); | |
86 } | |
87 | |
88 protected: | |
89 RendererSettings settings_; | |
90 FakeOutputSurfaceClient output_surface_client_; | |
91 scoped_ptr<FakeOutputSurface> output_surface_; | |
92 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; | |
93 scoped_ptr<ResourceProvider> resource_provider_; | |
94 scoped_ptr<SoftwareRenderer> renderer_; | |
95 }; | |
96 | |
97 TEST_F(SoftwareRendererTest, SolidColorQuad) { | |
98 gfx::Size outer_size(100, 100); | |
99 gfx::Size inner_size(98, 98); | |
100 gfx::Rect outer_rect(outer_size); | |
101 gfx::Rect inner_rect(gfx::Point(1, 1), inner_size); | |
102 gfx::Rect visible_rect(gfx::Point(1, 2), gfx::Size(98, 97)); | |
103 | |
104 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); | |
105 | |
106 RenderPassId root_render_pass_id = RenderPassId(1, 1); | |
107 scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); | |
108 root_render_pass->SetNew( | |
109 root_render_pass_id, outer_rect, outer_rect, gfx::Transform()); | |
110 SharedQuadState* shared_quad_state = | |
111 root_render_pass->CreateAndAppendSharedQuadState(); | |
112 shared_quad_state->SetAll(gfx::Transform(), | |
113 outer_size, | |
114 outer_rect, | |
115 outer_rect, | |
116 false, | |
117 1.0, | |
118 SkXfermode::kSrcOver_Mode, | |
119 0); | |
120 SolidColorDrawQuad* inner_quad = | |
121 root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); | |
122 inner_quad->SetNew( | |
123 shared_quad_state, inner_rect, inner_rect, SK_ColorCYAN, false); | |
124 inner_quad->visible_rect = visible_rect; | |
125 SolidColorDrawQuad* outer_quad = | |
126 root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); | |
127 outer_quad->SetNew( | |
128 shared_quad_state, outer_rect, outer_rect, SK_ColorYELLOW, false); | |
129 | |
130 RenderPassList list; | |
131 list.push_back(root_render_pass.Pass()); | |
132 | |
133 float device_scale_factor = 1.f; | |
134 gfx::Rect device_viewport_rect(outer_size); | |
135 scoped_ptr<SkBitmap> output = | |
136 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); | |
137 EXPECT_EQ(outer_rect.width(), output->info().fWidth); | |
138 EXPECT_EQ(outer_rect.height(), output->info().fHeight); | |
139 | |
140 EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0)); | |
141 EXPECT_EQ(SK_ColorYELLOW, | |
142 output->getColor(outer_size.width() - 1, outer_size.height() - 1)); | |
143 EXPECT_EQ(SK_ColorYELLOW, output->getColor(1, 1)); | |
144 EXPECT_EQ(SK_ColorCYAN, output->getColor(1, 2)); | |
145 EXPECT_EQ(SK_ColorCYAN, | |
146 output->getColor(inner_size.width() - 1, inner_size.height() - 1)); | |
147 } | |
148 | |
149 TEST_F(SoftwareRendererTest, TileQuad) { | |
150 gfx::Size outer_size(100, 100); | |
151 gfx::Size inner_size(98, 98); | |
152 gfx::Rect outer_rect(outer_size); | |
153 gfx::Rect inner_rect(gfx::Point(1, 1), inner_size); | |
154 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); | |
155 | |
156 ResourceProvider::ResourceId resource_yellow = | |
157 resource_provider()->CreateResource( | |
158 outer_size, GL_CLAMP_TO_EDGE, | |
159 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888); | |
160 ResourceProvider::ResourceId resource_cyan = | |
161 resource_provider()->CreateResource( | |
162 inner_size, GL_CLAMP_TO_EDGE, | |
163 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888); | |
164 | |
165 SkBitmap yellow_tile; | |
166 yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height()); | |
167 yellow_tile.eraseColor(SK_ColorYELLOW); | |
168 | |
169 SkBitmap cyan_tile; | |
170 cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height()); | |
171 cyan_tile.eraseColor(SK_ColorCYAN); | |
172 | |
173 resource_provider()->CopyToResource( | |
174 resource_yellow, static_cast<uint8_t*>(yellow_tile.getPixels()), | |
175 outer_size); | |
176 resource_provider()->CopyToResource( | |
177 resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), inner_size); | |
178 | |
179 gfx::Rect root_rect = outer_rect; | |
180 | |
181 RenderPassId root_render_pass_id = RenderPassId(1, 1); | |
182 scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); | |
183 root_render_pass->SetNew( | |
184 root_render_pass_id, root_rect, root_rect, gfx::Transform()); | |
185 SharedQuadState* shared_quad_state = | |
186 root_render_pass->CreateAndAppendSharedQuadState(); | |
187 shared_quad_state->SetAll(gfx::Transform(), | |
188 outer_size, | |
189 outer_rect, | |
190 outer_rect, | |
191 false, | |
192 1.0, | |
193 SkXfermode::kSrcOver_Mode, | |
194 0); | |
195 TileDrawQuad* inner_quad = | |
196 root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); | |
197 inner_quad->SetNew(shared_quad_state, | |
198 inner_rect, | |
199 inner_rect, | |
200 inner_rect, | |
201 resource_cyan, | |
202 gfx::RectF(inner_size), | |
203 inner_size, | |
204 false, | |
205 false); | |
206 TileDrawQuad* outer_quad = | |
207 root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); | |
208 outer_quad->SetNew(shared_quad_state, | |
209 outer_rect, | |
210 outer_rect, | |
211 outer_rect, | |
212 resource_yellow, | |
213 gfx::RectF(outer_size), | |
214 outer_size, | |
215 false, | |
216 false); | |
217 | |
218 RenderPassList list; | |
219 list.push_back(root_render_pass.Pass()); | |
220 | |
221 float device_scale_factor = 1.f; | |
222 gfx::Rect device_viewport_rect(outer_size); | |
223 scoped_ptr<SkBitmap> output = | |
224 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); | |
225 EXPECT_EQ(outer_rect.width(), output->info().fWidth); | |
226 EXPECT_EQ(outer_rect.height(), output->info().fHeight); | |
227 | |
228 EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0)); | |
229 EXPECT_EQ(SK_ColorYELLOW, | |
230 output->getColor(outer_size.width() - 1, outer_size.height() - 1)); | |
231 EXPECT_EQ(SK_ColorCYAN, output->getColor(1, 1)); | |
232 EXPECT_EQ(SK_ColorCYAN, | |
233 output->getColor(inner_size.width() - 1, inner_size.height() - 1)); | |
234 } | |
235 | |
236 TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { | |
237 gfx::Size tile_size(100, 100); | |
238 gfx::Rect tile_rect(tile_size); | |
239 gfx::Rect visible_rect = tile_rect; | |
240 visible_rect.Inset(1, 2, 3, 4); | |
241 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); | |
242 | |
243 ResourceProvider::ResourceId resource_cyan = | |
244 resource_provider()->CreateResource( | |
245 tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, | |
246 RGBA_8888); | |
247 | |
248 SkBitmap cyan_tile; // The lowest five rows are yellow. | |
249 cyan_tile.allocN32Pixels(tile_size.width(), tile_size.height()); | |
250 cyan_tile.eraseColor(SK_ColorCYAN); | |
251 cyan_tile.eraseArea( | |
252 SkIRect::MakeLTRB( | |
253 0, visible_rect.bottom() - 1, tile_rect.width(), tile_rect.bottom()), | |
254 SK_ColorYELLOW); | |
255 | |
256 resource_provider()->CopyToResource( | |
257 resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), tile_size); | |
258 | |
259 gfx::Rect root_rect(tile_size); | |
260 | |
261 RenderPassId root_render_pass_id = RenderPassId(1, 1); | |
262 scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); | |
263 root_render_pass->SetNew( | |
264 root_render_pass_id, root_rect, root_rect, gfx::Transform()); | |
265 SharedQuadState* shared_quad_state = | |
266 root_render_pass->CreateAndAppendSharedQuadState(); | |
267 shared_quad_state->SetAll(gfx::Transform(), | |
268 tile_size, | |
269 tile_rect, | |
270 tile_rect, | |
271 false, | |
272 1.0, | |
273 SkXfermode::kSrcOver_Mode, | |
274 0); | |
275 TileDrawQuad* quad = | |
276 root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); | |
277 quad->SetNew(shared_quad_state, | |
278 tile_rect, | |
279 tile_rect, | |
280 tile_rect, | |
281 resource_cyan, | |
282 gfx::RectF(tile_size), | |
283 tile_size, | |
284 false, | |
285 false); | |
286 quad->visible_rect = visible_rect; | |
287 | |
288 RenderPassList list; | |
289 list.push_back(root_render_pass.Pass()); | |
290 | |
291 float device_scale_factor = 1.f; | |
292 gfx::Rect device_viewport_rect(tile_size); | |
293 scoped_ptr<SkBitmap> output = | |
294 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); | |
295 EXPECT_EQ(tile_rect.width(), output->info().fWidth); | |
296 EXPECT_EQ(tile_rect.height(), output->info().fHeight); | |
297 | |
298 // Check portion of tile not in visible rect isn't drawn. | |
299 const unsigned int kTransparent = SK_ColorTRANSPARENT; | |
300 EXPECT_EQ(kTransparent, output->getColor(0, 0)); | |
301 EXPECT_EQ(kTransparent, | |
302 output->getColor(tile_rect.width() - 1, tile_rect.height() - 1)); | |
303 EXPECT_EQ(kTransparent, | |
304 output->getColor(visible_rect.x() - 1, visible_rect.y() - 1)); | |
305 EXPECT_EQ(kTransparent, | |
306 output->getColor(visible_rect.right(), visible_rect.bottom())); | |
307 // Ensure visible part is drawn correctly. | |
308 EXPECT_EQ(SK_ColorCYAN, output->getColor(visible_rect.x(), visible_rect.y())); | |
309 EXPECT_EQ( | |
310 SK_ColorCYAN, | |
311 output->getColor(visible_rect.right() - 2, visible_rect.bottom() - 2)); | |
312 // Ensure last visible line is correct. | |
313 EXPECT_EQ( | |
314 SK_ColorYELLOW, | |
315 output->getColor(visible_rect.right() - 1, visible_rect.bottom() - 1)); | |
316 } | |
317 | |
318 TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { | |
319 float device_scale_factor = 1.f; | |
320 gfx::Rect device_viewport_rect(0, 0, 100, 100); | |
321 | |
322 settings_.should_clear_root_render_pass = false; | |
323 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); | |
324 | |
325 RenderPassList list; | |
326 | |
327 // Draw a fullscreen green quad in a first frame. | |
328 RenderPassId root_clear_pass_id(1, 0); | |
329 TestRenderPass* root_clear_pass = AddRenderPass( | |
330 &list, root_clear_pass_id, device_viewport_rect, gfx::Transform()); | |
331 AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN); | |
332 | |
333 renderer()->DecideRenderPassAllocationsForFrame(list); | |
334 | |
335 scoped_ptr<SkBitmap> output = | |
336 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); | |
337 EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth); | |
338 EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight); | |
339 | |
340 EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0)); | |
341 EXPECT_EQ(SK_ColorGREEN, | |
342 output->getColor(device_viewport_rect.width() - 1, | |
343 device_viewport_rect.height() - 1)); | |
344 | |
345 list.clear(); | |
346 | |
347 // Draw a smaller magenta rect without filling the viewport in a separate | |
348 // frame. | |
349 gfx::Rect smaller_rect(20, 20, 60, 60); | |
350 | |
351 RenderPassId root_smaller_pass_id(2, 0); | |
352 TestRenderPass* root_smaller_pass = AddRenderPass( | |
353 &list, root_smaller_pass_id, device_viewport_rect, gfx::Transform()); | |
354 AddQuad(root_smaller_pass, smaller_rect, SK_ColorMAGENTA); | |
355 | |
356 renderer()->DecideRenderPassAllocationsForFrame(list); | |
357 | |
358 output = DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); | |
359 EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth); | |
360 EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight); | |
361 | |
362 // If we didn't clear, the borders should still be green. | |
363 EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0)); | |
364 EXPECT_EQ(SK_ColorGREEN, | |
365 output->getColor(device_viewport_rect.width() - 1, | |
366 device_viewport_rect.height() - 1)); | |
367 | |
368 EXPECT_EQ(SK_ColorMAGENTA, | |
369 output->getColor(smaller_rect.x(), smaller_rect.y())); | |
370 EXPECT_EQ( | |
371 SK_ColorMAGENTA, | |
372 output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1)); | |
373 } | |
374 | |
375 TEST_F(SoftwareRendererTest, RenderPassVisibleRect) { | |
376 float device_scale_factor = 1.f; | |
377 gfx::Rect device_viewport_rect(0, 0, 100, 100); | |
378 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); | |
379 | |
380 RenderPassList list; | |
381 | |
382 // Pass drawn as inner quad is magenta. | |
383 gfx::Rect smaller_rect(20, 20, 60, 60); | |
384 RenderPassId smaller_pass_id(2, 1); | |
385 TestRenderPass* smaller_pass = | |
386 AddRenderPass(&list, smaller_pass_id, smaller_rect, gfx::Transform()); | |
387 AddQuad(smaller_pass, smaller_rect, SK_ColorMAGENTA); | |
388 | |
389 // Root pass is green. | |
390 RenderPassId root_clear_pass_id(1, 0); | |
391 TestRenderPass* root_clear_pass = AddRenderPass( | |
392 &list, root_clear_pass_id, device_viewport_rect, gfx::Transform()); | |
393 AddRenderPassQuad(root_clear_pass, smaller_pass); | |
394 AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN); | |
395 | |
396 // Interior pass quad has smaller visible rect. | |
397 gfx::Rect interior_visible_rect(30, 30, 40, 40); | |
398 root_clear_pass->quad_list.front()->visible_rect = interior_visible_rect; | |
399 | |
400 renderer()->DecideRenderPassAllocationsForFrame(list); | |
401 | |
402 scoped_ptr<SkBitmap> output = | |
403 DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect); | |
404 EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth); | |
405 EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight); | |
406 | |
407 EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0)); | |
408 EXPECT_EQ(SK_ColorGREEN, | |
409 output->getColor(device_viewport_rect.width() - 1, | |
410 device_viewport_rect.height() - 1)); | |
411 | |
412 // Part outside visible rect should remain green. | |
413 EXPECT_EQ(SK_ColorGREEN, | |
414 output->getColor(smaller_rect.x(), smaller_rect.y())); | |
415 EXPECT_EQ( | |
416 SK_ColorGREEN, | |
417 output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1)); | |
418 | |
419 EXPECT_EQ( | |
420 SK_ColorMAGENTA, | |
421 output->getColor(interior_visible_rect.x(), interior_visible_rect.y())); | |
422 EXPECT_EQ(SK_ColorMAGENTA, | |
423 output->getColor(interior_visible_rect.right() - 1, | |
424 interior_visible_rect.bottom() - 1)); | |
425 } | |
426 | |
427 } // namespace | |
428 } // namespace cc | |
OLD | NEW |