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/gl_renderer.h"
6
7#include <set>
8
9#include "cc/base/math_util.h"
10#include "cc/output/compositor_frame_metadata.h"
11#include "cc/resources/prioritized_resource_manager.h"
12#include "cc/resources/resource_provider.h"
13#include "cc/test/fake_impl_proxy.h"
14#include "cc/test/fake_layer_tree_host_impl.h"
15#include "cc/test/fake_output_surface.h"
16#include "cc/test/fake_output_surface_client.h"
17#include "cc/test/mock_quad_culler.h"
18#include "cc/test/pixel_test.h"
19#include "cc/test/render_pass_test_common.h"
20#include "cc/test/render_pass_test_utils.h"
21#include "cc/test/test_web_graphics_context_3d.h"
22#include "gpu/GLES2/gl2extchromium.h"
23#include "gpu/command_buffer/client/context_support.h"
24#include "testing/gmock/include/gmock/gmock.h"
25#include "testing/gtest/include/gtest/gtest.h"
26#include "third_party/khronos/GLES2/gl2.h"
27#include "third_party/skia/include/core/SkImageFilter.h"
28#include "third_party/skia/include/core/SkMatrix.h"
29#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
30#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
31#include "ui/gfx/transform.h"
32
33using testing::_;
34using testing::AnyNumber;
35using testing::Args;
36using testing::AtLeast;
37using testing::ElementsAre;
38using testing::Expectation;
39using testing::InSequence;
40using testing::Mock;
41using testing::Return;
42using testing::StrictMock;
43using blink::WebGLId;
44using blink::WebString;
45using blink::WGC3Dbitfield;
46using blink::WGC3Dboolean;
47using blink::WGC3Dchar;
48using blink::WGC3Denum;
49using blink::WGC3Dfloat;
50using blink::WGC3Dint;
51using blink::WGC3Dintptr;
52using blink::WGC3Dsizei;
53using blink::WGC3Dsizeiptr;
54using blink::WGC3Duint;
55
56namespace cc {
57
58class GLRendererTest : public testing::Test {
59 protected:
60  RenderPass* root_render_pass() { return render_passes_in_draw_order_.back(); }
61
62  RenderPassList render_passes_in_draw_order_;
63};
64
65#define EXPECT_PROGRAM_VALID(program_binding)      \
66  do {                                             \
67    EXPECT_TRUE((program_binding)->program());     \
68    EXPECT_TRUE((program_binding)->initialized()); \
69  } while (false)
70
71// Explicitly named to be a friend in GLRenderer for shader access.
72class GLRendererShaderPixelTest : public GLRendererPixelTest {
73 public:
74  void TestShaders() {
75    ASSERT_FALSE(renderer()->IsContextLost());
76    EXPECT_PROGRAM_VALID(renderer()->GetTileCheckerboardProgram());
77    EXPECT_PROGRAM_VALID(renderer()->GetDebugBorderProgram());
78    EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgram());
79    EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgramAA());
80    TestShadersWithTexCoordPrecision(TexCoordPrecisionMedium);
81    TestShadersWithTexCoordPrecision(TexCoordPrecisionHigh);
82    ASSERT_FALSE(renderer()->IsContextLost());
83  }
84
85  void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) {
86    EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgram(precision));
87    EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgramAA(precision));
88    EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(precision));
89    EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(precision));
90    EXPECT_PROGRAM_VALID(
91        renderer()->GetRenderPassColorMatrixProgram(precision));
92    EXPECT_PROGRAM_VALID(
93        renderer()->GetRenderPassMaskColorMatrixProgramAA(precision));
94    EXPECT_PROGRAM_VALID(
95        renderer()->GetRenderPassColorMatrixProgramAA(precision));
96    EXPECT_PROGRAM_VALID(
97        renderer()->GetRenderPassMaskColorMatrixProgram(precision));
98    EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision));
99    EXPECT_PROGRAM_VALID(
100        renderer()->GetNonPremultipliedTextureProgram(precision));
101    EXPECT_PROGRAM_VALID(renderer()->GetTextureBackgroundProgram(precision));
102    EXPECT_PROGRAM_VALID(
103        renderer()->GetNonPremultipliedTextureBackgroundProgram(precision));
104    EXPECT_PROGRAM_VALID(renderer()->GetTextureIOSurfaceProgram(precision));
105    EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVProgram(precision));
106    EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVAProgram(precision));
107    // This is unlikely to be ever true in tests due to usage of osmesa.
108    if (renderer()->Capabilities().using_egl_image)
109      EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision));
110    else
111      EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision));
112    TestShadersWithSamplerType(precision, SamplerType2D);
113    TestShadersWithSamplerType(precision, SamplerType2DRect);
114    // This is unlikely to be ever true in tests due to usage of osmesa.
115    if (renderer()->Capabilities().using_egl_image)
116      TestShadersWithSamplerType(precision, SamplerTypeExternalOES);
117  }
118
119  void TestShadersWithSamplerType(TexCoordPrecision precision,
120                                  SamplerType sampler) {
121    EXPECT_PROGRAM_VALID(renderer()->GetTileProgram(precision, sampler));
122    EXPECT_PROGRAM_VALID(renderer()->GetTileProgramOpaque(precision, sampler));
123    EXPECT_PROGRAM_VALID(renderer()->GetTileProgramAA(precision, sampler));
124    EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzle(precision, sampler));
125    EXPECT_PROGRAM_VALID(
126        renderer()->GetTileProgramSwizzleOpaque(precision, sampler));
127    EXPECT_PROGRAM_VALID(
128        renderer()->GetTileProgramSwizzleAA(precision, sampler));
129  }
130};
131
132namespace {
133
134#if !defined(OS_ANDROID)
135TEST_F(GLRendererShaderPixelTest, AllShadersCompile) { TestShaders(); }
136#endif
137
138class FakeRendererClient : public RendererClient {
139 public:
140  FakeRendererClient() : set_full_root_layer_damage_count_(0) {}
141
142  // RendererClient methods.
143  virtual void SetFullRootLayerDamage() OVERRIDE {
144    set_full_root_layer_damage_count_++;
145  }
146
147  // Methods added for test.
148  int set_full_root_layer_damage_count() const {
149    return set_full_root_layer_damage_count_;
150  }
151
152 private:
153  int set_full_root_layer_damage_count_;
154};
155
156class FakeRendererGL : public GLRenderer {
157 public:
158  FakeRendererGL(RendererClient* client,
159                 const LayerTreeSettings* settings,
160                 OutputSurface* output_surface,
161                 ResourceProvider* resource_provider)
162      : GLRenderer(client,
163                   settings,
164                   output_surface,
165                   resource_provider,
166                   NULL,
167                   0) {}
168
169  // GLRenderer methods.
170
171  // Changing visibility to public.
172  using GLRenderer::IsBackbufferDiscarded;
173  using GLRenderer::DoDrawQuad;
174  using GLRenderer::BeginDrawingFrame;
175  using GLRenderer::FinishDrawingQuadList;
176  using GLRenderer::stencil_enabled;
177};
178
179class GLRendererWithDefaultHarnessTest : public GLRendererTest {
180 protected:
181  GLRendererWithDefaultHarnessTest() {
182    output_surface_ = FakeOutputSurface::Create3d(
183        TestWebGraphicsContext3D::Create()).Pass();
184    CHECK(output_surface_->BindToClient(&output_surface_client_));
185
186    resource_provider_ = ResourceProvider::Create(
187        output_surface_.get(), NULL, 0, false, 1).Pass();
188    renderer_ = make_scoped_ptr(new FakeRendererGL(&renderer_client_,
189                                                   &settings_,
190                                                   output_surface_.get(),
191                                                   resource_provider_.get()));
192  }
193
194  void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
195
196  LayerTreeSettings settings_;
197  FakeOutputSurfaceClient output_surface_client_;
198  scoped_ptr<FakeOutputSurface> output_surface_;
199  FakeRendererClient renderer_client_;
200  scoped_ptr<ResourceProvider> resource_provider_;
201  scoped_ptr<FakeRendererGL> renderer_;
202};
203
204// Closing the namespace here so that GLRendererShaderTest can take advantage
205// of the friend relationship with GLRenderer and all of the mock classes
206// declared above it.
207}  // namespace
208
209class GLRendererShaderTest : public GLRendererTest {
210 protected:
211  GLRendererShaderTest() {
212    output_surface_ = FakeOutputSurface::Create3d().Pass();
213    CHECK(output_surface_->BindToClient(&output_surface_client_));
214
215    resource_provider_ = ResourceProvider::Create(
216        output_surface_.get(), NULL, 0, false, 1).Pass();
217    renderer_.reset(new FakeRendererGL(&renderer_client_,
218                                       &settings_,
219                                       output_surface_.get(),
220                                       resource_provider_.get()));
221  }
222
223  void TestRenderPassProgram(TexCoordPrecision precision) {
224    EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_[precision]);
225    EXPECT_EQ(renderer_->render_pass_program_[precision].program(),
226              renderer_->program_shadow_);
227  }
228
229  void TestRenderPassColorMatrixProgram(TexCoordPrecision precision) {
230    EXPECT_PROGRAM_VALID(
231        &renderer_->render_pass_color_matrix_program_[precision]);
232    EXPECT_EQ(renderer_->render_pass_color_matrix_program_[precision].program(),
233              renderer_->program_shadow_);
234  }
235
236  void TestRenderPassMaskProgram(TexCoordPrecision precision) {
237    EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_[precision]);
238    EXPECT_EQ(renderer_->render_pass_mask_program_[precision].program(),
239              renderer_->program_shadow_);
240  }
241
242  void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
243    EXPECT_PROGRAM_VALID(
244        &renderer_->render_pass_mask_color_matrix_program_[precision]);
245    EXPECT_EQ(
246        renderer_->render_pass_mask_color_matrix_program_[precision].program(),
247        renderer_->program_shadow_);
248  }
249
250  void TestRenderPassProgramAA(TexCoordPrecision precision) {
251    EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_aa_[precision]);
252    EXPECT_EQ(renderer_->render_pass_program_aa_[precision].program(),
253              renderer_->program_shadow_);
254  }
255
256  void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
257    EXPECT_PROGRAM_VALID(
258        &renderer_->render_pass_color_matrix_program_aa_[precision]);
259    EXPECT_EQ(
260        renderer_->render_pass_color_matrix_program_aa_[precision].program(),
261        renderer_->program_shadow_);
262  }
263
264  void TestRenderPassMaskProgramAA(TexCoordPrecision precision) {
265    EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_aa_[precision]);
266    EXPECT_EQ(renderer_->render_pass_mask_program_aa_[precision].program(),
267              renderer_->program_shadow_);
268  }
269
270  void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
271    EXPECT_PROGRAM_VALID(
272        &renderer_->render_pass_mask_color_matrix_program_aa_[precision]);
273    EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_[precision]
274                  .program(),
275              renderer_->program_shadow_);
276  }
277
278  void TestSolidColorProgramAA() {
279    EXPECT_PROGRAM_VALID(&renderer_->solid_color_program_aa_);
280    EXPECT_EQ(renderer_->solid_color_program_aa_.program(),
281              renderer_->program_shadow_);
282  }
283
284  LayerTreeSettings settings_;
285  FakeOutputSurfaceClient output_surface_client_;
286  scoped_ptr<FakeOutputSurface> output_surface_;
287  FakeRendererClient renderer_client_;
288  scoped_ptr<ResourceProvider> resource_provider_;
289  scoped_ptr<FakeRendererGL> renderer_;
290};
291
292namespace {
293
294// Test GLRenderer DiscardBackbuffer functionality:
295// Suggest discarding framebuffer when one exists and the renderer is not
296// visible.
297// Expected: it is discarded and damage tracker is reset.
298TEST_F(
299    GLRendererWithDefaultHarnessTest,
300    SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerIfNotVisible) {
301  renderer_->SetVisible(false);
302  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
303  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
304}
305
306// Test GLRenderer DiscardBackbuffer functionality:
307// Suggest discarding framebuffer when one exists and the renderer is visible.
308// Expected: the allocation is ignored.
309TEST_F(GLRendererWithDefaultHarnessTest,
310       SuggestBackbufferNoDoNothingWhenVisible) {
311  renderer_->SetVisible(true);
312  EXPECT_EQ(0, renderer_client_.set_full_root_layer_damage_count());
313  EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
314}
315
316// Test GLRenderer DiscardBackbuffer functionality:
317// Suggest discarding framebuffer when one does not exist.
318// Expected: it does nothing.
319TEST_F(GLRendererWithDefaultHarnessTest,
320       SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) {
321  renderer_->SetVisible(false);
322  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
323  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
324
325  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
326  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
327}
328
329// Test GLRenderer DiscardBackbuffer functionality:
330// Begin drawing a frame while a framebuffer is discarded.
331// Expected: will recreate framebuffer.
332TEST_F(GLRendererWithDefaultHarnessTest,
333       DiscardedBackbufferIsRecreatedForScopeDuration) {
334  gfx::Rect viewport_rect(1, 1);
335  renderer_->SetVisible(false);
336  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
337  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
338
339  AddRenderPass(&render_passes_in_draw_order_,
340                RenderPass::Id(1, 0),
341                viewport_rect,
342                gfx::Transform());
343
344  renderer_->SetVisible(true);
345  renderer_->DrawFrame(&render_passes_in_draw_order_,
346                       NULL,
347                       1.f,
348                       viewport_rect,
349                       viewport_rect,
350                       true,
351                       false);
352  EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
353
354  SwapBuffers();
355  EXPECT_EQ(1u, output_surface_->num_sent_frames());
356}
357
358TEST_F(GLRendererWithDefaultHarnessTest,
359       FramebufferDiscardedAfterReadbackWhenNotVisible) {
360  gfx::Rect viewport_rect(1, 1);
361  renderer_->SetVisible(false);
362  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
363  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
364
365  AddRenderPass(&render_passes_in_draw_order_,
366                RenderPass::Id(1, 0),
367                viewport_rect,
368                gfx::Transform());
369
370  char pixels[4];
371  renderer_->DrawFrame(&render_passes_in_draw_order_,
372                       NULL,
373                       1.f,
374                       viewport_rect,
375                       viewport_rect,
376                       true,
377                       false);
378  EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
379
380  renderer_->GetFramebufferPixels(pixels, gfx::Rect(0, 0, 1, 1));
381  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
382  EXPECT_EQ(2, renderer_client_.set_full_root_layer_damage_count());
383}
384
385TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) {
386  gfx::Rect viewport_rect(1, 1);
387  EXPECT_FALSE(renderer_->stencil_enabled());
388
389  output_surface_->set_has_external_stencil_test(true);
390
391  TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
392                                            RenderPass::Id(1, 0),
393                                            viewport_rect,
394                                            gfx::Transform());
395  root_pass->has_transparent_background = false;
396
397  renderer_->DrawFrame(&render_passes_in_draw_order_,
398                       NULL,
399                       1.f,
400                       viewport_rect,
401                       viewport_rect,
402                       true,
403                       false);
404  EXPECT_TRUE(renderer_->stencil_enabled());
405}
406
407class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
408 public:
409  ForbidSynchronousCallContext() {}
410
411  virtual bool getActiveAttrib(WebGLId program,
412                               WGC3Duint index,
413                               ActiveInfo& info) {
414    ADD_FAILURE();
415    return false;
416  }
417  virtual bool getActiveUniform(WebGLId program,
418                                WGC3Duint index,
419                                ActiveInfo& info) {
420    ADD_FAILURE();
421    return false;
422  }
423  virtual void getAttachedShaders(WebGLId program,
424                                  WGC3Dsizei max_count,
425                                  WGC3Dsizei* count,
426                                  WebGLId* shaders) {
427    ADD_FAILURE();
428  }
429  virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name) {
430    ADD_FAILURE();
431    return 0;
432  }
433  virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value) {
434    ADD_FAILURE();
435  }
436  virtual void getBufferParameteriv(WGC3Denum target,
437                                    WGC3Denum pname,
438                                    WGC3Dint* value) {
439    ADD_FAILURE();
440  }
441  virtual Attributes getContextAttributes() {
442    ADD_FAILURE();
443    return attributes_;
444  }
445  virtual WGC3Denum getError() {
446    ADD_FAILURE();
447    return 0;
448  }
449  virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
450  virtual void getFramebufferAttachmentParameteriv(WGC3Denum target,
451                                                   WGC3Denum attachment,
452                                                   WGC3Denum pname,
453                                                   WGC3Dint* value) {
454    ADD_FAILURE();
455  }
456  virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value) {
457    if (pname == GL_MAX_TEXTURE_SIZE) {
458      // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
459      *value = 1024;
460    } else {
461      ADD_FAILURE();
462    }
463  }
464
465  // We allow querying the shader compilation and program link status in debug
466  // mode, but not release.
467  virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) {
468#ifndef NDEBUG
469    *value = 1;
470#else
471    ADD_FAILURE();
472#endif
473  }
474
475  virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) {
476#ifndef NDEBUG
477    *value = 1;
478#else
479    ADD_FAILURE();
480#endif
481  }
482
483  virtual WebString getString(WGC3Denum name) {
484    ADD_FAILURE() << name;
485    return WebString();
486  }
487
488  virtual WebString getProgramInfoLog(WebGLId program) {
489    ADD_FAILURE();
490    return WebString();
491  }
492  virtual void getRenderbufferParameteriv(WGC3Denum target,
493                                          WGC3Denum pname,
494                                          WGC3Dint* value) {
495    ADD_FAILURE();
496  }
497
498  virtual WebString getShaderInfoLog(WebGLId shader) {
499    ADD_FAILURE();
500    return WebString();
501  }
502  virtual void getShaderPrecisionFormat(WGC3Denum shadertype,
503                                        WGC3Denum precisiontype,
504                                        WGC3Dint* range,
505                                        WGC3Dint* precision) {
506    ADD_FAILURE();
507  }
508  virtual WebString getShaderSource(WebGLId shader) {
509    ADD_FAILURE();
510    return WebString();
511  }
512  virtual void getTexParameterfv(WGC3Denum target,
513                                 WGC3Denum pname,
514                                 WGC3Dfloat* value) {
515    ADD_FAILURE();
516  }
517  virtual void getTexParameteriv(WGC3Denum target,
518                                 WGC3Denum pname,
519                                 WGC3Dint* value) {
520    ADD_FAILURE();
521  }
522  virtual void getUniformfv(WebGLId program,
523                            WGC3Dint location,
524                            WGC3Dfloat* value) {
525    ADD_FAILURE();
526  }
527  virtual void getUniformiv(WebGLId program,
528                            WGC3Dint location,
529                            WGC3Dint* value) {
530    ADD_FAILURE();
531  }
532  virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name) {
533    ADD_FAILURE();
534    return 0;
535  }
536  virtual void getVertexAttribfv(WGC3Duint index,
537                                 WGC3Denum pname,
538                                 WGC3Dfloat* value) {
539    ADD_FAILURE();
540  }
541  virtual void getVertexAttribiv(WGC3Duint index,
542                                 WGC3Denum pname,
543                                 WGC3Dint* value) {
544    ADD_FAILURE();
545  }
546  virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index,
547                                              WGC3Denum pname) {
548    ADD_FAILURE();
549    return 0;
550  }
551};
552
553TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
554  FakeOutputSurfaceClient output_surface_client;
555  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
556      scoped_ptr<TestWebGraphicsContext3D>(new ForbidSynchronousCallContext)));
557  CHECK(output_surface->BindToClient(&output_surface_client));
558
559  scoped_ptr<ResourceProvider> resource_provider(
560      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
561
562  LayerTreeSettings settings;
563  FakeRendererClient renderer_client;
564  FakeRendererGL renderer(&renderer_client,
565                          &settings,
566                          output_surface.get(),
567                          resource_provider.get());
568}
569
570class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D {
571 public:
572  LoseContextOnFirstGetContext() {}
573
574  virtual void getProgramiv(WebGLId program,
575                            WGC3Denum pname,
576                            WGC3Dint* value) OVERRIDE {
577    context_lost_ = true;
578    *value = 0;
579  }
580
581  virtual void getShaderiv(WebGLId shader,
582                           WGC3Denum pname,
583                           WGC3Dint* value) OVERRIDE {
584    context_lost_ = true;
585    *value = 0;
586  }
587};
588
589TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
590  FakeOutputSurfaceClient output_surface_client;
591  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
592      scoped_ptr<TestWebGraphicsContext3D>(new LoseContextOnFirstGetContext)));
593  CHECK(output_surface->BindToClient(&output_surface_client));
594
595  scoped_ptr<ResourceProvider> resource_provider(
596      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
597
598  LayerTreeSettings settings;
599  FakeRendererClient renderer_client;
600  FakeRendererGL renderer(&renderer_client,
601                          &settings,
602                          output_surface.get(),
603                          resource_provider.get());
604}
605
606class ClearCountingContext : public TestWebGraphicsContext3D {
607 public:
608  ClearCountingContext() { test_capabilities_.discard_framebuffer = true; }
609
610  MOCK_METHOD3(discardFramebufferEXT,
611               void(WGC3Denum target,
612                    WGC3Dsizei numAttachments,
613                    const WGC3Denum* attachments));
614  MOCK_METHOD1(clear, void(WGC3Dbitfield mask));
615};
616
617TEST_F(GLRendererTest, OpaqueBackground) {
618  scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
619  ClearCountingContext* context = context_owned.get();
620
621  FakeOutputSurfaceClient output_surface_client;
622  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
623      context_owned.PassAs<TestWebGraphicsContext3D>()));
624  CHECK(output_surface->BindToClient(&output_surface_client));
625
626  scoped_ptr<ResourceProvider> resource_provider(
627      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
628
629  LayerTreeSettings settings;
630  FakeRendererClient renderer_client;
631  FakeRendererGL renderer(&renderer_client,
632                          &settings,
633                          output_surface.get(),
634                          resource_provider.get());
635
636  gfx::Rect viewport_rect(1, 1);
637  TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
638                                            RenderPass::Id(1, 0),
639                                            viewport_rect,
640                                            gfx::Transform());
641  root_pass->has_transparent_background = false;
642
643  // On DEBUG builds, render passes with opaque background clear to blue to
644  // easily see regions that were not drawn on the screen.
645  EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
646      .With(Args<2, 1>(ElementsAre(GL_COLOR_EXT)))
647      .Times(1);
648#ifdef NDEBUG
649  EXPECT_CALL(*context, clear(_)).Times(0);
650#else
651  EXPECT_CALL(*context, clear(_)).Times(1);
652#endif
653  renderer.DrawFrame(&render_passes_in_draw_order_,
654                     NULL,
655                     1.f,
656                     viewport_rect,
657                     viewport_rect,
658                     true,
659                     false);
660  Mock::VerifyAndClearExpectations(context);
661}
662
663TEST_F(GLRendererTest, TransparentBackground) {
664  scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
665  ClearCountingContext* context = context_owned.get();
666
667  FakeOutputSurfaceClient output_surface_client;
668  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
669      context_owned.PassAs<TestWebGraphicsContext3D>()));
670  CHECK(output_surface->BindToClient(&output_surface_client));
671
672  scoped_ptr<ResourceProvider> resource_provider(
673      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
674
675  LayerTreeSettings settings;
676  FakeRendererClient renderer_client;
677  FakeRendererGL renderer(&renderer_client,
678                          &settings,
679                          output_surface.get(),
680                          resource_provider.get());
681
682  gfx::Rect viewport_rect(1, 1);
683  TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
684                                            RenderPass::Id(1, 0),
685                                            viewport_rect,
686                                            gfx::Transform());
687  root_pass->has_transparent_background = true;
688
689  EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
690  EXPECT_CALL(*context, clear(_)).Times(1);
691  renderer.DrawFrame(&render_passes_in_draw_order_,
692                     NULL,
693                     1.f,
694                     viewport_rect,
695                     viewport_rect,
696                     true,
697                     false);
698
699  Mock::VerifyAndClearExpectations(context);
700}
701
702TEST_F(GLRendererTest, OffscreenOutputSurface) {
703  scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
704  ClearCountingContext* context = context_owned.get();
705
706  FakeOutputSurfaceClient output_surface_client;
707  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::CreateOffscreen(
708      context_owned.PassAs<TestWebGraphicsContext3D>()));
709  CHECK(output_surface->BindToClient(&output_surface_client));
710
711  scoped_ptr<ResourceProvider> resource_provider(
712      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
713
714  LayerTreeSettings settings;
715  FakeRendererClient renderer_client;
716  FakeRendererGL renderer(&renderer_client,
717                          &settings,
718                          output_surface.get(),
719                          resource_provider.get());
720
721  gfx::Rect viewport_rect(1, 1);
722  AddRenderPass(&render_passes_in_draw_order_,
723                RenderPass::Id(1, 0),
724                viewport_rect,
725                gfx::Transform());
726
727  EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
728      .With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0)))
729      .Times(1);
730  EXPECT_CALL(*context, clear(_)).Times(AnyNumber());
731  renderer.DrawFrame(&render_passes_in_draw_order_,
732                     NULL,
733                     1.f,
734                     viewport_rect,
735                     viewport_rect,
736                     true,
737                     false);
738  Mock::VerifyAndClearExpectations(context);
739}
740
741class VisibilityChangeIsLastCallTrackingContext
742    : public TestWebGraphicsContext3D {
743 public:
744  VisibilityChangeIsLastCallTrackingContext()
745      : last_call_was_set_visibility_(false) {}
746
747  // WebGraphicsContext3D methods.
748  virtual void flush() {
749    last_call_was_set_visibility_ = false;
750  }
751  virtual void deleteTexture(WebGLId) {
752    last_call_was_set_visibility_ = false;
753  }
754  virtual void deleteFramebuffer(WebGLId) {
755    last_call_was_set_visibility_ = false;
756  }
757  virtual void deleteQueryEXT(WebGLId) {
758    last_call_was_set_visibility_ = false;
759  }
760  virtual void deleteRenderbuffer(WebGLId) {
761    last_call_was_set_visibility_ = false;
762  }
763
764  // Methods added for test.
765  void set_last_call_was_visibility(bool visible) {
766    DCHECK(last_call_was_set_visibility_ == false);
767    last_call_was_set_visibility_ = true;
768  }
769  bool last_call_was_set_visibility() const {
770    return last_call_was_set_visibility_;
771  }
772
773 private:
774  bool last_call_was_set_visibility_;
775};
776
777TEST_F(GLRendererTest, VisibilityChangeIsLastCall) {
778  scoped_ptr<VisibilityChangeIsLastCallTrackingContext> context_owned(
779      new VisibilityChangeIsLastCallTrackingContext);
780  VisibilityChangeIsLastCallTrackingContext* context = context_owned.get();
781
782  scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(
783      context_owned.PassAs<TestWebGraphicsContext3D>());
784
785  provider->support()->SetSurfaceVisibleCallback(base::Bind(
786      &VisibilityChangeIsLastCallTrackingContext::set_last_call_was_visibility,
787      base::Unretained(context)));
788
789  FakeOutputSurfaceClient output_surface_client;
790  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
791        provider));
792  CHECK(output_surface->BindToClient(&output_surface_client));
793
794  scoped_ptr<ResourceProvider> resource_provider(
795      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
796
797  LayerTreeSettings settings;
798  FakeRendererClient renderer_client;
799  FakeRendererGL renderer(&renderer_client,
800                          &settings,
801                          output_surface.get(),
802                          resource_provider.get());
803
804  gfx::Rect viewport_rect(1, 1);
805  AddRenderPass(&render_passes_in_draw_order_,
806                RenderPass::Id(1, 0),
807                viewport_rect,
808                gfx::Transform());
809
810  // Ensure that the call to SetSurfaceVisible is the last call issue to the
811  // GPU process, after glFlush is called, and after the RendererClient's
812  // SetManagedMemoryPolicy is called. Plumb this tracking between both the
813  // RenderClient and the Context by giving them both a pointer to a variable on
814  // the stack.
815  renderer.SetVisible(true);
816  renderer.DrawFrame(&render_passes_in_draw_order_,
817                     NULL,
818                     1.f,
819                     viewport_rect,
820                     viewport_rect,
821                     true,
822                     false);
823  renderer.SetVisible(false);
824  EXPECT_TRUE(context->last_call_was_set_visibility());
825}
826
827class TextureStateTrackingContext : public TestWebGraphicsContext3D {
828 public:
829  TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) {
830    test_capabilities_.egl_image_external = true;
831  }
832
833  MOCK_METHOD3(texParameteri,
834               void(WGC3Denum target, WGC3Denum pname, WGC3Dint param));
835  MOCK_METHOD4(drawElements,
836               void(WGC3Denum mode,
837                    WGC3Dsizei count,
838                    WGC3Denum type,
839                    WGC3Dintptr offset));
840
841  virtual void activeTexture(WGC3Denum texture) {
842    EXPECT_NE(texture, active_texture_);
843    active_texture_ = texture;
844  }
845
846  WGC3Denum active_texture() const { return active_texture_; }
847
848 private:
849  WGC3Denum active_texture_;
850};
851
852TEST_F(GLRendererTest, ActiveTextureState) {
853  scoped_ptr<TextureStateTrackingContext> context_owned(
854      new TextureStateTrackingContext);
855  TextureStateTrackingContext* context = context_owned.get();
856
857  FakeOutputSurfaceClient output_surface_client;
858  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
859      context_owned.PassAs<TestWebGraphicsContext3D>()));
860  CHECK(output_surface->BindToClient(&output_surface_client));
861
862  scoped_ptr<ResourceProvider> resource_provider(
863      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
864
865  LayerTreeSettings settings;
866  FakeRendererClient renderer_client;
867  FakeRendererGL renderer(&renderer_client,
868                          &settings,
869                          output_surface.get(),
870                          resource_provider.get());
871
872  // During initialization we are allowed to set any texture parameters.
873  EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber());
874
875  RenderPass::Id id(1, 1);
876  TestRenderPass* root_pass = AddRenderPass(
877      &render_passes_in_draw_order_, id, gfx::Rect(100, 100), gfx::Transform());
878  root_pass->AppendOneOfEveryQuadType(resource_provider.get(),
879                                      RenderPass::Id(2, 1));
880
881  renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
882
883  // Set up expected texture filter state transitions that match the quads
884  // created in AppendOneOfEveryQuadType().
885  Mock::VerifyAndClearExpectations(context);
886  {
887    InSequence sequence;
888
889    // yuv_quad is drawn with the default linear filter.
890    EXPECT_CALL(*context, drawElements(_, _, _, _));
891
892    // tile_quad is drawn with GL_NEAREST because it is not transformed or
893    // scaled.
894    EXPECT_CALL(
895        *context,
896        texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
897    EXPECT_CALL(
898        *context,
899        texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
900    EXPECT_CALL(*context, drawElements(_, _, _, _));
901
902    // transformed_tile_quad uses GL_LINEAR.
903    EXPECT_CALL(*context, drawElements(_, _, _, _));
904
905    // scaled_tile_quad also uses GL_LINEAR.
906    EXPECT_CALL(*context, drawElements(_, _, _, _));
907
908    // The remaining quads also use GL_LINEAR because nearest neighbor
909    // filtering is currently only used with tile quads.
910    EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(6);
911  }
912
913  gfx::Rect viewport_rect(100, 100);
914  renderer.DrawFrame(&render_passes_in_draw_order_,
915                     NULL,
916                     1.f,
917                     viewport_rect,
918                     viewport_rect,
919                     true,
920                     false);
921  Mock::VerifyAndClearExpectations(context);
922}
923
924class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D {
925 public:
926  MOCK_METHOD1(clear, void(WGC3Dbitfield mask));
927  MOCK_METHOD4(drawElements,
928               void(WGC3Denum mode,
929                    WGC3Dsizei count,
930                    WGC3Denum type,
931                    WGC3Dintptr offset));
932};
933
934TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
935  scoped_ptr<NoClearRootRenderPassMockContext> mock_context_owned(
936      new NoClearRootRenderPassMockContext);
937  NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get();
938
939  FakeOutputSurfaceClient output_surface_client;
940  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
941      mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
942  CHECK(output_surface->BindToClient(&output_surface_client));
943
944  scoped_ptr<ResourceProvider> resource_provider(
945      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
946
947  LayerTreeSettings settings;
948  settings.should_clear_root_render_pass = false;
949
950  FakeRendererClient renderer_client;
951  FakeRendererGL renderer(&renderer_client,
952                          &settings,
953                          output_surface.get(),
954                          resource_provider.get());
955
956  gfx::Rect viewport_rect(10, 10);
957
958  RenderPass::Id root_pass_id(1, 0);
959  TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
960                                            root_pass_id,
961                                            viewport_rect,
962                                            gfx::Transform());
963  AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
964
965  RenderPass::Id child_pass_id(2, 0);
966  TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_,
967                                             child_pass_id,
968                                             viewport_rect,
969                                             gfx::Transform());
970  AddQuad(child_pass, viewport_rect, SK_ColorBLUE);
971
972  AddRenderPassQuad(root_pass, child_pass);
973
974#ifdef NDEBUG
975  GLint clear_bits = GL_COLOR_BUFFER_BIT;
976#else
977  GLint clear_bits = GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
978#endif
979
980  // First render pass is not the root one, clearing should happen.
981  EXPECT_CALL(*mock_context, clear(clear_bits)).Times(AtLeast(1));
982
983  Expectation first_render_pass =
984      EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1);
985
986  // The second render pass is the root one, clearing should be prevented.
987  EXPECT_CALL(*mock_context, clear(clear_bits)).Times(0).After(
988      first_render_pass);
989
990  EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(AnyNumber()).After(
991      first_render_pass);
992
993  renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
994  renderer.DrawFrame(&render_passes_in_draw_order_,
995                     NULL,
996                     1.f,
997                     viewport_rect,
998                     viewport_rect,
999                     true,
1000                     false);
1001
1002  // In multiple render passes all but the root pass should clear the
1003  // framebuffer.
1004  Mock::VerifyAndClearExpectations(&mock_context);
1005}
1006
1007class ScissorTestOnClearCheckingContext : public TestWebGraphicsContext3D {
1008 public:
1009  ScissorTestOnClearCheckingContext() : scissor_enabled_(false) {}
1010
1011  virtual void clear(WGC3Dbitfield) { EXPECT_FALSE(scissor_enabled_); }
1012
1013  virtual void enable(WGC3Denum cap) {
1014    if (cap == GL_SCISSOR_TEST)
1015      scissor_enabled_ = true;
1016  }
1017
1018  virtual void disable(WGC3Denum cap) {
1019    if (cap == GL_SCISSOR_TEST)
1020      scissor_enabled_ = false;
1021  }
1022
1023 private:
1024  bool scissor_enabled_;
1025};
1026
1027TEST_F(GLRendererTest, ScissorTestWhenClearing) {
1028  scoped_ptr<ScissorTestOnClearCheckingContext> context_owned(
1029      new ScissorTestOnClearCheckingContext);
1030
1031  FakeOutputSurfaceClient output_surface_client;
1032  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
1033      context_owned.PassAs<TestWebGraphicsContext3D>()));
1034  CHECK(output_surface->BindToClient(&output_surface_client));
1035
1036  scoped_ptr<ResourceProvider> resource_provider(
1037      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
1038
1039  LayerTreeSettings settings;
1040  FakeRendererClient renderer_client;
1041  FakeRendererGL renderer(&renderer_client,
1042                          &settings,
1043                          output_surface.get(),
1044                          resource_provider.get());
1045  EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
1046
1047  gfx::Rect viewport_rect(1, 1);
1048
1049  gfx::Rect grand_child_rect(25, 25);
1050  RenderPass::Id grand_child_pass_id(3, 0);
1051  TestRenderPass* grand_child_pass =
1052      AddRenderPass(&render_passes_in_draw_order_,
1053                    grand_child_pass_id,
1054                    grand_child_rect,
1055                    gfx::Transform());
1056  AddClippedQuad(grand_child_pass, grand_child_rect, SK_ColorYELLOW);
1057
1058  gfx::Rect child_rect(50, 50);
1059  RenderPass::Id child_pass_id(2, 0);
1060  TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_,
1061                                             child_pass_id,
1062                                             child_rect,
1063                                             gfx::Transform());
1064  AddQuad(child_pass, child_rect, SK_ColorBLUE);
1065
1066  RenderPass::Id root_pass_id(1, 0);
1067  TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1068                                            root_pass_id,
1069                                            viewport_rect,
1070                                            gfx::Transform());
1071  AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1072
1073  AddRenderPassQuad(root_pass, child_pass);
1074  AddRenderPassQuad(child_pass, grand_child_pass);
1075
1076  renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1077  renderer.DrawFrame(&render_passes_in_draw_order_,
1078                     NULL,
1079                     1.f,
1080                     viewport_rect,
1081                     viewport_rect,
1082                     true,
1083                     false);
1084}
1085
1086class DiscardCheckingContext : public TestWebGraphicsContext3D {
1087 public:
1088  DiscardCheckingContext() : discarded_(0) {
1089    set_have_post_sub_buffer(true);
1090    set_have_discard_framebuffer(true);
1091  }
1092
1093  virtual void discardFramebufferEXT(WGC3Denum target,
1094                                     WGC3Dsizei numAttachments,
1095                                     const WGC3Denum* attachments) {
1096    ++discarded_;
1097  }
1098
1099  int discarded() const { return discarded_; }
1100  void reset() { discarded_ = 0; }
1101
1102 private:
1103  int discarded_;
1104};
1105
1106class NonReshapableOutputSurface : public FakeOutputSurface {
1107 public:
1108  explicit NonReshapableOutputSurface(
1109      scoped_ptr<TestWebGraphicsContext3D> context3d)
1110      : FakeOutputSurface(TestContextProvider::Create(context3d.Pass()),
1111                          false) {
1112    surface_size_ = gfx::Size(500, 500);
1113  }
1114  virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE {}
1115  void set_fixed_size(gfx::Size size) { surface_size_ = size; }
1116};
1117
1118TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
1119  scoped_ptr<DiscardCheckingContext> context_owned(new DiscardCheckingContext);
1120  DiscardCheckingContext* context = context_owned.get();
1121
1122  FakeOutputSurfaceClient output_surface_client;
1123  scoped_ptr<NonReshapableOutputSurface> output_surface(
1124      new NonReshapableOutputSurface(
1125          context_owned.PassAs<TestWebGraphicsContext3D>()));
1126  CHECK(output_surface->BindToClient(&output_surface_client));
1127  output_surface->set_fixed_size(gfx::Size(100, 100));
1128
1129  scoped_ptr<ResourceProvider> resource_provider(
1130      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
1131
1132  LayerTreeSettings settings;
1133  settings.partial_swap_enabled = true;
1134  FakeRendererClient renderer_client;
1135  FakeRendererGL renderer(&renderer_client,
1136                          &settings,
1137                          output_surface.get(),
1138                          resource_provider.get());
1139  EXPECT_TRUE(renderer.Capabilities().using_partial_swap);
1140
1141  gfx::Rect viewport_rect(100, 100);
1142  gfx::Rect clip_rect(100, 100);
1143
1144  {
1145    // Partial frame, should not discard.
1146    RenderPass::Id root_pass_id(1, 0);
1147    TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1148                                              root_pass_id,
1149                                              viewport_rect,
1150                                              gfx::Transform());
1151    AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1152    root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f);
1153
1154    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1155    renderer.DrawFrame(&render_passes_in_draw_order_,
1156                       NULL,
1157                       1.f,
1158                       viewport_rect,
1159                       clip_rect,
1160                       true,
1161                       false);
1162    EXPECT_EQ(0, context->discarded());
1163    context->reset();
1164  }
1165  {
1166    // Full frame, should discard.
1167    RenderPass::Id root_pass_id(1, 0);
1168    TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1169                                              root_pass_id,
1170                                              viewport_rect,
1171                                              gfx::Transform());
1172    AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1173    root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
1174
1175    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1176    renderer.DrawFrame(&render_passes_in_draw_order_,
1177                       NULL,
1178                       1.f,
1179                       viewport_rect,
1180                       clip_rect,
1181                       true,
1182                       false);
1183    EXPECT_EQ(1, context->discarded());
1184    context->reset();
1185  }
1186  {
1187    // Partial frame, disallow partial swap, should discard.
1188    RenderPass::Id root_pass_id(1, 0);
1189    TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1190                                              root_pass_id,
1191                                              viewport_rect,
1192                                              gfx::Transform());
1193    AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1194    root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f);
1195
1196    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1197    renderer.DrawFrame(&render_passes_in_draw_order_,
1198                       NULL,
1199                       1.f,
1200                       viewport_rect,
1201                       clip_rect,
1202                       false,
1203                       false);
1204    EXPECT_EQ(1, context->discarded());
1205    context->reset();
1206  }
1207  {
1208    // Full frame, external scissor is set, should not discard.
1209    output_surface->set_has_external_stencil_test(true);
1210    RenderPass::Id root_pass_id(1, 0);
1211    TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1212                                              root_pass_id,
1213                                              viewport_rect,
1214                                              gfx::Transform());
1215    AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1216    root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
1217    root_pass->has_transparent_background = false;
1218
1219    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1220    renderer.DrawFrame(&render_passes_in_draw_order_,
1221                       NULL,
1222                       1.f,
1223                       viewport_rect,
1224                       clip_rect,
1225                       true,
1226                       false);
1227    EXPECT_EQ(0, context->discarded());
1228    context->reset();
1229    output_surface->set_has_external_stencil_test(false);
1230  }
1231  {
1232    // Full frame, clipped, should not discard.
1233    clip_rect = gfx::Rect(10, 10, 10, 10);
1234    RenderPass::Id root_pass_id(1, 0);
1235    TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1236                                              root_pass_id,
1237                                              viewport_rect,
1238                                              gfx::Transform());
1239    AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1240    root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
1241
1242    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1243    renderer.DrawFrame(&render_passes_in_draw_order_,
1244                       NULL,
1245                       1.f,
1246                       viewport_rect,
1247                       clip_rect,
1248                       true,
1249                       false);
1250    EXPECT_EQ(0, context->discarded());
1251    context->reset();
1252  }
1253  {
1254    // Full frame, doesn't cover the surface, should not discard.
1255    viewport_rect = gfx::Rect(10, 10, 10, 10);
1256    RenderPass::Id root_pass_id(1, 0);
1257    TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1258                                              root_pass_id,
1259                                              viewport_rect,
1260                                              gfx::Transform());
1261    AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1262    root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
1263
1264    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1265    renderer.DrawFrame(&render_passes_in_draw_order_,
1266                       NULL,
1267                       1.f,
1268                       viewport_rect,
1269                       clip_rect,
1270                       true,
1271                       false);
1272    EXPECT_EQ(0, context->discarded());
1273    context->reset();
1274  }
1275  {
1276    // Full frame, doesn't cover the surface (no offset), should not discard.
1277    clip_rect = gfx::Rect(100, 100);
1278    viewport_rect = gfx::Rect(50, 50);
1279    RenderPass::Id root_pass_id(1, 0);
1280    TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1281                                              root_pass_id,
1282                                              viewport_rect,
1283                                              gfx::Transform());
1284    AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
1285    root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
1286
1287    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1288    renderer.DrawFrame(&render_passes_in_draw_order_,
1289                       NULL,
1290                       1.f,
1291                       viewport_rect,
1292                       clip_rect,
1293                       true,
1294                       false);
1295    EXPECT_EQ(0, context->discarded());
1296    context->reset();
1297  }
1298}
1299
1300class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D {
1301 public:
1302  FlippedScissorAndViewportContext()
1303      : did_call_viewport_(false), did_call_scissor_(false) {}
1304  virtual ~FlippedScissorAndViewportContext() {
1305    EXPECT_TRUE(did_call_viewport_);
1306    EXPECT_TRUE(did_call_scissor_);
1307  }
1308
1309  virtual void viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
1310    EXPECT_EQ(10, x);
1311    EXPECT_EQ(390, y);
1312    EXPECT_EQ(100, width);
1313    EXPECT_EQ(100, height);
1314    did_call_viewport_ = true;
1315  }
1316
1317  virtual void scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
1318    EXPECT_EQ(30, x);
1319    EXPECT_EQ(450, y);
1320    EXPECT_EQ(20, width);
1321    EXPECT_EQ(20, height);
1322    did_call_scissor_ = true;
1323  }
1324
1325 private:
1326  bool did_call_viewport_;
1327  bool did_call_scissor_;
1328};
1329
1330TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
1331  // In Android WebView, the OutputSurface is unable to respect reshape() calls
1332  // and maintains a fixed size. This test verifies that glViewport and
1333  // glScissor's Y coordinate is flipped correctly in this environment, and that
1334  // the glViewport can be at a nonzero origin within the surface.
1335  scoped_ptr<FlippedScissorAndViewportContext> context_owned(
1336      new FlippedScissorAndViewportContext);
1337
1338  FakeOutputSurfaceClient output_surface_client;
1339  scoped_ptr<OutputSurface> output_surface(new NonReshapableOutputSurface(
1340      context_owned.PassAs<TestWebGraphicsContext3D>()));
1341  CHECK(output_surface->BindToClient(&output_surface_client));
1342
1343  scoped_ptr<ResourceProvider> resource_provider(
1344      ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
1345
1346  LayerTreeSettings settings;
1347  FakeRendererClient renderer_client;
1348  FakeRendererGL renderer(&renderer_client,
1349                          &settings,
1350                          output_surface.get(),
1351                          resource_provider.get());
1352  EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
1353
1354  gfx::Rect device_viewport_rect(10, 10, 100, 100);
1355  gfx::Rect viewport_rect(device_viewport_rect.size());
1356  gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
1357
1358  RenderPass::Id root_pass_id(1, 0);
1359  TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
1360                                            root_pass_id,
1361                                            viewport_rect,
1362                                            gfx::Transform());
1363  AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
1364
1365  renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1366  renderer.DrawFrame(&render_passes_in_draw_order_,
1367                     NULL,
1368                     1.f,
1369                     device_viewport_rect,
1370                     device_viewport_rect,
1371                     true,
1372                     false);
1373}
1374
1375TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
1376  gfx::Rect viewport_rect(1, 1);
1377
1378  gfx::Rect child_rect(50, 50);
1379  RenderPass::Id child_pass_id(2, 0);
1380  TestRenderPass* child_pass;
1381
1382  RenderPass::Id root_pass_id(1, 0);
1383  TestRenderPass* root_pass;
1384
1385  ResourceProvider::ResourceId mask = resource_provider_->CreateResource(
1386      gfx::Size(20, 12),
1387      GL_CLAMP_TO_EDGE,
1388      ResourceProvider::TextureUsageAny,
1389      resource_provider_->best_texture_format());
1390  resource_provider_->AllocateForTesting(mask);
1391
1392  SkScalar matrix[20];
1393  float amount = 0.5f;
1394  matrix[0] = 0.213f + 0.787f * amount;
1395  matrix[1] = 0.715f - 0.715f * amount;
1396  matrix[2] = 1.f - (matrix[0] + matrix[1]);
1397  matrix[3] = matrix[4] = 0;
1398  matrix[5] = 0.213f - 0.213f * amount;
1399  matrix[6] = 0.715f + 0.285f * amount;
1400  matrix[7] = 1.f - (matrix[5] + matrix[6]);
1401  matrix[8] = matrix[9] = 0;
1402  matrix[10] = 0.213f - 0.213f * amount;
1403  matrix[11] = 0.715f - 0.715f * amount;
1404  matrix[12] = 1.f - (matrix[10] + matrix[11]);
1405  matrix[13] = matrix[14] = 0;
1406  matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
1407  matrix[18] = 1;
1408  skia::RefPtr<SkColorFilter> color_filter(
1409      skia::AdoptRef(new SkColorMatrixFilter(matrix)));
1410  skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(
1411      SkColorFilterImageFilter::Create(color_filter.get(), NULL));
1412  FilterOperations filters;
1413  filters.Append(FilterOperation::CreateReferenceFilter(filter));
1414
1415  gfx::Transform transform_causing_aa;
1416  transform_causing_aa.Rotate(20.0);
1417
1418  // RenderPassProgram
1419  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1420                             child_pass_id,
1421                             child_rect,
1422                             gfx::Transform());
1423
1424  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1425                            root_pass_id,
1426                            viewport_rect,
1427                            gfx::Transform());
1428
1429  AddRenderPassQuad(
1430      root_pass, child_pass, 0, FilterOperations(), gfx::Transform());
1431
1432  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1433  renderer_->DrawFrame(&render_passes_in_draw_order_,
1434                       NULL,
1435                       1.f,
1436                       viewport_rect,
1437                       viewport_rect,
1438                       true,
1439                       false);
1440  TestRenderPassProgram(TexCoordPrecisionMedium);
1441
1442  // RenderPassColorMatrixProgram
1443  render_passes_in_draw_order_.clear();
1444
1445  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1446                             child_pass_id,
1447                             child_rect,
1448                             transform_causing_aa);
1449
1450  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1451                            root_pass_id,
1452                            viewport_rect,
1453                            gfx::Transform());
1454
1455  AddRenderPassQuad(root_pass, child_pass, 0, filters, gfx::Transform());
1456
1457  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1458  renderer_->DrawFrame(&render_passes_in_draw_order_,
1459                       NULL,
1460                       1.f,
1461                       viewport_rect,
1462                       viewport_rect,
1463                       true,
1464                       false);
1465  TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium);
1466
1467  // RenderPassMaskProgram
1468  render_passes_in_draw_order_.clear();
1469
1470  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1471                             child_pass_id,
1472                             child_rect,
1473                             gfx::Transform());
1474
1475  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1476                            root_pass_id,
1477                            viewport_rect,
1478                            gfx::Transform());
1479
1480  AddRenderPassQuad(
1481      root_pass, child_pass, mask, FilterOperations(), gfx::Transform());
1482
1483  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1484  renderer_->DrawFrame(&render_passes_in_draw_order_,
1485                       NULL,
1486                       1.f,
1487                       viewport_rect,
1488                       viewport_rect,
1489                       true,
1490                       false);
1491  TestRenderPassMaskProgram(TexCoordPrecisionMedium);
1492
1493  // RenderPassMaskColorMatrixProgram
1494  render_passes_in_draw_order_.clear();
1495
1496  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1497                             child_pass_id,
1498                             child_rect,
1499                             gfx::Transform());
1500
1501  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1502                            root_pass_id,
1503                            viewport_rect,
1504                            gfx::Transform());
1505
1506  AddRenderPassQuad(root_pass, child_pass, mask, filters, gfx::Transform());
1507
1508  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1509  renderer_->DrawFrame(&render_passes_in_draw_order_,
1510                       NULL,
1511                       1.f,
1512                       viewport_rect,
1513                       viewport_rect,
1514                       true,
1515                       false);
1516  TestRenderPassMaskColorMatrixProgram(TexCoordPrecisionMedium);
1517
1518  // RenderPassProgramAA
1519  render_passes_in_draw_order_.clear();
1520
1521  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1522                             child_pass_id,
1523                             child_rect,
1524                             transform_causing_aa);
1525
1526  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1527                            root_pass_id,
1528                            viewport_rect,
1529                            gfx::Transform());
1530
1531  AddRenderPassQuad(
1532      root_pass, child_pass, 0, FilterOperations(), transform_causing_aa);
1533
1534  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1535  renderer_->DrawFrame(&render_passes_in_draw_order_,
1536                       NULL,
1537                       1.f,
1538                       viewport_rect,
1539                       viewport_rect,
1540                       true,
1541                       false);
1542  TestRenderPassProgramAA(TexCoordPrecisionMedium);
1543
1544  // RenderPassColorMatrixProgramAA
1545  render_passes_in_draw_order_.clear();
1546
1547  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1548                             child_pass_id,
1549                             child_rect,
1550                             transform_causing_aa);
1551
1552  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1553                            root_pass_id,
1554                            viewport_rect,
1555                            gfx::Transform());
1556
1557  AddRenderPassQuad(root_pass, child_pass, 0, filters, transform_causing_aa);
1558
1559  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1560  renderer_->DrawFrame(&render_passes_in_draw_order_,
1561                       NULL,
1562                       1.f,
1563                       viewport_rect,
1564                       viewport_rect,
1565                       true,
1566                       false);
1567  TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium);
1568
1569  // RenderPassMaskProgramAA
1570  render_passes_in_draw_order_.clear();
1571
1572  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1573                             child_pass_id,
1574                             child_rect,
1575                             transform_causing_aa);
1576
1577  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1578                            root_pass_id,
1579                            viewport_rect,
1580                            gfx::Transform());
1581
1582  AddRenderPassQuad(
1583      root_pass, child_pass, mask, FilterOperations(), transform_causing_aa);
1584
1585  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1586  renderer_->DrawFrame(&render_passes_in_draw_order_,
1587                       NULL,
1588                       1.f,
1589                       viewport_rect,
1590                       viewport_rect,
1591                       true,
1592                       false);
1593  TestRenderPassMaskProgramAA(TexCoordPrecisionMedium);
1594
1595  // RenderPassMaskColorMatrixProgramAA
1596  render_passes_in_draw_order_.clear();
1597
1598  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1599                             child_pass_id,
1600                             child_rect,
1601                             transform_causing_aa);
1602
1603  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1604                            root_pass_id,
1605                            viewport_rect,
1606                            transform_causing_aa);
1607
1608  AddRenderPassQuad(root_pass, child_pass, mask, filters, transform_causing_aa);
1609
1610  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1611  renderer_->DrawFrame(&render_passes_in_draw_order_,
1612                       NULL,
1613                       1.f,
1614                       viewport_rect,
1615                       viewport_rect,
1616                       true,
1617                       false);
1618  TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecisionMedium);
1619}
1620
1621// At this time, the AA code path cannot be taken if the surface's rect would
1622// project incorrectly by the given transform, because of w<0 clipping.
1623TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
1624  gfx::Rect child_rect(50, 50);
1625  RenderPass::Id child_pass_id(2, 0);
1626  TestRenderPass* child_pass;
1627
1628  gfx::Rect viewport_rect(1, 1);
1629  RenderPass::Id root_pass_id(1, 0);
1630  TestRenderPass* root_pass;
1631
1632  gfx::Transform transform_preventing_aa;
1633  transform_preventing_aa.ApplyPerspectiveDepth(40.0);
1634  transform_preventing_aa.RotateAboutYAxis(-20.0);
1635  transform_preventing_aa.Scale(30.0, 1.0);
1636
1637  // Verify that the test transform and test rect actually do cause the clipped
1638  // flag to trigger. Otherwise we are not testing the intended scenario.
1639  bool clipped = false;
1640  MathUtil::MapQuad(transform_preventing_aa, gfx::QuadF(child_rect), &clipped);
1641  ASSERT_TRUE(clipped);
1642
1643  child_pass = AddRenderPass(&render_passes_in_draw_order_,
1644                             child_pass_id,
1645                             child_rect,
1646                             transform_preventing_aa);
1647
1648  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1649                            root_pass_id,
1650                            viewport_rect,
1651                            gfx::Transform());
1652
1653  AddRenderPassQuad(
1654      root_pass, child_pass, 0, FilterOperations(), transform_preventing_aa);
1655
1656  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1657  renderer_->DrawFrame(&render_passes_in_draw_order_,
1658                       NULL,
1659                       1.f,
1660                       viewport_rect,
1661                       viewport_rect,
1662                       true,
1663                       false);
1664
1665  // If use_aa incorrectly ignores clipping, it will use the
1666  // RenderPassProgramAA shader instead of the RenderPassProgram.
1667  TestRenderPassProgram(TexCoordPrecisionMedium);
1668}
1669
1670TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
1671  gfx::Rect viewport_rect(1, 1);
1672  RenderPass::Id root_pass_id(1, 0);
1673  TestRenderPass* root_pass;
1674
1675  gfx::Transform pixel_aligned_transform_causing_aa;
1676  pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f);
1677  pixel_aligned_transform_causing_aa.Scale(0.5f, 0.5f);
1678
1679  root_pass = AddRenderPass(&render_passes_in_draw_order_,
1680                            root_pass_id,
1681                            viewport_rect,
1682                            gfx::Transform());
1683  AddTransformedQuad(root_pass,
1684                     viewport_rect,
1685                     SK_ColorYELLOW,
1686                     pixel_aligned_transform_causing_aa);
1687
1688  renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
1689  renderer_->DrawFrame(&render_passes_in_draw_order_,
1690                       NULL,
1691                       1.f,
1692                       viewport_rect,
1693                       viewport_rect,
1694                       true,
1695                       false);
1696
1697  TestSolidColorProgramAA();
1698}
1699
1700class OutputSurfaceMockContext : public TestWebGraphicsContext3D {
1701 public:
1702  OutputSurfaceMockContext() {
1703    test_capabilities_.post_sub_buffer = true;
1704  }
1705
1706  // Specifically override methods even if they are unused (used in conjunction
1707  // with StrictMock). We need to make sure that GLRenderer does not issue
1708  // framebuffer-related GL calls directly. Instead these are supposed to go
1709  // through the OutputSurface abstraction.
1710  MOCK_METHOD2(bindFramebuffer, void(WGC3Denum target, WebGLId framebuffer));
1711  MOCK_METHOD3(reshapeWithScaleFactor,
1712               void(int width, int height, float scale_factor));
1713  MOCK_METHOD4(drawElements,
1714               void(WGC3Denum mode,
1715                    WGC3Dsizei count,
1716                    WGC3Denum type,
1717                    WGC3Dintptr offset));
1718};
1719
1720class MockOutputSurface : public OutputSurface {
1721 public:
1722  MockOutputSurface()
1723      : OutputSurface(
1724            TestContextProvider::Create(scoped_ptr<TestWebGraphicsContext3D>(
1725                new StrictMock<OutputSurfaceMockContext>))) {
1726    surface_size_ = gfx::Size(100, 100);
1727  }
1728  virtual ~MockOutputSurface() {}
1729
1730  MOCK_METHOD0(EnsureBackbuffer, void());
1731  MOCK_METHOD0(DiscardBackbuffer, void());
1732  MOCK_METHOD2(Reshape, void(gfx::Size size, float scale_factor));
1733  MOCK_METHOD0(BindFramebuffer, void());
1734  MOCK_METHOD1(SwapBuffers, void(CompositorFrame* frame));
1735};
1736
1737class MockOutputSurfaceTest : public GLRendererTest {
1738 protected:
1739  virtual void SetUp() {
1740    FakeOutputSurfaceClient output_surface_client_;
1741    CHECK(output_surface_.BindToClient(&output_surface_client_));
1742
1743    resource_provider_ =
1744        ResourceProvider::Create(&output_surface_, NULL, 0, false, 1).Pass();
1745
1746    renderer_.reset(new FakeRendererGL(&renderer_client_,
1747                                       &settings_,
1748                                       &output_surface_,
1749                                       resource_provider_.get()));
1750  }
1751
1752  void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
1753
1754  void DrawFrame(float device_scale_factor, gfx::Rect device_viewport_rect) {
1755    RenderPass::Id render_pass_id(1, 0);
1756    TestRenderPass* render_pass = AddRenderPass(&render_passes_in_draw_order_,
1757                                                render_pass_id,
1758                                                device_viewport_rect,
1759                                                gfx::Transform());
1760    AddQuad(render_pass, device_viewport_rect, SK_ColorGREEN);
1761
1762    EXPECT_CALL(output_surface_, EnsureBackbuffer()).WillRepeatedly(Return());
1763
1764    EXPECT_CALL(output_surface_,
1765                Reshape(device_viewport_rect.size(), device_scale_factor))
1766        .Times(1);
1767
1768    EXPECT_CALL(output_surface_, BindFramebuffer()).Times(1);
1769
1770    EXPECT_CALL(*Context(), drawElements(_, _, _, _)).Times(1);
1771
1772    renderer_->DecideRenderPassAllocationsForFrame(
1773        render_passes_in_draw_order_);
1774    renderer_->DrawFrame(&render_passes_in_draw_order_,
1775                         NULL,
1776                         device_scale_factor,
1777                         device_viewport_rect,
1778                         device_viewport_rect,
1779                         true,
1780                         false);
1781  }
1782
1783  OutputSurfaceMockContext* Context() {
1784    return static_cast<OutputSurfaceMockContext*>(
1785        output_surface_.context_provider()->Context3d());
1786  }
1787
1788  LayerTreeSettings settings_;
1789  FakeOutputSurfaceClient output_surface_client_;
1790  StrictMock<MockOutputSurface> output_surface_;
1791  scoped_ptr<ResourceProvider> resource_provider_;
1792  FakeRendererClient renderer_client_;
1793  scoped_ptr<FakeRendererGL> renderer_;
1794};
1795
1796TEST_F(MockOutputSurfaceTest, DrawFrameAndSwap) {
1797  gfx::Rect device_viewport_rect(1, 1);
1798  DrawFrame(1.f, device_viewport_rect);
1799
1800  EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
1801  renderer_->SwapBuffers(CompositorFrameMetadata());
1802}
1803
1804TEST_F(MockOutputSurfaceTest, DrawFrameAndResizeAndSwap) {
1805  gfx::Rect device_viewport_rect(1, 1);
1806
1807  DrawFrame(1.f, device_viewport_rect);
1808  EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
1809  renderer_->SwapBuffers(CompositorFrameMetadata());
1810
1811  device_viewport_rect = gfx::Rect(2, 2);
1812
1813  DrawFrame(2.f, device_viewport_rect);
1814  EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
1815  renderer_->SwapBuffers(CompositorFrameMetadata());
1816
1817  DrawFrame(2.f, device_viewport_rect);
1818  EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
1819  renderer_->SwapBuffers(CompositorFrameMetadata());
1820
1821  device_viewport_rect = gfx::Rect(1, 1);
1822
1823  DrawFrame(1.f, device_viewport_rect);
1824  EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
1825  renderer_->SwapBuffers(CompositorFrameMetadata());
1826}
1827
1828class GLRendererTestSyncPoint : public GLRendererPixelTest {
1829 protected:
1830  static void SyncPointCallback(int* callback_count) {
1831    ++(*callback_count);
1832    base::MessageLoop::current()->QuitWhenIdle();
1833  }
1834
1835  static void OtherCallback(int* callback_count) {
1836    ++(*callback_count);
1837    base::MessageLoop::current()->QuitWhenIdle();
1838  }
1839};
1840
1841#if !defined(OS_ANDROID)
1842TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) {
1843  int sync_point_callback_count = 0;
1844  int other_callback_count = 0;
1845  blink::WebGraphicsContext3D* context3d =
1846      output_surface_->context_provider()->Context3d();
1847  gpu::ContextSupport* context_support =
1848      output_surface_->context_provider()->ContextSupport();
1849
1850  uint32 sync_point = context3d->insertSyncPoint();
1851
1852  context3d->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
1853                                 GL_INNOCENT_CONTEXT_RESET_ARB);
1854
1855  context_support->SignalSyncPoint(
1856      sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count));
1857  EXPECT_EQ(0, sync_point_callback_count);
1858  EXPECT_EQ(0, other_callback_count);
1859
1860  // Make the sync point happen.
1861  context3d->finish();
1862  // Post a task after the sync point.
1863  base::MessageLoop::current()->PostTask(
1864      FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
1865
1866  base::MessageLoop::current()->Run();
1867
1868  // The sync point shouldn't have happened since the context was lost.
1869  EXPECT_EQ(0, sync_point_callback_count);
1870  EXPECT_EQ(1, other_callback_count);
1871}
1872
1873TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) {
1874  int sync_point_callback_count = 0;
1875  int other_callback_count = 0;
1876
1877  blink::WebGraphicsContext3D* context3d =
1878      output_surface_->context_provider()->Context3d();
1879  gpu::ContextSupport* context_support =
1880      output_surface_->context_provider()->ContextSupport();
1881
1882  uint32 sync_point = context3d->insertSyncPoint();
1883
1884  context_support->SignalSyncPoint(
1885      sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count));
1886  EXPECT_EQ(0, sync_point_callback_count);
1887  EXPECT_EQ(0, other_callback_count);
1888
1889  // Make the sync point happen.
1890  context3d->finish();
1891  // Post a task after the sync point.
1892  base::MessageLoop::current()->PostTask(
1893      FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
1894
1895  base::MessageLoop::current()->Run();
1896
1897  // The sync point should have happened.
1898  EXPECT_EQ(1, sync_point_callback_count);
1899  EXPECT_EQ(1, other_callback_count);
1900}
1901#endif  // OS_ANDROID
1902
1903}  // namespace
1904}  // namespace cc
1905