• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/test/layer_tree_pixel_test.h"
6 
7 #include "base/command_line.h"
8 #include "base/path_service.h"
9 #include "cc/base/switches.h"
10 #include "cc/layers/solid_color_layer.h"
11 #include "cc/layers/texture_layer.h"
12 #include "cc/output/copy_output_request.h"
13 #include "cc/output/copy_output_result.h"
14 #include "cc/resources/texture_mailbox.h"
15 #include "cc/test/paths.h"
16 #include "cc/test/pixel_comparator.h"
17 #include "cc/test/pixel_test_output_surface.h"
18 #include "cc/test/pixel_test_software_output_device.h"
19 #include "cc/test/pixel_test_utils.h"
20 #include "cc/trees/layer_tree_impl.h"
21 #include "ui/gl/gl_implementation.h"
22 #include "webkit/common/gpu/context_provider_in_process.h"
23 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
24 
25 namespace cc {
26 
LayerTreePixelTest()27 LayerTreePixelTest::LayerTreePixelTest()
28     : pixel_comparator_(new ExactPixelComparator(true)),
29       test_type_(GL_WITH_DEFAULT),
30       pending_texture_mailbox_callbacks_(0),
31       impl_side_painting_(true) {}
32 
~LayerTreePixelTest()33 LayerTreePixelTest::~LayerTreePixelTest() {}
34 
CreateOutputSurface(bool fallback)35 scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface(
36     bool fallback) {
37   gfx::Size surface_expansion_size(40, 60);
38   scoped_ptr<PixelTestOutputSurface> output_surface;
39 
40   switch (test_type_) {
41     case SOFTWARE_WITH_DEFAULT:
42     case SOFTWARE_WITH_BITMAP: {
43       scoped_ptr<PixelTestSoftwareOutputDevice> software_output_device(
44           new PixelTestSoftwareOutputDevice);
45       software_output_device->set_surface_expansion_size(
46           surface_expansion_size);
47       output_surface = make_scoped_ptr(
48           new PixelTestOutputSurface(
49               software_output_device.PassAs<SoftwareOutputDevice>()));
50       break;
51     }
52 
53     case GL_WITH_DEFAULT:
54     case GL_WITH_BITMAP: {
55       CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
56 
57       using webkit::gpu::ContextProviderInProcess;
58       output_surface = make_scoped_ptr(new PixelTestOutputSurface(
59           ContextProviderInProcess::CreateOffscreen()));
60       break;
61     }
62   }
63 
64   output_surface->set_surface_expansion_size(surface_expansion_size);
65   return output_surface.PassAs<OutputSurface>();
66 }
67 
OffscreenContextProvider()68 scoped_refptr<ContextProvider> LayerTreePixelTest::OffscreenContextProvider() {
69   scoped_refptr<webkit::gpu::ContextProviderInProcess> provider =
70       webkit::gpu::ContextProviderInProcess::CreateOffscreen();
71   CHECK(provider.get());
72   return provider;
73 }
74 
CommitCompleteOnThread(LayerTreeHostImpl * impl)75 void LayerTreePixelTest::CommitCompleteOnThread(LayerTreeHostImpl* impl) {
76   LayerTreeImpl* commit_tree =
77       impl->pending_tree() ? impl->pending_tree() : impl->active_tree();
78   if (commit_tree->source_frame_number() != 0)
79     return;
80 
81   gfx::Rect viewport = impl->DeviceViewport();
82   // The viewport has a 0,0 origin without external influence.
83   EXPECT_EQ(gfx::Point().ToString(), viewport.origin().ToString());
84   // Be that influence!
85   viewport += gfx::Vector2d(20, 10);
86   impl->SetExternalDrawConstraints(gfx::Transform(), viewport, viewport, true);
87   EXPECT_EQ(viewport.ToString(), impl->DeviceViewport().ToString());
88 }
89 
CreateCopyOutputRequest()90 scoped_ptr<CopyOutputRequest> LayerTreePixelTest::CreateCopyOutputRequest() {
91   return CopyOutputRequest::CreateBitmapRequest(
92       base::Bind(&LayerTreePixelTest::ReadbackResult, base::Unretained(this)));
93 }
94 
ReadbackResult(scoped_ptr<CopyOutputResult> result)95 void LayerTreePixelTest::ReadbackResult(scoped_ptr<CopyOutputResult> result) {
96   ASSERT_TRUE(result->HasBitmap());
97   result_bitmap_ = result->TakeBitmap().Pass();
98   EndTest();
99 }
100 
BeginTest()101 void LayerTreePixelTest::BeginTest() {
102   Layer* target = readback_target_ ? readback_target_
103                                    : layer_tree_host()->root_layer();
104   target->RequestCopyOfOutput(CreateCopyOutputRequest().Pass());
105   PostSetNeedsCommitToMainThread();
106 }
107 
AfterTest()108 void LayerTreePixelTest::AfterTest() {
109   base::FilePath test_data_dir;
110   EXPECT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir));
111   base::FilePath ref_file_path = test_data_dir.Append(ref_file_);
112 
113   CommandLine* cmd = CommandLine::ForCurrentProcess();
114   if (cmd->HasSwitch(switches::kCCRebaselinePixeltests))
115     EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true));
116 
117   EXPECT_TRUE(MatchesPNGFile(*result_bitmap_,
118                              ref_file_path,
119                              *pixel_comparator_));
120 }
121 
CreateSolidColorLayer(gfx::Rect rect,SkColor color)122 scoped_refptr<SolidColorLayer> LayerTreePixelTest::CreateSolidColorLayer(
123     gfx::Rect rect, SkColor color) {
124   scoped_refptr<SolidColorLayer> layer = SolidColorLayer::Create();
125   layer->SetIsDrawable(true);
126   layer->SetAnchorPoint(gfx::PointF());
127   layer->SetBounds(rect.size());
128   layer->SetPosition(rect.origin());
129   layer->SetBackgroundColor(color);
130   return layer;
131 }
132 
EndTest()133 void LayerTreePixelTest::EndTest() {
134   // Drop TextureMailboxes on the main thread so that they can be cleaned up and
135   // the pending callbacks will fire.
136   for (size_t i = 0; i < texture_layers_.size(); ++i) {
137     texture_layers_[i]->SetTextureMailbox(TextureMailbox(),
138                                           scoped_ptr<SingleReleaseCallback>());
139   }
140 
141   TryEndTest();
142 }
143 
TryEndTest()144 void LayerTreePixelTest::TryEndTest() {
145   if (!result_bitmap_)
146     return;
147   if (pending_texture_mailbox_callbacks_)
148     return;
149   LayerTreeTest::EndTest();
150 }
151 
152 scoped_refptr<SolidColorLayer> LayerTreePixelTest::
CreateSolidColorLayerWithBorder(gfx::Rect rect,SkColor color,int border_width,SkColor border_color)153     CreateSolidColorLayerWithBorder(
154         gfx::Rect rect, SkColor color, int border_width, SkColor border_color) {
155   scoped_refptr<SolidColorLayer> layer = CreateSolidColorLayer(rect, color);
156   scoped_refptr<SolidColorLayer> border_top = CreateSolidColorLayer(
157       gfx::Rect(0, 0, rect.width(), border_width), border_color);
158   scoped_refptr<SolidColorLayer> border_left = CreateSolidColorLayer(
159       gfx::Rect(0,
160                 border_width,
161                 border_width,
162                 rect.height() - border_width * 2),
163       border_color);
164   scoped_refptr<SolidColorLayer> border_right =
165       CreateSolidColorLayer(gfx::Rect(rect.width() - border_width,
166                                       border_width,
167                                       border_width,
168                                       rect.height() - border_width * 2),
169                             border_color);
170   scoped_refptr<SolidColorLayer> border_bottom = CreateSolidColorLayer(
171       gfx::Rect(0, rect.height() - border_width, rect.width(), border_width),
172       border_color);
173   layer->AddChild(border_top);
174   layer->AddChild(border_left);
175   layer->AddChild(border_right);
176   layer->AddChild(border_bottom);
177   return layer;
178 }
179 
CreateTextureLayer(gfx::Rect rect,const SkBitmap & bitmap)180 scoped_refptr<TextureLayer> LayerTreePixelTest::CreateTextureLayer(
181     gfx::Rect rect, const SkBitmap& bitmap) {
182   scoped_refptr<TextureLayer> layer = TextureLayer::CreateForMailbox(NULL);
183   layer->SetIsDrawable(true);
184   layer->SetAnchorPoint(gfx::PointF());
185   layer->SetBounds(rect.size());
186   layer->SetPosition(rect.origin());
187 
188   TextureMailbox texture_mailbox;
189   scoped_ptr<SingleReleaseCallback> release_callback;
190   CopyBitmapToTextureMailboxAsTexture(
191       bitmap, &texture_mailbox, &release_callback);
192   layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
193 
194   texture_layers_.push_back(layer);
195   pending_texture_mailbox_callbacks_++;
196   return layer;
197 }
198 
RunPixelTest(PixelTestType test_type,scoped_refptr<Layer> content_root,base::FilePath file_name)199 void LayerTreePixelTest::RunPixelTest(
200     PixelTestType test_type,
201     scoped_refptr<Layer> content_root,
202     base::FilePath file_name) {
203   test_type_ = test_type;
204   content_root_ = content_root;
205   readback_target_ = NULL;
206   ref_file_ = file_name;
207   RunTest(true, false, impl_side_painting_);
208 }
209 
RunPixelTestWithReadbackTarget(PixelTestType test_type,scoped_refptr<Layer> content_root,Layer * target,base::FilePath file_name)210 void LayerTreePixelTest::RunPixelTestWithReadbackTarget(
211     PixelTestType test_type,
212     scoped_refptr<Layer> content_root,
213     Layer* target,
214     base::FilePath file_name) {
215   test_type_ = test_type;
216   content_root_ = content_root;
217   readback_target_ = target;
218   ref_file_ = file_name;
219   RunTest(true, false, impl_side_painting_);
220 }
221 
SetupTree()222 void LayerTreePixelTest::SetupTree() {
223   scoped_refptr<Layer> root = Layer::Create();
224   root->SetBounds(content_root_->bounds());
225   root->AddChild(content_root_);
226   layer_tree_host()->SetRootLayer(root);
227   LayerTreeTest::SetupTree();
228 }
229 
CopyTextureMailboxToBitmap(gfx::Size size,const TextureMailbox & texture_mailbox)230 scoped_ptr<SkBitmap> LayerTreePixelTest::CopyTextureMailboxToBitmap(
231     gfx::Size size,
232     const TextureMailbox& texture_mailbox) {
233   DCHECK(texture_mailbox.IsTexture());
234   if (!texture_mailbox.IsTexture())
235     return scoped_ptr<SkBitmap>();
236 
237   using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
238   scoped_ptr<blink::WebGraphicsContext3D> context3d(
239       WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
240           blink::WebGraphicsContext3D::Attributes()));
241 
242   EXPECT_TRUE(context3d->makeContextCurrent());
243 
244   if (texture_mailbox.sync_point())
245     context3d->waitSyncPoint(texture_mailbox.sync_point());
246 
247   unsigned texture_id = context3d->createTexture();
248   context3d->bindTexture(GL_TEXTURE_2D, texture_id);
249   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
250   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
251   context3d->texParameteri(
252       GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
253   context3d->texParameteri(
254       GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
255   context3d->consumeTextureCHROMIUM(texture_mailbox.target(),
256                                     texture_mailbox.data());
257   context3d->bindTexture(GL_TEXTURE_2D, 0);
258 
259   unsigned fbo = context3d->createFramebuffer();
260   context3d->bindFramebuffer(GL_FRAMEBUFFER, fbo);
261   context3d->framebufferTexture2D(GL_FRAMEBUFFER,
262                                   GL_COLOR_ATTACHMENT0,
263                                   GL_TEXTURE_2D,
264                                   texture_id,
265                                   0);
266   EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
267             context3d->checkFramebufferStatus(GL_FRAMEBUFFER));
268 
269   scoped_ptr<uint8[]> pixels(new uint8[size.GetArea() * 4]);
270   context3d->readPixels(0,
271                         0,
272                         size.width(),
273                         size.height(),
274                         GL_RGBA,
275                         GL_UNSIGNED_BYTE,
276                         pixels.get());
277 
278   context3d->deleteFramebuffer(fbo);
279   context3d->deleteTexture(texture_id);
280 
281   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
282   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
283                     size.width(),
284                     size.height());
285   bitmap->allocPixels();
286 
287   scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
288   uint8* out_pixels = static_cast<uint8*>(bitmap->getPixels());
289 
290   size_t row_bytes = size.width() * 4;
291   size_t total_bytes = size.height() * row_bytes;
292   for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
293     // Flip Y axis.
294     size_t src_y = total_bytes - dest_y - row_bytes;
295     // Swizzle OpenGL -> Skia byte order.
296     for (size_t x = 0; x < row_bytes; x += 4) {
297       out_pixels[dest_y + x + SK_R32_SHIFT/8] = pixels.get()[src_y + x + 0];
298       out_pixels[dest_y + x + SK_G32_SHIFT/8] = pixels.get()[src_y + x + 1];
299       out_pixels[dest_y + x + SK_B32_SHIFT/8] = pixels.get()[src_y + x + 2];
300       out_pixels[dest_y + x + SK_A32_SHIFT/8] = pixels.get()[src_y + x + 3];
301     }
302   }
303 
304   return bitmap.Pass();
305 }
306 
ReleaseTextureMailbox(scoped_ptr<blink::WebGraphicsContext3D> context3d,uint32 texture,uint32 sync_point,bool lost_resource)307 void LayerTreePixelTest::ReleaseTextureMailbox(
308     scoped_ptr<blink::WebGraphicsContext3D> context3d,
309     uint32 texture,
310     uint32 sync_point,
311     bool lost_resource) {
312   if (sync_point)
313     context3d->waitSyncPoint(sync_point);
314   context3d->deleteTexture(texture);
315   pending_texture_mailbox_callbacks_--;
316   TryEndTest();
317 }
318 
CopyBitmapToTextureMailboxAsTexture(const SkBitmap & bitmap,TextureMailbox * texture_mailbox,scoped_ptr<SingleReleaseCallback> * release_callback)319 void LayerTreePixelTest::CopyBitmapToTextureMailboxAsTexture(
320     const SkBitmap& bitmap,
321     TextureMailbox* texture_mailbox,
322     scoped_ptr<SingleReleaseCallback>* release_callback) {
323   DCHECK_GT(bitmap.width(), 0);
324   DCHECK_GT(bitmap.height(), 0);
325 
326   CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
327 
328   using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
329   scoped_ptr<blink::WebGraphicsContext3D> context3d(
330       WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
331           blink::WebGraphicsContext3D::Attributes()));
332 
333   EXPECT_TRUE(context3d->makeContextCurrent());
334 
335   unsigned texture_id = context3d->createTexture();
336   context3d->bindTexture(GL_TEXTURE_2D, texture_id);
337   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
338   context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
339   context3d->texParameteri(
340       GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
341   context3d->texParameteri(
342       GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
343 
344   DCHECK_EQ(SkBitmap::kARGB_8888_Config, bitmap.getConfig());
345 
346   {
347     SkAutoLockPixels lock(bitmap);
348 
349     size_t row_bytes = bitmap.width() * 4;
350     size_t total_bytes = bitmap.height() * row_bytes;
351 
352     scoped_ptr<uint8[]> gl_pixels(new uint8[total_bytes]);
353     uint8* bitmap_pixels = static_cast<uint8*>(bitmap.getPixels());
354 
355     for (size_t y = 0; y < total_bytes; y += row_bytes) {
356       // Flip Y axis.
357       size_t src_y = total_bytes - y - row_bytes;
358       // Swizzle Skia -> OpenGL byte order.
359       for (size_t x = 0; x < row_bytes; x += 4) {
360         gl_pixels.get()[y + x + 0] = bitmap_pixels[src_y + x + SK_R32_SHIFT/8];
361         gl_pixels.get()[y + x + 1] = bitmap_pixels[src_y + x + SK_G32_SHIFT/8];
362         gl_pixels.get()[y + x + 2] = bitmap_pixels[src_y + x + SK_B32_SHIFT/8];
363         gl_pixels.get()[y + x + 3] = bitmap_pixels[src_y + x + SK_A32_SHIFT/8];
364       }
365     }
366 
367     context3d->texImage2D(GL_TEXTURE_2D,
368                           0,
369                           GL_RGBA,
370                           bitmap.width(),
371                           bitmap.height(),
372                           0,
373                           GL_RGBA,
374                           GL_UNSIGNED_BYTE,
375                           gl_pixels.get());
376   }
377 
378   gpu::Mailbox mailbox;
379   context3d->genMailboxCHROMIUM(mailbox.name);
380   context3d->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
381   context3d->bindTexture(GL_TEXTURE_2D, 0);
382   uint32 sync_point = context3d->insertSyncPoint();
383 
384   *texture_mailbox = TextureMailbox(mailbox, sync_point);
385   *release_callback = SingleReleaseCallback::Create(
386       base::Bind(&LayerTreePixelTest::ReleaseTextureMailbox,
387                  base::Unretained(this),
388                  base::Passed(&context3d),
389                  texture_id));
390 }
391 
392 }  // namespace cc
393