1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
// Copyright 2019 The Chromium Authors
// 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/command_line.h"
#include "base/rand_util.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "components/viz/demo/client/demo_client.h"
#include "components/viz/demo/common/switches.h"
#include "components/viz/host/renderer_settings_creation.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
namespace demo {
DemoHost::DemoHost(
gfx::AcceleratedWidget widget,
const gfx::Size& size,
mojo::PendingReceiver<viz::mojom::FrameSinkManagerClient> client_receiver,
mojo::PendingRemote<viz::mojom::FrameSinkManager> frame_sink_manager_remote)
: 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_receiver),
std::move(frame_sink_manager_remote)));
}
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_.GetCurrentLocalSurfaceId());
}
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.
mojo::PendingRemote<viz::mojom::CompositorFrameSinkClient> client_remote;
auto client_receiver = client_remote.InitWithNewPipeAndPassReceiver();
mojo::PendingRemote<viz::mojom::CompositorFrameSink> sink_remote;
auto sink_receiver = sink_remote.InitWithNewPipeAndPassReceiver();
host_frame_sink_manager_.CreateCompositorFrameSink(
frame_sink_id, std::move(sink_receiver), std::move(client_remote));
// 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_receiver),
std::move(sink_remote));
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::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DemoHost::EmbedClients, base::Unretained(this),
embedded_client.get(), gfx::Rect(125, 125, 150, 150)),
base::Seconds(1));
}
embedded_clients_.push_back(std::move(embedded_client));
}
void DemoHost::Initialize(
mojo::PendingReceiver<viz::mojom::FrameSinkManagerClient> receiver,
mojo::PendingRemote<viz::mojom::FrameSinkManager> remote) {
host_frame_sink_manager_.BindAndSetManager(std::move(receiver), nullptr,
std::move(remote));
display_client_ = std::make_unique<viz::HostDisplayClient>(widget_);
auto root_params = viz::mojom::RootCompositorFrameSinkParams::New();
// Create interfaces for a root CompositorFrameSink.
mojo::PendingAssociatedRemote<viz::mojom::CompositorFrameSink> sink_remote;
root_params->compositor_frame_sink =
sink_remote.InitWithNewEndpointAndPassReceiver();
auto client_receiver = root_params->compositor_frame_sink_client
.InitWithNewPipeAndPassReceiver();
root_params->display_private =
display_private_.BindNewEndpointAndPassReceiver();
root_params->display_client = display_client_->GetBoundRemote(nullptr);
constexpr viz::FrameSinkId root_frame_sink_id(0xdead, 0xbeef);
root_params->frame_sink_id = root_frame_sink_id;
root_params->widget = widget_;
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
root_params->gpu_compositing = cmd_line->HasSwitch(switches::kVizDemoUseGPU);
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_.GetCurrentLocalSurfaceId(),
gfx::Rect(size_));
root_client_->Initialize(std::move(client_receiver), std::move(sink_remote));
// Embed a new client into the root after the first second.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DemoHost::EmbedClients, base::Unretained(this),
root_client_.get(), gfx::Rect(50, 50, 300, 300)),
base::Seconds(1));
}
void DemoHost::OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) {}
void DemoHost::OnFrameTokenChanged(uint32_t frame_token,
base::TimeTicks activation_time) {}
} // namespace demo
|