diff options
author | boliu <boliu@chromium.org> | 2014-12-10 16:54:41 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-12-11 00:55:03 +0000 |
commit | ec5d6de3135398882a0975c95de98d5111aa6c2e (patch) | |
tree | fb4ef88deca5e11943a3ae1ea54a9bb77dee7ba8 | |
parent | 9015c8b4419268a35a5c1a0f2afb7a2a2aaff699 (diff) | |
download | chromium_src-ec5d6de3135398882a0975c95de98d5111aa6c2e.zip chromium_src-ec5d6de3135398882a0975c95de98d5111aa6c2e.tar.gz chromium_src-ec5d6de3135398882a0975c95de98d5111aa6c2e.tar.bz2 |
aw: Rendering test harness and end-to-end smoke test
The test harness is heavily modelled after LayerTreeTests in
cc.
Add implementation for simulating invalidation and functor
behavior. Add in enough hooks to allow a end-to-end smoke
test from invalidation to draw to functor draw.
BUG=418346
Review URL: https://codereview.chromium.org/786533002
Cr-Commit-Position: refs/heads/master@{#307812}
-rw-r--r-- | android_webview/android_webview_tests.gypi | 3 | ||||
-rw-r--r-- | android_webview/browser/browser_view_renderer_unittest.cc | 20 | ||||
-rw-r--r-- | android_webview/browser/test/fake_window.cc | 235 | ||||
-rw-r--r-- | android_webview/browser/test/fake_window.h | 94 | ||||
-rw-r--r-- | android_webview/browser/test/rendering_test.cc | 51 | ||||
-rw-r--r-- | android_webview/browser/test/rendering_test.h | 39 | ||||
-rw-r--r-- | android_webview/lib/DEPS | 1 | ||||
-rw-r--r-- | android_webview/lib/main/webview_tests.cc | 5 |
8 files changed, 415 insertions, 33 deletions
diff --git a/android_webview/android_webview_tests.gypi b/android_webview/android_webview_tests.gypi index 2dc3c7b..2e1ba0e 100644 --- a/android_webview/android_webview_tests.gypi +++ b/android_webview/android_webview_tests.gypi @@ -113,6 +113,7 @@ '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', '../ui/base/ui_base.gyp:ui_base_jni_headers', + '../ui/gl/gl.gyp:gl', 'android_webview_common', 'android_webview_unittests_jni', ], @@ -127,6 +128,8 @@ 'browser/browser_view_renderer_unittest.cc', 'browser/net/android_stream_reader_url_request_job_unittest.cc', 'browser/net/input_stream_reader_unittest.cc', + 'browser/test/fake_window.cc', + 'browser/test/fake_window.h', 'browser/test/rendering_test.cc', 'browser/test/rendering_test.h', 'lib/main/webview_tests.cc', diff --git a/android_webview/browser/browser_view_renderer_unittest.cc b/android_webview/browser/browser_view_renderer_unittest.cc index 6ecf99a..0c2786b 100644 --- a/android_webview/browser/browser_view_renderer_unittest.cc +++ b/android_webview/browser/browser_view_renderer_unittest.cc @@ -2,13 +2,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "android_webview/browser/browser_view_renderer.h" #include "android_webview/browser/test/rendering_test.h" namespace android_webview { -TEST_F(RenderingTest, SmokeTest) { - SetUpTestHarness(); - RunTest(); -} +class SmokeTest : public RenderingTest { + void StartTest() override { + browser_view_renderer_->SetContinuousInvalidate(true); + } + + void WillOnDraw() override { + browser_view_renderer_->SetContinuousInvalidate(false); + } + + void DidDrawOnRT(SharedRendererState* functor) override { + EndTest(); + } +}; + +RENDERING_TEST_F(SmokeTest); } // namespace android_webview diff --git a/android_webview/browser/test/fake_window.cc b/android_webview/browser/test/fake_window.cc new file mode 100644 index 0000000..c709f62e --- /dev/null +++ b/android_webview/browser/test/fake_window.cc @@ -0,0 +1,235 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/browser/test/fake_window.h" + +#include "android_webview/browser/browser_view_renderer.h" +#include "android_webview/public/browser/draw_gl.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "ui/gl/gl_bindings.h" + +namespace android_webview { + +class FakeWindow::ScopedMakeCurrent { + public: + ScopedMakeCurrent(FakeWindow* view_root) : view_root_(view_root) { + DCHECK(!view_root_->context_current_); + view_root_->context_current_ = true; + bool result = view_root_->context_->MakeCurrent(view_root_->surface_.get()); + DCHECK(result); + }; + + ~ScopedMakeCurrent() { + DCHECK(view_root_->context_current_); + view_root_->context_current_ = false; + + // Release the underlying EGLContext. This is required because the real + // GLContextEGL may no longer be current here and to satisfy DCHECK in + // GLContextEGL::IsCurrent. + eglMakeCurrent(view_root_->surface_->GetDisplay(), EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT); + view_root_->context_->ReleaseCurrent(view_root_->surface_.get()); + } + + private: + FakeWindow* view_root_; +}; + +FakeWindow::FakeWindow(BrowserViewRenderer* view, + WindowHooks* hooks, + gfx::Rect location) + : view_(view), + hooks_(hooks), + surface_size_(100, 100), + location_(location), + on_draw_hardware_pending_(false), + functor_(nullptr), + context_current_(false), + weak_ptr_factory_(this) { + CheckCurrentlyOnUIThread(); + DCHECK(view_); + view_->OnAttachedToWindow(location_.width(), location_.height()); +} + +FakeWindow::~FakeWindow() { + CheckCurrentlyOnUIThread(); +} + +void FakeWindow::Detach() { + CheckCurrentlyOnUIThread(); + view_->OnDetachedFromWindow(); + + if (render_thread_loop_) { + base::WaitableEvent completion(true, false); + render_thread_loop_->PostTask( + FROM_HERE, base::Bind(&FakeWindow::DestroyOnRT, base::Unretained(this), + &completion)); + completion.Wait(); + } + + render_thread_.reset(); + functor_ = nullptr; +} + +void FakeWindow::RequestDrawGL(bool wait_for_completion) { + CheckCurrentlyOnUIThread(); + base::WaitableEvent completion(true, false); + render_thread_loop_->PostTask( + FROM_HERE, + base::Bind(&FakeWindow::ProcessFunctorOnRT, base::Unretained(this), + wait_for_completion ? &completion : nullptr)); + if (wait_for_completion) + completion.Wait(); +} + +void FakeWindow::ProcessFunctorOnRT(base::WaitableEvent* sync) { + CheckCurrentlyOnRT(); + AwDrawGLInfo process_info; + process_info.version = kAwDrawGLInfoVersion; + process_info.mode = AwDrawGLInfo::kModeProcess; + + hooks_->WillProcessOnRT(functor_); + { + ScopedMakeCurrent make_current(this); + functor_->DrawGL(&process_info); + } + hooks_->DidProcessOnRT(functor_); + + if (sync) + sync->Signal(); +} + +void FakeWindow::PostInvalidate() { + CheckCurrentlyOnUIThread(); + if (on_draw_hardware_pending_) + return; + on_draw_hardware_pending_ = true; + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, + base::Bind(&FakeWindow::OnDrawHardware, weak_ptr_factory_.GetWeakPtr())); +} + +void FakeWindow::OnDrawHardware() { + CheckCurrentlyOnUIThread(); + DCHECK(on_draw_hardware_pending_); + on_draw_hardware_pending_ = false; + + bool success = view_->OnDrawHardware(); + if (success) { + CreateRenderThreadIfNeeded(); + + base::WaitableEvent completion(true, false); + render_thread_loop_->PostTask( + FROM_HERE, base::Bind(&FakeWindow::DrawFunctorOnRT, + base::Unretained(this), &completion)); + completion.Wait(); + } +} + +void FakeWindow::DrawFunctorOnRT(base::WaitableEvent* sync) { + CheckCurrentlyOnRT(); + // Ok to access UI functions until sync is signalled. + gfx::Rect location = location_; + { + AwDrawGLInfo process_info; + process_info.version = kAwDrawGLInfoVersion; + process_info.mode = AwDrawGLInfo::kModeSync; + + hooks_->WillSyncOnRT(functor_); + functor_->DrawGL(&process_info); + hooks_->DidSyncOnRT(functor_); + } + sync->Signal(); + + AwDrawGLInfo draw_info; + draw_info.version = kAwDrawGLInfoVersion; + draw_info.mode = AwDrawGLInfo::kModeDraw; + draw_info.clip_left = location.x(); + draw_info.clip_top = location.y(); + draw_info.clip_right = location.x() + location.width(); + draw_info.clip_bottom = location.y() + location.height(); + draw_info.width = surface_size_.width(); + draw_info.height = surface_size_.height(); + draw_info.is_layer = false; + + draw_info.transform[0] = 1.0; + draw_info.transform[1] = 0.0; + draw_info.transform[2] = 0.0; + draw_info.transform[3] = 0.0; + + draw_info.transform[4] = 0.0; + draw_info.transform[5] = 1.0; + draw_info.transform[6] = 0.0; + draw_info.transform[7] = 0.0; + + draw_info.transform[8] = 0.0; + draw_info.transform[9] = 0.0; + draw_info.transform[10] = 1.0; + draw_info.transform[11] = 0.0; + + draw_info.transform[12] = 0.0; + draw_info.transform[13] = 0.0; + draw_info.transform[14] = 0.0; + draw_info.transform[15] = 1.0; + + hooks_->WillDrawOnRT(functor_); + { + ScopedMakeCurrent make_current(this); + functor_->DrawGL(&draw_info); + } + hooks_->DidDrawOnRT(functor_); +} + +void FakeWindow::CheckCurrentlyOnUIThread() { + DCHECK(ui_checker_.CalledOnValidSequencedThread()); +} + +void FakeWindow::CreateRenderThreadIfNeeded() { + CheckCurrentlyOnUIThread(); + if (functor_) { + DCHECK(render_thread_.get()); + DCHECK(render_thread_loop_.get()); + return; + } + functor_ = view_->GetAwDrawGLViewContext(); + render_thread_.reset(new base::Thread("TestRenderThread")); + render_thread_->Start(); + render_thread_loop_ = render_thread_->task_runner(); + rt_checker_.DetachFromSequence(); + + base::WaitableEvent completion(true, false); + render_thread_loop_->PostTask( + FROM_HERE, base::Bind(&FakeWindow::InitializeOnRT, base::Unretained(this), + &completion)); + completion.Wait(); +} + +void FakeWindow::InitializeOnRT(base::WaitableEvent* sync) { + CheckCurrentlyOnRT(); + surface_ = gfx::GLSurface::CreateOffscreenGLSurface(surface_size_); + DCHECK(surface_.get()); + DCHECK(surface_->GetHandle()); + context_ = gfx::GLContext::CreateGLContext(nullptr, surface_.get(), + gfx::PreferDiscreteGpu); + DCHECK(context_.get()); + sync->Signal(); +} + +void FakeWindow::DestroyOnRT(base::WaitableEvent* sync) { + CheckCurrentlyOnRT(); + if (context_) { + DCHECK(!context_->IsCurrent(surface_.get())); + context_ = nullptr; + surface_ = nullptr; + } + sync->Signal(); +} + +void FakeWindow::CheckCurrentlyOnRT() { + DCHECK(rt_checker_.CalledOnValidSequencedThread()); +} + +} // namespace android_webview diff --git a/android_webview/browser/test/fake_window.h b/android_webview/browser/test/fake_window.h new file mode 100644 index 0000000..abe9ec0 --- /dev/null +++ b/android_webview/browser/test/fake_window.h @@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_BROWSER_TEST_FAKE_WINDOW_H_ +#define ANDROID_WEBVIEW_BROWSER_TEST_FAKE_WINDOW_H_ + +#include <map> + +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "base/single_thread_task_runner.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_surface.h" + +namespace base { +class Thread; +class WaitableEvent; +} + +namespace android_webview { + +class BrowserViewRenderer; +class SharedRendererState; + +class WindowHooks { + public: + virtual ~WindowHooks() {} + + virtual void WillOnDraw() = 0; + virtual void DidOnDraw() = 0; + + virtual void WillSyncOnRT(SharedRendererState* functor) = 0; + virtual void DidSyncOnRT(SharedRendererState* functor) = 0; + virtual void WillProcessOnRT(SharedRendererState* functor) = 0; + virtual void DidProcessOnRT(SharedRendererState* functor) = 0; + virtual void WillDrawOnRT(SharedRendererState* functor) = 0; + virtual void DidDrawOnRT(SharedRendererState* functor) = 0; +}; + +class FakeWindow { + public: + FakeWindow(BrowserViewRenderer* view, + WindowHooks* hooks, + gfx::Rect location); + ~FakeWindow(); + + void Detach(); + + // BrowserViewRendererClient methods. + void RequestDrawGL(bool wait_for_completion); + void PostInvalidate(); + + private: + class ScopedMakeCurrent; + + void OnDrawHardware(); + void CheckCurrentlyOnUIThread(); + void CreateRenderThreadIfNeeded(); + + void InitializeOnRT(base::WaitableEvent* sync); + void DestroyOnRT(base::WaitableEvent* sync); + void ProcessFunctorOnRT(base::WaitableEvent* sync); + void DrawFunctorOnRT(base::WaitableEvent* sync); + void CheckCurrentlyOnRT(); + + // const so can be used on both threads. + BrowserViewRenderer* const view_; + WindowHooks* const hooks_; + const gfx::Size surface_size_; + + // UI thread members. + gfx::Rect location_; + bool on_draw_hardware_pending_; + base::SequenceChecker ui_checker_; + + // Render thread members. + scoped_ptr<base::Thread> render_thread_; + base::SequenceChecker rt_checker_; + SharedRendererState* functor_; + scoped_refptr<base::SingleThreadTaskRunner> render_thread_loop_; + scoped_refptr<gfx::GLSurface> surface_; + scoped_refptr<gfx::GLContext> context_; + bool context_current_; + + base::WeakPtrFactory<FakeWindow> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(FakeWindow); +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_TEST_FAKE_WINDOW_H_ diff --git a/android_webview/browser/test/rendering_test.cc b/android_webview/browser/test/rendering_test.cc index bea0de1..995b602 100644 --- a/android_webview/browser/test/rendering_test.cc +++ b/android_webview/browser/test/rendering_test.cc @@ -6,36 +6,27 @@ #include "android_webview/browser/browser_view_renderer.h" #include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy.h" #include "content/public/test/test_synchronous_compositor_android.h" namespace android_webview { RenderingTest::RenderingTest() : message_loop_(new base::MessageLoop) { + ui_proxy_ = base::MessageLoopProxy::current(); } RenderingTest::~RenderingTest() { + if (window_.get()) + window_->Detach(); } void RenderingTest::SetUpTestHarness() { DCHECK(!browser_view_renderer_.get()); browser_view_renderer_.reset( new BrowserViewRenderer(this, base::MessageLoopProxy::current())); + InitializeCompositor(); + Attach(); } -class RenderingTest::ScopedInitializeCompositor { - public: - explicit ScopedInitializeCompositor(RenderingTest* test) : test_(test) { - test_->InitializeCompositor(); - } - - ~ScopedInitializeCompositor() { test_->TeardownCompositor(); } - - private: - RenderingTest* test_; - DISALLOW_COPY_AND_ASSIGN(ScopedInitializeCompositor); -}; - void RenderingTest::InitializeCompositor() { DCHECK(!compositor_.get()); DCHECK(browser_view_renderer_.get()); @@ -43,25 +34,43 @@ void RenderingTest::InitializeCompositor() { compositor_->SetClient(browser_view_renderer_.get()); } -void RenderingTest::TeardownCompositor() { - DCHECK(compositor_.get()); - DCHECK(browser_view_renderer_.get()); - compositor_.reset(); +void RenderingTest::Attach() { + window_.reset( + new FakeWindow(browser_view_renderer_.get(), this, gfx::Rect(100, 100))); } void RenderingTest::RunTest() { - ScopedInitializeCompositor initialize_compositor(this); - StartTest(); + SetUpTestHarness(); + + ui_proxy_->PostTask( + FROM_HERE, base::Bind(&RenderingTest::StartTest, base::Unretained(this))); + message_loop_->Run(); +} + +void RenderingTest::StartTest() { + EndTest(); +} + +void RenderingTest::EndTest() { + ui_proxy_->PostTask(FROM_HERE, base::Bind(&RenderingTest::QuitMessageLoop, + base::Unretained(this))); +} + +void RenderingTest::QuitMessageLoop() { + DCHECK_EQ(base::MessageLoop::current(), message_loop_.get()); + message_loop_->QuitWhenIdle(); } bool RenderingTest::RequestDrawGL(bool wait_for_completion) { - return false; + window_->RequestDrawGL(wait_for_completion); + return true; } void RenderingTest::OnNewPicture() { } void RenderingTest::PostInvalidate() { + window_->PostInvalidate(); } void RenderingTest::InvalidateOnFunctorDestroy() { diff --git a/android_webview/browser/test/rendering_test.h b/android_webview/browser/test/rendering_test.h index 31347ec..e5c64ed 100644 --- a/android_webview/browser/test/rendering_test.h +++ b/android_webview/browser/test/rendering_test.h @@ -6,7 +6,9 @@ #define ANDROID_WEBVIEW_BROWSER_TEST_RENDERING_TEST_H_ #include "android_webview/browser/browser_view_renderer_client.h" +#include "android_webview/browser/test/fake_window.h" #include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop_proxy.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -20,8 +22,11 @@ class TestSynchronousCompositor; namespace android_webview { class BrowserViewRenderer; +class FakeWindow; -class RenderingTest : public testing::Test, public BrowserViewRendererClient { +class RenderingTest : public testing::Test, + public BrowserViewRendererClient, + public WindowHooks { public: // BrowserViewRendererClient overrides. bool RequestDrawGL(bool wait_for_completion) override; @@ -38,27 +43,45 @@ class RenderingTest : public testing::Test, public BrowserViewRendererClient { float max_page_scale_factor) override {} void DidOverscroll(gfx::Vector2d overscroll_delta) override {} + // WindowHooks overrides. + void WillOnDraw() override {} + void DidOnDraw() override {} + void WillSyncOnRT(SharedRendererState* functor) override {} + void DidSyncOnRT(SharedRendererState* functor) override {} + void WillProcessOnRT(SharedRendererState* functor) override {} + void DidProcessOnRT(SharedRendererState* functor) override {} + void WillDrawOnRT(SharedRendererState* functor) override {} + void DidDrawOnRT(SharedRendererState* functor) override {} + protected: RenderingTest(); ~RenderingTest() override; - void SetUpTestHarness(); + virtual void SetUpTestHarness(); + virtual void StartTest(); + void RunTest(); + void InitializeCompositor(); + void Attach(); + void EndTest(); - virtual void StartTest() {} + scoped_refptr<base::MessageLoopProxy> ui_proxy_; + scoped_ptr<BrowserViewRenderer> browser_view_renderer_; + scoped_ptr<content::TestSynchronousCompositor> compositor_; + scoped_ptr<FakeWindow> window_; private: - class ScopedInitializeCompositor; - void InitializeCompositor(); - void TeardownCompositor(); + void QuitMessageLoop(); const scoped_ptr<base::MessageLoop> message_loop_; - scoped_ptr<content::TestSynchronousCompositor> compositor_; - scoped_ptr<BrowserViewRenderer> browser_view_renderer_; DISALLOW_COPY_AND_ASSIGN(RenderingTest); }; +#define RENDERING_TEST_F(TEST_FIXTURE_NAME) \ + TEST_F(TEST_FIXTURE_NAME, RunTest) { RunTest(); } \ + class NeedsSemicolon##TEST_FIXTURE_NAME {} + } // namespace android_webview #endif // ANDROID_WEBVIEW_BROWSER_TEST_RENDERING_TEST_H_ diff --git a/android_webview/lib/DEPS b/android_webview/lib/DEPS index 4442017..ab83088 100644 --- a/android_webview/lib/DEPS +++ b/android_webview/lib/DEPS @@ -3,4 +3,5 @@ include_rules = [ "+components", # For jni registers. "+content/public", "+media/base/media_switches.h", # For media command line switches. + "+ui/gl", ] diff --git a/android_webview/lib/main/webview_tests.cc b/android_webview/lib/main/webview_tests.cc index 08109fe..0fe4b6b 100644 --- a/android_webview/lib/main/webview_tests.cc +++ b/android_webview/lib/main/webview_tests.cc @@ -4,9 +4,14 @@ #include "android_webview/native/android_webview_jni_registrar.h" #include "base/android/jni_android.h" +#include "base/command_line.h" #include "base/test/test_suite.h" +#include "content/public/common/content_switches.h" +#include "ui/gl/gl_surface.h" int main(int argc, char** argv) { android_webview::RegisterJni(base::android::AttachCurrentThread()); + CommandLine::ForCurrentProcess()->AppendSwitch(switches::kSingleProcess); + gfx::GLSurface::InitializeOneOffForTests(); return base::TestSuite(argc, argv).Run(); } |