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