blob: c50f75c48a3c29ec51e109ea34158c60732572ea [file] [log] [blame]
// Copyright 2017 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 "base/android/application_status_listener.h"
#include "base/android/build_info.h"
#include "base/base_switches.h"
#include "base/test/scoped_feature_list.h"
#include "components/viz/common/features.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/gpu_stream_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "content/test/gpu_browsertest_helpers.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/android/window_android.h"
#include "url/gurl.h"
namespace content {
namespace {
enum class CompositorImplMode {
kNormal,
kViz,
kVizSkDDL,
};
class CompositorImplBrowserTest
: public testing::WithParamInterface<CompositorImplMode>,
public ContentBrowserTest {
public:
CompositorImplBrowserTest() {}
void SetUp() override {
switch (GetParam()) {
case CompositorImplMode::kNormal:
break;
case CompositorImplMode::kViz:
scoped_feature_list_.InitAndEnableFeature(
features::kVizDisplayCompositor);
break;
case CompositorImplMode::kVizSkDDL:
scoped_feature_list_.InitWithFeatures(
{features::kVizDisplayCompositor, features::kUseSkiaRenderer,
features::kDefaultEnableOopRasterization},
{});
break;
}
ContentBrowserTest::SetUp();
}
protected:
void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->Start());
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory("content/test/data");
ASSERT_TRUE(https_server.Start());
GURL http_url(embedded_test_server()->GetURL("/title1.html"));
ASSERT_TRUE(NavigateToURL(shell(), http_url));
}
ui::WindowAndroid* window() const {
return web_contents()->GetTopLevelNativeWindow();
}
CompositorImpl* compositor_impl() const {
return static_cast<CompositorImpl*>(window()->GetCompositor());
}
WebContentsImpl* web_contents() const {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
RenderWidgetHostViewAndroid* render_widget_host_view_android() const {
return static_cast<RenderWidgetHostViewAndroid*>(
web_contents()->GetRenderWidgetHostView());
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(CompositorImplBrowserTest);
};
INSTANTIATE_TEST_CASE_P(P,
CompositorImplBrowserTest,
::testing::Values(CompositorImplMode::kNormal,
CompositorImplMode::kViz,
CompositorImplMode::kVizSkDDL));
class CompositorImplLowEndBrowserTest : public CompositorImplBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kEnableLowEndDeviceMode);
command_line->AppendSwitch(switches::kInProcessGPU);
content::ContentBrowserTest::SetUpCommandLine(command_line);
}
};
// Viz on android is not yet compatible with in-process GPU. Only run in
// kNormal mode.
// TODO(ericrk): Make this work everywhere. https://crbug.com/851643
INSTANTIATE_TEST_CASE_P(P,
CompositorImplLowEndBrowserTest,
::testing::Values(CompositorImplMode::kNormal));
// RunLoop implementation that calls glFlush() every second until it observes
// OnContextLost().
class ContextLostRunLoop : public viz::ContextLostObserver {
public:
ContextLostRunLoop(viz::ContextProvider* context_provider)
: context_provider_(context_provider) {
context_provider_->AddObserver(this);
}
~ContextLostRunLoop() override { context_provider_->RemoveObserver(this); }
void RunUntilContextLost() {
CheckForContextLoss();
run_loop_.Run();
}
void CheckForContextLoss() {
if (did_lose_context_) {
run_loop_.Quit();
return;
}
context_provider_->ContextGL()->Flush();
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&ContextLostRunLoop::CheckForContextLoss,
base::Unretained(this)),
base::TimeDelta::FromSeconds(1));
}
private:
// viz::LostContextProvider:
void OnContextLost() override { did_lose_context_ = true; }
viz::ContextProvider* const context_provider_;
bool did_lose_context_ = false;
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(ContextLostRunLoop);
};
// RunLoop implementation that runs until it observes a compositor frame.
class CompositorFrameRunLoop : public ui::WindowAndroidObserver {
public:
CompositorFrameRunLoop(ui::WindowAndroid* window) : window_(window) {
window_->AddObserver(this);
}
~CompositorFrameRunLoop() override { window_->RemoveObserver(this); }
void RunUntilFrame() { run_loop_.Run(); }
private:
// ui::WindowAndroidObserver:
void OnCompositingDidCommit() override { run_loop_.Quit(); }
void OnRootWindowVisibilityChanged(bool visible) override {}
void OnAttachCompositor() override {}
void OnDetachCompositor() override {}
void OnActivityStopped() override {}
void OnActivityStarted() override {}
ui::WindowAndroid* const window_;
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(CompositorFrameRunLoop);
};
IN_PROC_BROWSER_TEST_P(CompositorImplLowEndBrowserTest,
CompositorImplDropsResourcesOnBackground) {
// This test makes invalid assumptions when surface synchronization is
// enabled. The compositor lock is obsolete, and inspecting frames
// from the CompositorImpl does not guarantee renderer CompositorFrames
// are ready.
if (features::IsSurfaceSynchronizationEnabled())
return;
auto* rwhva = render_widget_host_view_android();
auto* compositor = compositor_impl();
auto context = GpuBrowsertestCreateContext(
GpuBrowsertestEstablishGpuChannelSyncRunLoop());
context->BindToCurrentThread();
CompositorFrameRunLoop(window()).RunUntilFrame();
EXPECT_TRUE(rwhva->HasValidFrame());
ContextLostRunLoop run_loop(context.get());
compositor->SetVisibleForTesting(false);
base::android::ApplicationStatusListener::NotifyApplicationStateChange(
base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
rwhva->OnRootWindowVisibilityChanged(false);
rwhva->Hide();
// Ensure that context is eventually dropped and at that point we do not have
// a valid frame.
run_loop.RunUntilContextLost();
EXPECT_FALSE(rwhva->HasValidFrame());
// Become visible again:
compositor->SetVisibleForTesting(true);
base::android::ApplicationStatusListener::NotifyApplicationStateChange(
base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
rwhva->Show();
rwhva->OnRootWindowVisibilityChanged(true);
// We should have taken the compositor lock on resume.
EXPECT_TRUE(compositor->IsLockedForTesting());
EXPECT_FALSE(rwhva->HasValidFrame());
// The compositor should eventually be unlocked and produce a frame.
CompositorFrameRunLoop(window()).RunUntilFrame();
EXPECT_FALSE(compositor->IsLockedForTesting());
EXPECT_TRUE(rwhva->HasValidFrame());
}
// RunLoop implementation that runs until it observes a swap with size.
class CompositorSwapRunLoop {
public:
CompositorSwapRunLoop(CompositorImpl* compositor) : compositor_(compositor) {
compositor_->SetSwapCompletedWithSizeCallbackForTesting(base::BindRepeating(
&CompositorSwapRunLoop::DidSwap, base::Unretained(this)));
}
~CompositorSwapRunLoop() {
compositor_->SetSwapCompletedWithSizeCallbackForTesting(base::DoNothing());
}
void RunUntilSwap() { run_loop_.Run(); }
private:
void DidSwap(const gfx::Size& pixel_size) {
EXPECT_FALSE(pixel_size.IsEmpty());
run_loop_.Quit();
}
CompositorImpl* compositor_;
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(CompositorSwapRunLoop);
};
IN_PROC_BROWSER_TEST_P(CompositorImplBrowserTest,
CompositorImplReceivesSwapCallbacks) {
// OOP-R is required for this test to succeed with SkDDL, but is disabled on
// Android L and lower.
if (GetParam() == CompositorImplMode::kVizSkDDL &&
base::android::BuildInfo::GetInstance()->sdk_int() <
base::android::SDK_VERSION_MARSHMALLOW) {
return;
}
CompositorSwapRunLoop(compositor_impl()).RunUntilSwap();
}
} // namespace
} // namespace content