File: demo_host.cc

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (180 lines) | stat: -rw-r--r-- 8,160 bytes parent folder | download | duplicates (9)
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