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