blob: 36499307a2d41f4e45bdbdfd5a8efcf74fcc87e9 [file] [log] [blame]
// Copyright 2019 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 "components/viz/demo/host/demo_host.h"
#include <utility>
#include "base/rand_util.h"
#include "components/viz/demo/client/demo_client.h"
#include "components/viz/host/renderer_settings_creation.h"
namespace demo {
DemoHost::DemoHost(gfx::AcceleratedWidget widget,
const gfx::Size& size,
viz::mojom::FrameSinkManagerClientRequest client_request,
viz::mojom::FrameSinkManagerPtr frame_sink_manager_ptr)
: widget_(widget), size_(size), thread_("DemoHost") {
CHECK(thread_.Start());
thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&DemoHost::Initialize, base::Unretained(this),
std::move(client_request),
frame_sink_manager_ptr.PassInterface()));
}
DemoHost::~DemoHost() = default;
void DemoHost::Resize(const gfx::Size& size) {
thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&DemoHost::ResizeOnThread, base::Unretained(this), size));
}
void DemoHost::ResizeOnThread(const gfx::Size& size) {
if (size_ == size)
return;
size_ = size;
display_private_->Resize(size);
// Every size change for a client needs a new LocalSurfaceId.
allocator_.GenerateId();
root_client_->Resize(size_, allocator_.GetCurrentLocalSurfaceIdAllocation());
}
void DemoHost::EmbedClients(DemoClient* embedder_client,
const gfx::Rect& child_bounds) {
// Generate a FrameSinkId for the client. Each client can have any number of
// frame-sinks, and these frame-sinks should share the same |client_id|
// component for the FrameSinkId. In this demo however, each client has a
// single FrameSink, so the client-id can just be randomly generated, and it
// doesn't make a difference.
uint64_t rand = base::RandUint64();
viz::FrameSinkId frame_sink_id(rand >> 32, rand & 0xffffffff);
// Register the frame sink and its hierarchy.
host_frame_sink_manager_.RegisterFrameSinkId(
frame_sink_id, this, viz::ReportFirstSurfaceActivation::kNo);
host_frame_sink_manager_.RegisterFrameSinkHierarchy(
embedder_client->frame_sink_id(), frame_sink_id);
// Next, create a mojom::CompositorFrameSink for the client, so that the
// client is able to submit visual (and hit-test) content to the viz service.
// Note that in this demo app, the host is setting up the message-pipes, and
// then sending the end-points to the embedded-client and the viz-service.
// However, it is possible for the embedded-client to initiate the creation of
// the message-pipes, in which case, the client would need to send the
// service-end-points to the host (via a non-viz API), so that the host can in
// turn send them to the service.
viz::mojom::CompositorFrameSinkClientPtr client_ptr;
auto client_request = mojo::MakeRequest(&client_ptr);
viz::mojom::CompositorFrameSinkPtr sink_ptr;
auto sink_request = mojo::MakeRequest(&sink_ptr);
host_frame_sink_manager_.CreateCompositorFrameSink(
frame_sink_id, std::move(sink_request), std::move(client_ptr));
// At this point, the host is done setting everything up. Now it is up to the
// new client to take over the communication (i.e. the mojo message pipes)
// with the service for the frame-sink. The embedder (i.e. the parent client)
// also needs to know about the new client's FrameSinkId, so that it is able
// to embed it. Both the embedder and the embedded client also need to use
// the same LocalSurfaceId for the embedding. Typically, the embedder is the
// one that generates the LocalSurfaceId for the embedded client. However, it
// is possible for another source (e.g. the viz-host) to generate the
// LocalSurfaceId, and dispatch that separately to both the embedder and the
// embedded clients. There is no specific viz-API for communicating these
// FrameSinkId and LocalSurfaceId between these clients. In chrome, these
// happen through the content API (or through the window-service API in
// ChromeOS).
// In this demo app, the embedder-client is assigning the LocalSurfaceId
// (through DemoClient).
auto lsid_allocation = embedder_client->Embed(frame_sink_id, child_bounds);
auto embedded_client = std::make_unique<DemoClient>(
frame_sink_id, lsid_allocation, child_bounds);
embedded_client->Initialize(std::move(client_request),
sink_ptr.PassInterface());
if (embedder_client == root_client_.get()) {
// Embed another client after a second. This could embed the client
// immediately here too if desired. The delay is to demonstrate asynchronous
// usage of the API.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DemoHost::EmbedClients, base::Unretained(this),
embedded_client.get(), gfx::Rect(125, 125, 150, 150)),
base::TimeDelta::FromSeconds(1));
}
embedded_clients_.push_back(std::move(embedded_client));
}
void DemoHost::Initialize(viz::mojom::FrameSinkManagerClientRequest request,
viz::mojom::FrameSinkManagerPtrInfo ptr_info) {
host_frame_sink_manager_.BindAndSetManager(
std::move(request), nullptr,
viz::mojom::FrameSinkManagerPtr(std::move(ptr_info)));
display_client_ = std::make_unique<viz::HostDisplayClient>(widget_);
auto root_params = viz::mojom::RootCompositorFrameSinkParams::New();
// Create interfaces for a root CompositorFrameSink.
viz::mojom::CompositorFrameSinkAssociatedPtrInfo sink_info;
root_params->compositor_frame_sink = mojo::MakeRequest(&sink_info);
auto client_request =
mojo::MakeRequest(&root_params->compositor_frame_sink_client);
root_params->display_private = mojo::MakeRequest(&display_private_);
root_params->display_client =
display_client_->GetBoundPtr(nullptr).PassInterface();
constexpr viz::FrameSinkId root_frame_sink_id(0xdead, 0xbeef);
root_params->frame_sink_id = root_frame_sink_id;
root_params->widget = widget_;
root_params->gpu_compositing = false;
root_params->renderer_settings = viz::CreateRendererSettings();
host_frame_sink_manager_.RegisterFrameSinkId(
root_params->frame_sink_id, this, viz::ReportFirstSurfaceActivation::kNo);
host_frame_sink_manager_.CreateRootCompositorFrameSink(
std::move(root_params));
display_private_->Resize(size_);
display_private_->SetDisplayVisible(true);
// Initialize as a client now, since the host has to submit compositor frames
// like any other clients.
// The 'root' is not embedded by anything else. However, it still needs to
// have a valid LocalSurfaceId, which changes when root changes size (or
// device-scale-factor etc.).
allocator_.GenerateId();
root_client_ = std::make_unique<DemoClient>(
root_frame_sink_id, allocator_.GetCurrentLocalSurfaceIdAllocation(),
gfx::Rect(size_));
root_client_->Initialize(std::move(client_request), std::move(sink_info));
// Embed a new client into the root after the first second.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DemoHost::EmbedClients, base::Unretained(this),
root_client_.get(), gfx::Rect(50, 50, 300, 300)),
base::TimeDelta::FromSeconds(1));
}
void DemoHost::OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) {}
void DemoHost::OnFrameTokenChanged(uint32_t frame_token) {}
} // namespace demo