Index: cc/output/output_surface_unittest.cc |
diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc |
index ebc018f8ea61a0b2ea37ac26c1adffd8b8673b01..7dcb1cce0fe59ea65f5f6cc51634e3c0a85a9cf5 100644 |
--- a/cc/output/output_surface_unittest.cc |
+++ b/cc/output/output_surface_unittest.cc |
@@ -5,6 +5,7 @@ |
#include "cc/output/output_surface.h" |
#include "cc/output/output_surface_client.h" |
#include "cc/output/software_output_device.h" |
+#include "cc/test/scheduler_test_common.h" |
#include "cc/test/test_web_graphics_context_3d.h" |
#include "gpu/GLES2/gl2extchromium.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -25,19 +26,43 @@ class TestOutputSurface : public OutputSurface { |
scoped_ptr<cc::SoftwareOutputDevice> software_device) |
: OutputSurface(context3d.Pass(), software_device.Pass()) {} |
- OutputSurfaceClient* client() { return client_; } |
- |
bool InitializeNewContext3D( |
scoped_ptr<WebKit::WebGraphicsContext3D> new_context3d) { |
return InitializeAndSetContext3D(new_context3d.Pass(), |
scoped_refptr<ContextProvider>()); |
} |
+ |
+ bool HasClientForTesting() { |
+ return HasClient(); |
+ } |
+ |
+ void OnVSyncParametersChangedForTesting(base::TimeTicks timebase, |
+ base::TimeDelta interval) { |
+ OnVSyncParametersChanged(timebase, interval); |
+ } |
+ |
+ void BeginFrameForTesting(base::TimeTicks frame_time) { |
+ BeginFrame(frame_time); |
+ } |
+ |
+ void DidSwapBuffersForTesting() { |
+ DidSwapBuffers(); |
+ } |
+ |
+ int pending_swap_buffers() { |
+ return pending_swap_buffers_; |
+ } |
+ |
+ void OnSwapBuffersCompleteForTesting() { |
+ OnSwapBuffersComplete(NULL); |
+ } |
}; |
class FakeOutputSurfaceClient : public OutputSurfaceClient { |
public: |
FakeOutputSurfaceClient() |
- : deferred_initialize_result_(true), |
+ : begin_frame_count_(0), |
+ deferred_initialize_result_(true), |
deferred_initialize_called_(false), |
did_lose_output_surface_called_(false) {} |
@@ -47,9 +72,9 @@ class FakeOutputSurfaceClient : public OutputSurfaceClient { |
return deferred_initialize_result_; |
} |
virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {} |
- virtual void OnVSyncParametersChanged(base::TimeTicks timebase, |
- base::TimeDelta interval) OVERRIDE {} |
- virtual void BeginFrame(base::TimeTicks frame_time) OVERRIDE {} |
+ virtual void BeginFrame(base::TimeTicks frame_time) OVERRIDE { |
+ begin_frame_count_++; |
+ } |
virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE {} |
virtual void DidLoseOutputSurface() OVERRIDE { |
did_lose_output_surface_called_ = true; |
@@ -57,6 +82,10 @@ class FakeOutputSurfaceClient : public OutputSurfaceClient { |
virtual void SetExternalDrawConstraints(const gfx::Transform& transform, |
gfx::Rect viewport) OVERRIDE {} |
+ int begin_frame_count() { |
+ return begin_frame_count_; |
+ } |
+ |
void set_deferred_initialize_result(bool result) { |
deferred_initialize_result_ = result; |
} |
@@ -70,6 +99,7 @@ class FakeOutputSurfaceClient : public OutputSurfaceClient { |
} |
private: |
+ int begin_frame_count_; |
bool deferred_initialize_result_; |
bool deferred_initialize_called_; |
bool did_lose_output_surface_called_; |
@@ -81,11 +111,11 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) { |
TestOutputSurface output_surface( |
context3d.PassAs<WebKit::WebGraphicsContext3D>()); |
- EXPECT_EQ(NULL, output_surface.client()); |
+ EXPECT_FALSE(output_surface.HasClientForTesting()); |
FakeOutputSurfaceClient client; |
EXPECT_TRUE(output_surface.BindToClient(&client)); |
- EXPECT_EQ(&client, output_surface.client()); |
+ EXPECT_TRUE(output_surface.HasClientForTesting()); |
EXPECT_FALSE(client.deferred_initialize_called()); |
// Verify DidLoseOutputSurface callback is hooked up correctly. |
@@ -104,11 +134,11 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) { |
TestOutputSurface output_surface( |
context3d.PassAs<WebKit::WebGraphicsContext3D>()); |
- EXPECT_EQ(NULL, output_surface.client()); |
+ EXPECT_FALSE(output_surface.HasClientForTesting()); |
FakeOutputSurfaceClient client; |
EXPECT_FALSE(output_surface.BindToClient(&client)); |
- EXPECT_EQ(NULL, output_surface.client()); |
+ EXPECT_FALSE(output_surface.HasClientForTesting()); |
} |
class InitializeNewContext3D : public ::testing::Test { |
@@ -121,13 +151,13 @@ class InitializeNewContext3D : public ::testing::Test { |
protected: |
void BindOutputSurface() { |
EXPECT_TRUE(output_surface_.BindToClient(&client_)); |
- EXPECT_EQ(&client_, output_surface_.client()); |
+ EXPECT_TRUE(output_surface_.HasClientForTesting()); |
} |
void InitializeNewContextExpectFail() { |
EXPECT_FALSE(output_surface_.InitializeNewContext3D( |
context3d_.PassAs<WebKit::WebGraphicsContext3D>())); |
- EXPECT_EQ(&client_, output_surface_.client()); |
+ EXPECT_TRUE(output_surface_.HasClientForTesting()); |
EXPECT_FALSE(output_surface_.context3d()); |
EXPECT_TRUE(output_surface_.software_device()); |
@@ -164,5 +194,110 @@ TEST_F(InitializeNewContext3D, ClientDeferredInitializeFails) { |
InitializeNewContextExpectFail(); |
} |
+TEST(OutputSurfaceTest, BeginFrameEmulation) { |
+ scoped_ptr<TestWebGraphicsContext3D> context3d = |
+ TestWebGraphicsContext3D::Create(); |
+ |
+ TestOutputSurface output_surface( |
+ context3d.PassAs<WebKit::WebGraphicsContext3D>()); |
+ EXPECT_FALSE(output_surface.HasClientForTesting()); |
+ |
+ FakeOutputSurfaceClient client; |
+ EXPECT_TRUE(output_surface.BindToClient(&client)); |
+ EXPECT_TRUE(output_surface.HasClientForTesting()); |
+ EXPECT_FALSE(client.deferred_initialize_called()); |
+ |
+ // Initialize BeginFrame emulation |
+ FakeThread impl_thread; |
+ bool throttle_frame_production = true; |
+ const base::TimeDelta display_refresh_interval = |
+ base::TimeDelta::FromMicroseconds(16666); |
+ |
+ output_surface.InitializeBeginFrameEmulation( |
+ &impl_thread, |
+ throttle_frame_production, |
+ display_refresh_interval); |
+ |
+ output_surface.SetMaxFramesPending(2); |
+ |
+ // We should start off with 0 BeginFrames |
+ EXPECT_EQ(client.begin_frame_count(), 0); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 0); |
+ |
+ // We should not have a pending task until a BeginFrame has been requested. |
+ EXPECT_FALSE(impl_thread.HasPendingTask()); |
+ output_surface.SetNeedsBeginFrame(true); |
+ EXPECT_TRUE(impl_thread.HasPendingTask()); |
+ |
+ // BeginFrame should be called on the first tick. |
+ impl_thread.RunPendingTask(); |
+ EXPECT_EQ(client.begin_frame_count(), 1); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 0); |
+ |
+ // BeginFrame should not be called when there is a pending BeginFrame. |
+ impl_thread.RunPendingTask(); |
+ EXPECT_EQ(client.begin_frame_count(), 1); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 0); |
+ |
+ // DidSwapBuffers should clear the pending BeginFrame. |
+ output_surface.DidSwapBuffersForTesting(); |
+ EXPECT_EQ(client.begin_frame_count(), 1); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ impl_thread.RunPendingTask(); |
+ EXPECT_EQ(client.begin_frame_count(), 2); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ |
+ // BeginFrame should be throttled by pending swap buffers. |
+ output_surface.DidSwapBuffersForTesting(); |
+ EXPECT_EQ(client.begin_frame_count(), 2); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 2); |
+ impl_thread.RunPendingTask(); |
+ EXPECT_EQ(client.begin_frame_count(), 2); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 2); |
+ |
+ // SwapAck should decrement pending swap buffers and unblock BeginFrame again. |
+ output_surface.OnSwapBuffersCompleteForTesting(); |
+ EXPECT_EQ(client.begin_frame_count(), 2); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ impl_thread.RunPendingTask(); |
+ EXPECT_EQ(client.begin_frame_count(), 3); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ |
+ // Calling SetNeedsBeginFrame again indicates a swap did not occur but |
+ // the client still wants another BeginFrame. |
+ output_surface.SetNeedsBeginFrame(true); |
+ impl_thread.RunPendingTask(); |
+ EXPECT_EQ(client.begin_frame_count(), 4); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ |
+ // Disabling SetNeedsBeginFrame should prevent further BeginFrames. |
+ output_surface.SetNeedsBeginFrame(false); |
+ impl_thread.RunPendingTask(); |
+ EXPECT_FALSE(impl_thread.HasPendingTask()); |
+ EXPECT_EQ(client.begin_frame_count(), 4); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ |
+ // Optimistically injected BeginFrames without a SetNeedsBeginFrame should be |
+ // allowed. |
+ output_surface.BeginFrameForTesting(base::TimeTicks::Now()); |
+ EXPECT_EQ(client.begin_frame_count(), 5); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ |
+ // Optimistically injected BeginFrames without a SetNeedsBeginFrame should |
+ // still be throttled by pending begin frames however. |
+ output_surface.BeginFrameForTesting(base::TimeTicks::Now()); |
+ EXPECT_EQ(client.begin_frame_count(), 5); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 1); |
+ |
+ // Optimistically injected BeginFrames without a SetNeedsBeginFrame should |
+ // also be throttled by pending swap buffers. |
+ output_surface.DidSwapBuffersForTesting(); |
+ EXPECT_EQ(client.begin_frame_count(), 5); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 2); |
+ output_surface.BeginFrameForTesting(base::TimeTicks::Now()); |
+ EXPECT_EQ(client.begin_frame_count(), 5); |
+ EXPECT_EQ(output_surface.pending_swap_buffers(), 2); |
+} |
+ |
} // namespace |
} // namespace cc |