| 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 |