OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/output/output_surface.h" | 5 #include "cc/output/output_surface.h" |
6 #include "cc/output/output_surface_client.h" | 6 #include "cc/output/output_surface_client.h" |
7 #include "cc/output/software_output_device.h" | 7 #include "cc/output/software_output_device.h" |
8 #include "cc/test/scheduler_test_common.h" | |
9 #include "cc/test/test_web_graphics_context_3d.h" | 8 #include "cc/test/test_web_graphics_context_3d.h" |
10 #include "gpu/GLES2/gl2extchromium.h" | 9 #include "gpu/GLES2/gl2extchromium.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
12 | 11 |
13 namespace cc { | 12 namespace cc { |
14 namespace { | 13 namespace { |
15 | 14 |
16 class TestOutputSurface : public OutputSurface { | 15 class TestOutputSurface : public OutputSurface { |
17 public: | 16 public: |
18 explicit TestOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d) | 17 explicit TestOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d) |
19 : OutputSurface(context3d.Pass()) {} | 18 : OutputSurface(context3d.Pass()) {} |
20 | 19 |
21 explicit TestOutputSurface( | 20 explicit TestOutputSurface( |
22 scoped_ptr<cc::SoftwareOutputDevice> software_device) | 21 scoped_ptr<cc::SoftwareOutputDevice> software_device) |
23 : OutputSurface(software_device.Pass()) {} | 22 : OutputSurface(software_device.Pass()) {} |
24 | 23 |
25 TestOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d, | 24 TestOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d, |
26 scoped_ptr<cc::SoftwareOutputDevice> software_device) | 25 scoped_ptr<cc::SoftwareOutputDevice> software_device) |
27 : OutputSurface(context3d.Pass(), software_device.Pass()) {} | 26 : OutputSurface(context3d.Pass(), software_device.Pass()) {} |
28 | 27 |
| 28 OutputSurfaceClient* client() { return client_; } |
| 29 |
29 bool InitializeNewContext3D( | 30 bool InitializeNewContext3D( |
30 scoped_ptr<WebKit::WebGraphicsContext3D> new_context3d) { | 31 scoped_ptr<WebKit::WebGraphicsContext3D> new_context3d) { |
31 return InitializeAndSetContext3D(new_context3d.Pass(), | 32 return InitializeAndSetContext3D(new_context3d.Pass(), |
32 scoped_refptr<ContextProvider>()); | 33 scoped_refptr<ContextProvider>()); |
33 } | 34 } |
34 | |
35 bool HasClientForTesting() { | |
36 return HasClient(); | |
37 } | |
38 | |
39 void OnVSyncParametersChangedForTesting(base::TimeTicks timebase, | |
40 base::TimeDelta interval) { | |
41 OnVSyncParametersChanged(timebase, interval); | |
42 } | |
43 | |
44 void BeginFrameForTesting(base::TimeTicks frame_time) { | |
45 BeginFrame(frame_time); | |
46 } | |
47 | |
48 void DidSwapBuffersForTesting() { | |
49 DidSwapBuffers(); | |
50 } | |
51 | |
52 int pending_swap_buffers() { | |
53 return pending_swap_buffers_; | |
54 } | |
55 | |
56 void OnSwapBuffersCompleteForTesting() { | |
57 OnSwapBuffersComplete(NULL); | |
58 } | |
59 }; | 35 }; |
60 | 36 |
61 class FakeOutputSurfaceClient : public OutputSurfaceClient { | 37 class FakeOutputSurfaceClient : public OutputSurfaceClient { |
62 public: | 38 public: |
63 FakeOutputSurfaceClient() | 39 FakeOutputSurfaceClient() |
64 : begin_frame_count_(0), | 40 : deferred_initialize_result_(true), |
65 deferred_initialize_result_(true), | |
66 deferred_initialize_called_(false), | 41 deferred_initialize_called_(false), |
67 did_lose_output_surface_called_(false) {} | 42 did_lose_output_surface_called_(false) {} |
68 | 43 |
69 virtual bool DeferredInitialize( | 44 virtual bool DeferredInitialize( |
70 scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE { | 45 scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE { |
71 deferred_initialize_called_ = true; | 46 deferred_initialize_called_ = true; |
72 return deferred_initialize_result_; | 47 return deferred_initialize_result_; |
73 } | 48 } |
74 virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {} | 49 virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {} |
75 virtual void BeginFrame(base::TimeTicks frame_time) OVERRIDE { | 50 virtual void OnVSyncParametersChanged(base::TimeTicks timebase, |
76 begin_frame_count_++; | 51 base::TimeDelta interval) OVERRIDE {} |
77 } | 52 virtual void BeginFrame(base::TimeTicks frame_time) OVERRIDE {} |
78 virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE {} | 53 virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE {} |
79 virtual void DidLoseOutputSurface() OVERRIDE { | 54 virtual void DidLoseOutputSurface() OVERRIDE { |
80 did_lose_output_surface_called_ = true; | 55 did_lose_output_surface_called_ = true; |
81 } | 56 } |
82 virtual void SetExternalDrawConstraints(const gfx::Transform& transform, | 57 virtual void SetExternalDrawConstraints(const gfx::Transform& transform, |
83 gfx::Rect viewport) OVERRIDE {} | 58 gfx::Rect viewport) OVERRIDE {} |
84 | 59 |
85 int begin_frame_count() { | |
86 return begin_frame_count_; | |
87 } | |
88 | |
89 void set_deferred_initialize_result(bool result) { | 60 void set_deferred_initialize_result(bool result) { |
90 deferred_initialize_result_ = result; | 61 deferred_initialize_result_ = result; |
91 } | 62 } |
92 | 63 |
93 bool deferred_initialize_called() { | 64 bool deferred_initialize_called() { |
94 return deferred_initialize_called_; | 65 return deferred_initialize_called_; |
95 } | 66 } |
96 | 67 |
97 bool did_lose_output_surface_called() { | 68 bool did_lose_output_surface_called() { |
98 return did_lose_output_surface_called_; | 69 return did_lose_output_surface_called_; |
99 } | 70 } |
100 | 71 |
101 private: | 72 private: |
102 int begin_frame_count_; | |
103 bool deferred_initialize_result_; | 73 bool deferred_initialize_result_; |
104 bool deferred_initialize_called_; | 74 bool deferred_initialize_called_; |
105 bool did_lose_output_surface_called_; | 75 bool did_lose_output_surface_called_; |
106 }; | 76 }; |
107 | 77 |
108 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) { | 78 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) { |
109 scoped_ptr<TestWebGraphicsContext3D> context3d = | 79 scoped_ptr<TestWebGraphicsContext3D> context3d = |
110 TestWebGraphicsContext3D::Create(); | 80 TestWebGraphicsContext3D::Create(); |
111 | 81 |
112 TestOutputSurface output_surface( | 82 TestOutputSurface output_surface( |
113 context3d.PassAs<WebKit::WebGraphicsContext3D>()); | 83 context3d.PassAs<WebKit::WebGraphicsContext3D>()); |
114 EXPECT_FALSE(output_surface.HasClientForTesting()); | 84 EXPECT_EQ(NULL, output_surface.client()); |
115 | 85 |
116 FakeOutputSurfaceClient client; | 86 FakeOutputSurfaceClient client; |
117 EXPECT_TRUE(output_surface.BindToClient(&client)); | 87 EXPECT_TRUE(output_surface.BindToClient(&client)); |
118 EXPECT_TRUE(output_surface.HasClientForTesting()); | 88 EXPECT_EQ(&client, output_surface.client()); |
119 EXPECT_FALSE(client.deferred_initialize_called()); | 89 EXPECT_FALSE(client.deferred_initialize_called()); |
120 | 90 |
121 // Verify DidLoseOutputSurface callback is hooked up correctly. | 91 // Verify DidLoseOutputSurface callback is hooked up correctly. |
122 EXPECT_FALSE(client.did_lose_output_surface_called()); | 92 EXPECT_FALSE(client.did_lose_output_surface_called()); |
123 output_surface.context3d()->loseContextCHROMIUM( | 93 output_surface.context3d()->loseContextCHROMIUM( |
124 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); | 94 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); |
125 EXPECT_TRUE(client.did_lose_output_surface_called()); | 95 EXPECT_TRUE(client.did_lose_output_surface_called()); |
126 } | 96 } |
127 | 97 |
128 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) { | 98 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) { |
129 scoped_ptr<TestWebGraphicsContext3D> context3d = | 99 scoped_ptr<TestWebGraphicsContext3D> context3d = |
130 TestWebGraphicsContext3D::Create(); | 100 TestWebGraphicsContext3D::Create(); |
131 | 101 |
132 // Lose the context so BindToClient fails. | 102 // Lose the context so BindToClient fails. |
133 context3d->set_times_make_current_succeeds(0); | 103 context3d->set_times_make_current_succeeds(0); |
134 | 104 |
135 TestOutputSurface output_surface( | 105 TestOutputSurface output_surface( |
136 context3d.PassAs<WebKit::WebGraphicsContext3D>()); | 106 context3d.PassAs<WebKit::WebGraphicsContext3D>()); |
137 EXPECT_FALSE(output_surface.HasClientForTesting()); | 107 EXPECT_EQ(NULL, output_surface.client()); |
138 | 108 |
139 FakeOutputSurfaceClient client; | 109 FakeOutputSurfaceClient client; |
140 EXPECT_FALSE(output_surface.BindToClient(&client)); | 110 EXPECT_FALSE(output_surface.BindToClient(&client)); |
141 EXPECT_FALSE(output_surface.HasClientForTesting()); | 111 EXPECT_EQ(NULL, output_surface.client()); |
142 } | 112 } |
143 | 113 |
144 class InitializeNewContext3D : public ::testing::Test { | 114 class InitializeNewContext3D : public ::testing::Test { |
145 public: | 115 public: |
146 InitializeNewContext3D() | 116 InitializeNewContext3D() |
147 : context3d_(TestWebGraphicsContext3D::Create()), | 117 : context3d_(TestWebGraphicsContext3D::Create()), |
148 output_surface_( | 118 output_surface_( |
149 scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {} | 119 scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {} |
150 | 120 |
151 protected: | 121 protected: |
152 void BindOutputSurface() { | 122 void BindOutputSurface() { |
153 EXPECT_TRUE(output_surface_.BindToClient(&client_)); | 123 EXPECT_TRUE(output_surface_.BindToClient(&client_)); |
154 EXPECT_TRUE(output_surface_.HasClientForTesting()); | 124 EXPECT_EQ(&client_, output_surface_.client()); |
155 } | 125 } |
156 | 126 |
157 void InitializeNewContextExpectFail() { | 127 void InitializeNewContextExpectFail() { |
158 EXPECT_FALSE(output_surface_.InitializeNewContext3D( | 128 EXPECT_FALSE(output_surface_.InitializeNewContext3D( |
159 context3d_.PassAs<WebKit::WebGraphicsContext3D>())); | 129 context3d_.PassAs<WebKit::WebGraphicsContext3D>())); |
160 EXPECT_TRUE(output_surface_.HasClientForTesting()); | 130 EXPECT_EQ(&client_, output_surface_.client()); |
161 | 131 |
162 EXPECT_FALSE(output_surface_.context3d()); | 132 EXPECT_FALSE(output_surface_.context3d()); |
163 EXPECT_TRUE(output_surface_.software_device()); | 133 EXPECT_TRUE(output_surface_.software_device()); |
164 } | 134 } |
165 | 135 |
166 scoped_ptr<TestWebGraphicsContext3D> context3d_; | 136 scoped_ptr<TestWebGraphicsContext3D> context3d_; |
167 TestOutputSurface output_surface_; | 137 TestOutputSurface output_surface_; |
168 FakeOutputSurfaceClient client_; | 138 FakeOutputSurfaceClient client_; |
169 }; | 139 }; |
170 | 140 |
(...skipping 16 matching lines...) Expand all Loading... |
187 context3d_->set_times_make_current_succeeds(0); | 157 context3d_->set_times_make_current_succeeds(0); |
188 InitializeNewContextExpectFail(); | 158 InitializeNewContextExpectFail(); |
189 } | 159 } |
190 | 160 |
191 TEST_F(InitializeNewContext3D, ClientDeferredInitializeFails) { | 161 TEST_F(InitializeNewContext3D, ClientDeferredInitializeFails) { |
192 BindOutputSurface(); | 162 BindOutputSurface(); |
193 client_.set_deferred_initialize_result(false); | 163 client_.set_deferred_initialize_result(false); |
194 InitializeNewContextExpectFail(); | 164 InitializeNewContextExpectFail(); |
195 } | 165 } |
196 | 166 |
197 TEST(OutputSurfaceTest, BeginFrameEmulation) { | |
198 scoped_ptr<TestWebGraphicsContext3D> context3d = | |
199 TestWebGraphicsContext3D::Create(); | |
200 | |
201 TestOutputSurface output_surface( | |
202 context3d.PassAs<WebKit::WebGraphicsContext3D>()); | |
203 EXPECT_FALSE(output_surface.HasClientForTesting()); | |
204 | |
205 FakeOutputSurfaceClient client; | |
206 EXPECT_TRUE(output_surface.BindToClient(&client)); | |
207 EXPECT_TRUE(output_surface.HasClientForTesting()); | |
208 EXPECT_FALSE(client.deferred_initialize_called()); | |
209 | |
210 // Initialize BeginFrame emulation | |
211 FakeThread impl_thread; | |
212 bool throttle_frame_production = true; | |
213 const base::TimeDelta display_refresh_interval = | |
214 base::TimeDelta::FromMicroseconds(16666); | |
215 | |
216 output_surface.InitializeBeginFrameEmulation( | |
217 &impl_thread, | |
218 throttle_frame_production, | |
219 display_refresh_interval); | |
220 | |
221 output_surface.SetMaxFramesPending(2); | |
222 | |
223 // We should start off with 0 BeginFrames | |
224 EXPECT_EQ(client.begin_frame_count(), 0); | |
225 EXPECT_EQ(output_surface.pending_swap_buffers(), 0); | |
226 | |
227 // We should not have a pending task until a BeginFrame has been requested. | |
228 EXPECT_FALSE(impl_thread.HasPendingTask()); | |
229 output_surface.SetNeedsBeginFrame(true); | |
230 EXPECT_TRUE(impl_thread.HasPendingTask()); | |
231 | |
232 // BeginFrame should be called on the first tick. | |
233 impl_thread.RunPendingTask(); | |
234 EXPECT_EQ(client.begin_frame_count(), 1); | |
235 EXPECT_EQ(output_surface.pending_swap_buffers(), 0); | |
236 | |
237 // BeginFrame should not be called when there is a pending BeginFrame. | |
238 impl_thread.RunPendingTask(); | |
239 EXPECT_EQ(client.begin_frame_count(), 1); | |
240 EXPECT_EQ(output_surface.pending_swap_buffers(), 0); | |
241 | |
242 // DidSwapBuffers should clear the pending BeginFrame. | |
243 output_surface.DidSwapBuffersForTesting(); | |
244 EXPECT_EQ(client.begin_frame_count(), 1); | |
245 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
246 impl_thread.RunPendingTask(); | |
247 EXPECT_EQ(client.begin_frame_count(), 2); | |
248 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
249 | |
250 // BeginFrame should be throttled by pending swap buffers. | |
251 output_surface.DidSwapBuffersForTesting(); | |
252 EXPECT_EQ(client.begin_frame_count(), 2); | |
253 EXPECT_EQ(output_surface.pending_swap_buffers(), 2); | |
254 impl_thread.RunPendingTask(); | |
255 EXPECT_EQ(client.begin_frame_count(), 2); | |
256 EXPECT_EQ(output_surface.pending_swap_buffers(), 2); | |
257 | |
258 // SwapAck should decrement pending swap buffers and unblock BeginFrame again. | |
259 output_surface.OnSwapBuffersCompleteForTesting(); | |
260 EXPECT_EQ(client.begin_frame_count(), 2); | |
261 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
262 impl_thread.RunPendingTask(); | |
263 EXPECT_EQ(client.begin_frame_count(), 3); | |
264 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
265 | |
266 // Calling SetNeedsBeginFrame again indicates a swap did not occur but | |
267 // the client still wants another BeginFrame. | |
268 output_surface.SetNeedsBeginFrame(true); | |
269 impl_thread.RunPendingTask(); | |
270 EXPECT_EQ(client.begin_frame_count(), 4); | |
271 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
272 | |
273 // Disabling SetNeedsBeginFrame should prevent further BeginFrames. | |
274 output_surface.SetNeedsBeginFrame(false); | |
275 impl_thread.RunPendingTask(); | |
276 EXPECT_FALSE(impl_thread.HasPendingTask()); | |
277 EXPECT_EQ(client.begin_frame_count(), 4); | |
278 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
279 | |
280 // Optimistically injected BeginFrames without a SetNeedsBeginFrame should be | |
281 // allowed. | |
282 output_surface.BeginFrameForTesting(base::TimeTicks::Now()); | |
283 EXPECT_EQ(client.begin_frame_count(), 5); | |
284 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
285 | |
286 // Optimistically injected BeginFrames without a SetNeedsBeginFrame should | |
287 // still be throttled by pending begin frames however. | |
288 output_surface.BeginFrameForTesting(base::TimeTicks::Now()); | |
289 EXPECT_EQ(client.begin_frame_count(), 5); | |
290 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); | |
291 | |
292 // Optimistically injected BeginFrames without a SetNeedsBeginFrame should | |
293 // also be throttled by pending swap buffers. | |
294 output_surface.DidSwapBuffersForTesting(); | |
295 EXPECT_EQ(client.begin_frame_count(), 5); | |
296 EXPECT_EQ(output_surface.pending_swap_buffers(), 2); | |
297 output_surface.BeginFrameForTesting(base::TimeTicks::Now()); | |
298 EXPECT_EQ(client.begin_frame_count(), 5); | |
299 EXPECT_EQ(output_surface.pending_swap_buffers(), 2); | |
300 } | |
301 | |
302 } // namespace | 167 } // namespace |
303 } // namespace cc | 168 } // namespace cc |
OLD | NEW |