GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / cc / output / software_renderer_unittest.cc
blob3b2c4bc231762be757400372fc1b445ecebb1305
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.
5 #include "cc/output/software_renderer.h"
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"
27 namespace cc {
28 namespace {
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_));
38 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
39 resource_provider_ = ResourceProvider::Create(output_surface_.get(),
40 shared_bitmap_manager_.get(),
41 NULL,
42 NULL,
44 false,
45 1);
46 renderer_ = SoftwareRenderer::Create(
47 this, &settings_, output_surface_.get(), resource_provider());
50 ResourceProvider* resource_provider() const {
51 return resource_provider_.get();
54 SoftwareRenderer* renderer() const { return renderer_.get(); }
56 // RendererClient implementation.
57 void SetFullRootLayerDamage() override {}
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;
65 list->back()->copy_requests.push_back(
66 CopyOutputRequest::CreateBitmapRequest(
67 base::Bind(&SoftwareRendererTest::SaveBitmapResult,
68 base::Unretained(&bitmap_result),
69 loop.QuitClosure())));
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();
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();
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_;
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));
104 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
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,
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);
130 RenderPassList list;
131 list.push_back(root_render_pass.Pass());
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);
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));
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));
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);
165 SkBitmap yellow_tile;
166 yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height());
167 yellow_tile.eraseColor(SK_ColorYELLOW);
169 SkBitmap cyan_tile;
170 cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height());
171 cyan_tile.eraseColor(SK_ColorCYAN);
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);
179 gfx::Rect root_rect = outer_rect;
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,
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);
218 RenderPassList list;
219 list.push_back(root_render_pass.Pass());
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);
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));
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));
243 ResourceProvider::ResourceId resource_cyan =
244 resource_provider()->CreateResource(
245 tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
246 RGBA_8888);
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);
256 resource_provider()->CopyToResource(
257 resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), tile_size);
259 gfx::Rect root_rect(tile_size);
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,
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;
288 RenderPassList list;
289 list.push_back(root_render_pass.Pass());
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);
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));
318 TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
319 float device_scale_factor = 1.f;
320 gfx::Rect device_viewport_rect(0, 0, 100, 100);
322 settings_.should_clear_root_render_pass = false;
323 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
325 RenderPassList list;
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);
333 renderer()->DecideRenderPassAllocationsForFrame(list);
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);
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));
345 list.clear();
347 // Draw a smaller magenta rect without filling the viewport in a separate
348 // frame.
349 gfx::Rect smaller_rect(20, 20, 60, 60);
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);
356 renderer()->DecideRenderPassAllocationsForFrame(list);
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);
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));
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));
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));
380 RenderPassList list;
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);
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);
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;
400 renderer()->DecideRenderPassAllocationsForFrame(list);
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);
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));
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));
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));
427 } // namespace
428 } // namespace cc