diff options
-rw-r--r-- | cc/output/output_surface.cc | 56 | ||||
-rw-r--r-- | cc/output/output_surface.h | 14 | ||||
-rw-r--r-- | cc/output/output_surface_unittest.cc | 97 |
3 files changed, 154 insertions, 13 deletions
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc index 1be41892..84d94b8 100644 --- a/cc/output/output_surface.cc +++ b/cc/output/output_surface.cc @@ -30,7 +30,9 @@ class OutputSurfaceCallbacks public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback { public: explicit OutputSurfaceCallbacks(OutputSurfaceClient* client) - : client_(client) {} + : client_(client) { + DCHECK(client_); + } // WK:WGC3D::WGSwapBuffersCompleteCallbackCHROMIUM implementation. virtual void onSwapBuffersComplete() { client_->OnSwapBuffersComplete(); } @@ -78,24 +80,60 @@ bool OutputSurface::ForcedDrawToSoftwareDevice() const { bool OutputSurface::BindToClient( cc::OutputSurfaceClient* client) { DCHECK(client); - if (context3d_ && !context3d_->makeContextCurrent()) - return false; client_ = client; - if (!context3d_) - return true; - string extensions_string = UTF16ToASCII(context3d_->getString(GL_EXTENSIONS)); + bool success = true; + + if (context3d_) { + success = context3d_->makeContextCurrent(); + if (success) + SetContext3D(context3d_.Pass()); + } + + if (!success) + client_ = NULL; + + return success; +} + +bool OutputSurface::InitializeAndSetContext3D( + scoped_ptr<WebKit::WebGraphicsContext3D> context3d, + scoped_refptr<ContextProvider> offscreen_context_provider) { + DCHECK(!context3d_); + DCHECK(context3d); + DCHECK(client_); + + bool success = false; + if (context3d->makeContextCurrent()) { + SetContext3D(context3d.Pass()); + if (client_->DeferredInitialize(offscreen_context_provider)) + success = true; + } + + if (!success) { + context3d_.reset(); + callbacks_.reset(); + } + + return success; +} + +void OutputSurface::SetContext3D( + scoped_ptr<WebKit::WebGraphicsContext3D> context3d) { + DCHECK(!context3d_); + DCHECK(context3d); + DCHECK(client_); + + string extensions_string = UTF16ToASCII(context3d->getString(GL_EXTENSIONS)); vector<string> extensions_list; base::SplitString(extensions_string, ' ', &extensions_list); set<string> extensions(extensions_list.begin(), extensions_list.end()); - has_gl_discard_backbuffer_ = extensions.count("GL_CHROMIUM_discard_backbuffer") > 0; + context3d_ = context3d.Pass(); callbacks_.reset(new OutputSurfaceCallbacks(client_)); context3d_->setSwapBuffersCompleteCallbackCHROMIUM(callbacks_.get()); context3d_->setContextLostCallback(callbacks_.get()); - - return true; } void OutputSurface::SendFrameToParentCompositor(CompositorFrame* frame) { diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h index 00877de..fb93eb7 100644 --- a/cc/output/output_surface.h +++ b/cc/output/output_surface.h @@ -6,8 +6,10 @@ #define CC_OUTPUT_OUTPUT_SURFACE_H_ #include "base/basictypes.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "cc/output/context_provider.h" #include "cc/output/software_output_device.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" @@ -106,17 +108,25 @@ class CC_EXPORT OutputSurface { virtual void SetNeedsBeginFrame(bool enable) {} protected: + // Synchronously initialize context3d and enter hardware mode. + // This can only supported in threaded compositing mode. + // |offscreen_context_provider| should match what is returned by + // LayerTreeClient::OffscreenContextProviderForCompositorThread. + bool InitializeAndSetContext3D( + scoped_ptr<WebKit::WebGraphicsContext3D> context3d, + scoped_refptr<ContextProvider> offscreen_context_provider); + OutputSurfaceClient* client_; struct cc::OutputSurface::Capabilities capabilities_; + scoped_ptr<OutputSurfaceCallbacks> callbacks_; scoped_ptr<WebKit::WebGraphicsContext3D> context3d_; scoped_ptr<cc::SoftwareOutputDevice> software_device_; bool has_gl_discard_backbuffer_; gfx::Size surface_size_; float device_scale_factor_; - scoped_ptr<OutputSurfaceCallbacks> callbacks_; - private: + void SetContext3D(scoped_ptr<WebKit::WebGraphicsContext3D> context3d); DISALLOW_COPY_AND_ASSIGN(OutputSurface); }; diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc index 1d365d9..72bf0a4 100644 --- a/cc/output/output_surface_unittest.cc +++ b/cc/output/output_surface_unittest.cc @@ -4,7 +4,9 @@ #include "cc/output/output_surface.h" #include "cc/output/output_surface_client.h" +#include "cc/output/software_output_device.h" #include "cc/test/test_web_graphics_context_3d.h" +#include "gpu/GLES2/gl2extchromium.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -24,13 +26,25 @@ class TestOutputSurface : public OutputSurface { : 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>()); + } }; class FakeOutputSurfaceClient : public OutputSurfaceClient { public: + FakeOutputSurfaceClient() + : deferred_initialize_result_(true), + deferred_initialize_called_(false), + did_lose_output_surface_called_(false) {} + virtual bool DeferredInitialize( scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE { - return true; + deferred_initialize_called_ = true; + return deferred_initialize_result_; } virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {} virtual void OnVSyncParametersChanged(base::TimeTicks timebase, @@ -39,9 +53,28 @@ class FakeOutputSurfaceClient : public OutputSurfaceClient { virtual void OnSendFrameToParentCompositorAck(const CompositorFrameAck& ack) OVERRIDE {} virtual void OnSwapBuffersComplete() OVERRIDE {} - virtual void DidLoseOutputSurface() OVERRIDE {} + virtual void DidLoseOutputSurface() OVERRIDE { + did_lose_output_surface_called_ = true; + } virtual void SetExternalDrawConstraints(const gfx::Transform& transform, gfx::Rect viewport) OVERRIDE {} + + void set_deferred_initialize_result(bool result) { + deferred_initialize_result_ = result; + } + + bool deferred_initialize_called() { + return deferred_initialize_called_; + } + + bool did_lose_output_surface_called() { + return did_lose_output_surface_called_; + } + + private: + bool deferred_initialize_result_; + bool deferred_initialize_called_; + bool did_lose_output_surface_called_; }; TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) { @@ -55,6 +88,13 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) { FakeOutputSurfaceClient client; EXPECT_TRUE(output_surface.BindToClient(&client)); EXPECT_EQ(&client, output_surface.client()); + EXPECT_FALSE(client.deferred_initialize_called()); + + // Verify DidLoseOutputSurface callback is hooked up correctly. + EXPECT_FALSE(client.did_lose_output_surface_called()); + output_surface.context3d()->loseContextCHROMIUM( + GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); + EXPECT_TRUE(client.did_lose_output_surface_called()); } TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) { @@ -73,5 +113,58 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) { EXPECT_EQ(NULL, output_surface.client()); } +class InitializeNewContext3D : public ::testing::Test { + public: + InitializeNewContext3D() + : context3d_(TestWebGraphicsContext3D::Create()), + output_surface_( + scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {} + + protected: + void BindOutputSurface() { + EXPECT_TRUE(output_surface_.BindToClient(&client_)); + EXPECT_EQ(&client_, output_surface_.client()); + } + + void InitializeNewContextExpectFail() { + EXPECT_FALSE(output_surface_.InitializeNewContext3D( + context3d_.PassAs<WebKit::WebGraphicsContext3D>())); + EXPECT_EQ(&client_, output_surface_.client()); + + EXPECT_FALSE(output_surface_.context3d()); + EXPECT_TRUE(output_surface_.software_device()); + } + + scoped_ptr<TestWebGraphicsContext3D> context3d_; + TestOutputSurface output_surface_; + FakeOutputSurfaceClient client_; +}; + +TEST_F(InitializeNewContext3D, Success) { + BindOutputSurface(); + EXPECT_FALSE(client_.deferred_initialize_called()); + + EXPECT_TRUE(output_surface_.InitializeNewContext3D( + context3d_.PassAs<WebKit::WebGraphicsContext3D>())); + EXPECT_TRUE(client_.deferred_initialize_called()); + + EXPECT_FALSE(client_.did_lose_output_surface_called()); + output_surface_.context3d()->loseContextCHROMIUM( + GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); + EXPECT_TRUE(client_.did_lose_output_surface_called()); +} + +TEST_F(InitializeNewContext3D, Context3dMakeCurrentFails) { + BindOutputSurface(); + context3d_->set_times_make_current_succeeds(0); + InitializeNewContextExpectFail(); +} + +TEST_F(InitializeNewContext3D, ClientDeferredInitializeFails) { + BindOutputSurface(); + client_.set_deferred_initialize_result(false); + InitializeNewContextExpectFail(); +} + } // namespace } // namespace cc |