Skip to content

Commit

Permalink
mus::GpuService: Support establish GpuChannel asynchronously.
Browse files Browse the repository at this point in the history
The mus::GpuService will be used by chrome browser process
and chrome renderer process in mus+ash. The current chrome
browser may establish Gpu channel in both sync and async
modes. The renderer process will only establish gpu channel
synchronously. To satisfy chrome's requirements, we add the
async version EstablishGpuChannel on GpuService.

BUG=586390

Review-Url: https://codereview.chromium.org/2087333002
Cr-Commit-Position: refs/heads/master@{#402581}
  • Loading branch information
phuang authored and Commit bot committed Jun 28, 2016
1 parent 7b42531 commit 83ec46d
Show file tree
Hide file tree
Showing 15 changed files with 232 additions and 42 deletions.
2 changes: 2 additions & 0 deletions ash/mus/window_manager_application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "components/mus/common/event_matcher_util.h"
#include "components/mus/common/gpu_service.h"
#include "components/mus/public/cpp/window.h"
#include "components/mus/public/cpp/window_tree_client.h"
#include "services/shell/public/cpp/connection.h"
Expand Down Expand Up @@ -67,6 +68,7 @@ void WindowManagerApplication::Initialize(shell::Connector* connector,
const shell::Identity& identity,
uint32_t id) {
connector_ = connector;
::mus::GpuService::Initialize(connector);
window_manager_.reset(new WindowManager(this, connector_));

aura_init_.reset(new views::AuraInit(connector_, "ash_mus_resources.pak"));
Expand Down
3 changes: 3 additions & 0 deletions ash/sysui/sysui_application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/threading/sequenced_worker_pool.h"
#include "components/mus/common/gpu_service.h"
#include "components/mus/public/cpp/property_type_converters.h"
#include "components/mus/public/interfaces/input_devices/input_device_server.mojom.h"
#include "services/catalog/public/cpp/resource_loader.h"
Expand Down Expand Up @@ -308,6 +309,8 @@ SysUIApplication::~SysUIApplication() {}
void SysUIApplication::Initialize(::shell::Connector* connector,
const ::shell::Identity& identity,
uint32_t id) {
mus::GpuService::Initialize(connector);

ash_init_.reset(new AshInit());
ash_init_->Initialize(connector, identity);

Expand Down
186 changes: 163 additions & 23 deletions components/mus/common/gpu_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/mus/common/gpu_type_converters.h"
#include "components/mus/common/mojo_gpu_memory_buffer_manager.h"
#include "components/mus/common/switches.h"
#include "components/mus/public/interfaces/gpu_service.mojom.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
Expand All @@ -18,18 +17,38 @@

namespace mus {

GpuService::GpuService()
namespace {

void PostTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
const tracked_objects::Location& from_here,
const base::Closure& callback) {
runner->PostTask(from_here, callback);
}

GpuService* g_gpu_service = nullptr;
}

GpuService::GpuService(shell::Connector* connector)
: main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
connector_(connector),
shutdown_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED),
io_thread_("GPUIOThread"),
gpu_memory_buffer_manager_(new MojoGpuMemoryBufferManager) {
gpu_memory_buffer_manager_(new MojoGpuMemoryBufferManager),
is_establishing_(false),
establishing_condition_(&lock_) {
DCHECK(main_task_runner_);
DCHECK(connector_);
base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
thread_options.priority = base::ThreadPriority::NORMAL;
CHECK(io_thread_.StartWithOptions(thread_options));
}

GpuService::~GpuService() {}
GpuService::~GpuService() {
DCHECK(IsMainThread());
if (gpu_channel_)
gpu_channel_->DestroyChannel();
}

// static
bool GpuService::UseChromeGpuCommandBuffer() {
Expand All @@ -43,46 +62,167 @@ bool GpuService::UseChromeGpuCommandBuffer() {
#endif
}

// static
void GpuService::Initialize(shell::Connector* connector) {
DCHECK(!g_gpu_service);
g_gpu_service = new GpuService(connector);
}

// static
void GpuService::Terminate() {
DCHECK(g_gpu_service);
delete g_gpu_service;
g_gpu_service = nullptr;
}

// static
GpuService* GpuService::GetInstance() {
return base::Singleton<GpuService,
base::LeakySingletonTraits<GpuService>>::get();
DCHECK(g_gpu_service);
return g_gpu_service;
}

void GpuService::EstablishGpuChannel(const base::Closure& callback) {
base::AutoLock auto_lock(lock_);
auto runner = base::ThreadTaskRunnerHandle::Get();
if (GetGpuChannelLocked()) {
runner->PostTask(FROM_HERE, callback);
return;
}

base::Closure wrapper_callback =
IsMainThread() ? callback
: base::Bind(PostTask, runner, FROM_HERE, callback);
establish_callbacks_.push_back(wrapper_callback);

if (!is_establishing_) {
is_establishing_ = true;
main_task_runner_->PostTask(
FROM_HERE, base::Bind(&GpuService::EstablishGpuChannelOnMainThread,
base::Unretained(this)));
}
}

scoped_refptr<gpu::GpuChannelHost> GpuService::EstablishGpuChannel(
shell::Connector* connector) {
scoped_refptr<gpu::GpuChannelHost> GpuService::EstablishGpuChannelSync() {
base::AutoLock auto_lock(lock_);
if (GetGpuChannelLocked())
return gpu_channel_;

if (IsMainThread()) {
is_establishing_ = true;
EstablishGpuChannelOnMainThreadSyncLocked();
} else {
if (!is_establishing_) {
// Create an establishing gpu channel task, if there isn't one.
is_establishing_ = true;
main_task_runner_->PostTask(
FROM_HERE, base::Bind(&GpuService::EstablishGpuChannelOnMainThread,
base::Unretained(this)));
}

// Wait until the pending establishing task is finished.
do {
establishing_condition_.Wait();
} while (is_establishing_);
}
return gpu_channel_;
}

scoped_refptr<gpu::GpuChannelHost> GpuService::GetGpuChannel() {
base::AutoLock auto_lock(lock_);
return GetGpuChannelLocked();
}

scoped_refptr<gpu::GpuChannelHost> GpuService::GetGpuChannelLocked() {
if (gpu_channel_ && gpu_channel_->IsLost()) {
gpu_channel_->DestroyChannel();
main_task_runner_->PostTask(
FROM_HERE,
base::Bind(&gpu::GpuChannelHost::DestroyChannel, gpu_channel_));
gpu_channel_ = nullptr;
}
return gpu_channel_;
}

if (gpu_channel_)
return gpu_channel_;
void GpuService::EstablishGpuChannelOnMainThread() {
base::AutoLock auto_lock(lock_);
DCHECK(IsMainThread());

// In GpuService::EstablishGpuChannelOnMainThreadSyncLocked(), we use the sync
// mojo EstablishGpuChannel call, after that call the gpu_service_ will be
// reset immediatelly. So gpu_service_ should be always null here.
DCHECK(!gpu_service_);

// is_establishing_ is false, it means GpuService::EstablishGpuChannelSync()
// has been used, and we don't need try to establish a new GPU channel
// anymore.
if (!is_establishing_)
return;

connector_->ConnectToInterface("mojo:mus", &gpu_service_);
const bool locked = false;
gpu_service_->EstablishGpuChannel(
base::Bind(&GpuService::EstablishGpuChannelOnMainThreadDone,
base::Unretained(this), locked));
}

void GpuService::EstablishGpuChannelOnMainThreadSyncLocked() {
DCHECK(IsMainThread());
DCHECK(is_establishing_);

mus::mojom::GpuServicePtr gpu_service;
connector->ConnectToInterface("mojo:mus", &gpu_service);
// In browser process, EstablishGpuChannelSync() is only used by testing &
// GpuProcessTransportFactory::GetGLHelper(). For GetGLHelper(), it expects
// the gpu channel has been established, so it should not reach here.
// For testing, the asyc method should not be used.
// In renderer process, we only use EstablishGpuChannelSync().
// So the gpu_service_ should be null here.
DCHECK(!gpu_service_);

int client_id = 0;
mojom::ChannelHandlePtr channel_handle;
mojom::GpuInfoPtr gpu_info;
connector_->ConnectToInterface("mojo:mus", &gpu_service_);
{
// TODO(penghuang): Remove the ScopedAllowSyncCall when HW rendering is
// enabled in mus chrome.
base::AutoUnlock auto_unlock(lock_);
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
if (!gpu_service->EstablishGpuChannel(&client_id, &channel_handle,
&gpu_info)) {
if (!gpu_service_->EstablishGpuChannel(&client_id, &channel_handle,
&gpu_info)) {
DLOG(WARNING)
<< "Channel encountered error while establishing gpu channel.";
return nullptr;
return;
}
}
const bool locked = true;
EstablishGpuChannelOnMainThreadDone(
locked, client_id, std::move(channel_handle), std::move(gpu_info));
}

// TODO(penghuang): Get the real gpu info from mus.
gpu_channel_ = gpu::GpuChannelHost::Create(
this, client_id, gpu::GPUInfo(), channel_handle.To<IPC::ChannelHandle>(),
&shutdown_event_, gpu_memory_buffer_manager_.get());
return gpu_channel_;
void GpuService::EstablishGpuChannelOnMainThreadDone(
bool locked,
int client_id,
mojom::ChannelHandlePtr channel_handle,
mojom::GpuInfoPtr gpu_info) {
DCHECK(IsMainThread());
scoped_refptr<gpu::GpuChannelHost> gpu_channel;
if (client_id) {
// TODO(penghuang): Get the real gpu info from mus.
gpu_channel = gpu::GpuChannelHost::Create(
this, client_id, gpu::GPUInfo(),
channel_handle.To<IPC::ChannelHandle>(), &shutdown_event_,
gpu_memory_buffer_manager_.get());
}

auto auto_lock = base::WrapUnique<base::AutoLock>(
locked ? nullptr : new base::AutoLock(lock_));
DCHECK(is_establishing_);
DCHECK(!gpu_channel_);

is_establishing_ = false;
gpu_channel_ = gpu_channel;
establishing_condition_.Broadcast();

for (const auto& i : establish_callbacks_)
i.Run();
establish_callbacks_.clear();
gpu_service_.reset();
}

bool GpuService::IsMainThread() {
Expand Down
36 changes: 30 additions & 6 deletions components/mus/common/gpu_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "components/mus/common/mojo_gpu_memory_buffer_manager.h"
#include "components/mus/common/mus_common_export.h"
#include "components/mus/public/interfaces/gpu_service.mojom.h"
#include "gpu/ipc/client/gpu_channel_host.h"

namespace shell {
Expand All @@ -23,36 +25,58 @@ class Connector;

namespace mus {

class MojoGpuMemoryBufferManager;

class MUS_COMMON_EXPORT GpuService : public gpu::GpuChannelHostFactory {
public:
scoped_refptr<gpu::GpuChannelHost> EstablishGpuChannel(
shell::Connector* connector);
void EstablishGpuChannel(const base::Closure& callback);
scoped_refptr<gpu::GpuChannelHost> EstablishGpuChannelSync();
scoped_refptr<gpu::GpuChannelHost> GetGpuChannel();
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() const {
return gpu_memory_buffer_manager_.get();
}

static bool UseChromeGpuCommandBuffer();

// The GpuService has to be initialized in the main thread before establishing
// the gpu channel.
static void Initialize(shell::Connector* connector);
// The GpuService has to be terminated in the main thread.
static void Terminate();
static GpuService* GetInstance();

private:
friend struct base::DefaultSingletonTraits<GpuService>;

GpuService();
explicit GpuService(shell::Connector* connector);
~GpuService() override;

scoped_refptr<gpu::GpuChannelHost> GetGpuChannelLocked();
void EstablishGpuChannelOnMainThread();
void EstablishGpuChannelOnMainThreadSyncLocked();
void EstablishGpuChannelOnMainThreadDone(
bool locked,
int client_id,
mojom::ChannelHandlePtr channel_handle,
mojom::GpuInfoPtr gpu_info);

// gpu::GpuChannelHostFactory overrides:
bool IsMainThread() override;
scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
std::unique_ptr<base::SharedMemory> AllocateSharedMemory(
size_t size) override;

scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
shell::Connector* connector_;
base::WaitableEvent shutdown_event_;
base::Thread io_thread_;
std::unique_ptr<MojoGpuMemoryBufferManager> gpu_memory_buffer_manager_;

// Lock for |gpu_channel_|.
// Lock for |gpu_channel_|, |establish_callbacks_| & |is_establishing_|.
base::Lock lock_;
bool is_establishing_;
mus::mojom::GpuServicePtr gpu_service_;
scoped_refptr<gpu::GpuChannelHost> gpu_channel_;
std::vector<base::Closure> establish_callbacks_;
base::ConditionVariable establishing_condition_;

DISALLOW_COPY_AND_ASSIGN(GpuService);
};
Expand Down
2 changes: 2 additions & 0 deletions components/mus/demo/mus_demo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "base/time/time.h"
#include "components/bitmap_uploader/bitmap_uploader.h"
#include "components/mus/common/gpu_service.h"
#include "components/mus/public/cpp/window.h"
#include "components/mus/public/cpp/window_tree_client.h"
#include "services/shell/public/cpp/connector.h"
Expand Down Expand Up @@ -66,6 +67,7 @@ void MusDemo::Initialize(shell::Connector* connector,
const shell::Identity& identity,
uint32_t id) {
connector_ = connector;
mus::GpuService::GetInstance()->Initialize(connector_);
window_tree_client_ = new mus::WindowTreeClient(this, this, nullptr);
window_tree_client_->ConnectAsWindowManager(connector);
}
Expand Down
2 changes: 1 addition & 1 deletion components/mus/public/cpp/lib/gles2_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ bool GLES2Context::Initialize(const std::vector<int32_t>& attribs,
gpu_control = command_buffer_client_impl_.get();
} else {
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
GpuService::GetInstance()->EstablishGpuChannel(connector);
GpuService::GetInstance()->EstablishGpuChannelSync();
if (!gpu_channel_host)
return false;
gpu::SurfaceHandle surface_handle = gfx::kNullAcceleratedWidget;
Expand Down
1 change: 1 addition & 0 deletions content/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ source_set("browser") {
if (use_aura) {
deps += [
"//components/bitmap_uploader",
"//components/mus/common:mus_common",
"//components/mus/public/cpp",
"//components/mus/public/interfaces",
"//ui/aura",
Expand Down
1 change: 1 addition & 0 deletions content/browser/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include_rules = [
"+components/leveldb",
"+components/link_header_util",
"+components/mime_util",
"+components/mus/common",
"+components/mus/public/interfaces",
"+components/mus/public",
"+components/network_session_configurator/switches.h",
Expand Down
Loading

0 comments on commit 83ec46d

Please sign in to comment.