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