Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
use api::{ApiMsg, DebugCommand, DebugFlags};
6
use api::channel::MsgSender;
7
use api::units::DeviceIntSize;
8
use crate::print_tree::PrintTreePrinter;
9
use crate::renderer;
10
use std::sync::mpsc::{channel, Receiver};
11
use std::sync::mpsc::Sender;
12
use std::thread;
13
use ws;
14
use base64::encode;
15
use image_loader;
16
17
// Messages that are sent from the render backend to the renderer
18
// debug command queue. These are sent in a separate queue so
19
// that none of these types are exposed to the RenderApi interfaces.
20
// We can't use select!() as it's not stable...
21
enum DebugMsg {
22
AddSender(ws::Sender),
23
RemoveSender(ws::util::Token),
24
}
25
26
// Represents a connection to a client.
27
struct Server {
28
ws: ws::Sender,
29
debug_tx: Sender<DebugMsg>,
30
api_tx: MsgSender<ApiMsg>,
31
debug_flags: DebugFlags,
32
}
33
34
impl ws::Handler for Server {
35
fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
36
self.debug_tx
37
.send(DebugMsg::AddSender(self.ws.clone()))
38
.ok();
39
40
Ok(())
41
}
42
43
fn on_close(&mut self, _: ws::CloseCode, _: &str) {
44
self.debug_tx
45
.send(DebugMsg::RemoveSender(self.ws.token()))
46
.ok();
47
}
48
49
fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
50
match msg {
51
ws::Message::Text(string) => {
52
// First, check for flag change commands.
53
let mut set_flags = true;
54
match string.as_str() {
55
"enable_profiler" => self.debug_flags.insert(DebugFlags::PROFILER_DBG),
56
"disable_profiler" => self.debug_flags.remove(DebugFlags::PROFILER_DBG),
57
"enable_texture_cache_debug" => self.debug_flags.insert(DebugFlags::TEXTURE_CACHE_DBG),
58
"disable_texture_cache_debug" => self.debug_flags.remove(DebugFlags::TEXTURE_CACHE_DBG),
59
"enable_render_target_debug" => self.debug_flags.insert(DebugFlags::RENDER_TARGET_DBG),
60
"disable_render_target_debug" => self.debug_flags.remove(DebugFlags::RENDER_TARGET_DBG),
61
"enable_gpu_time_queries" => self.debug_flags.insert(DebugFlags::GPU_TIME_QUERIES),
62
"disable_gpu_time_queries" => self.debug_flags.remove(DebugFlags::GPU_TIME_QUERIES),
63
"enable_gpu_sample_queries" => self.debug_flags.insert(DebugFlags::GPU_SAMPLE_QUERIES),
64
"disable_gpu_sample_queries" => self.debug_flags.remove(DebugFlags::GPU_SAMPLE_QUERIES),
65
"disable_opaque_pass" => self.debug_flags.insert(DebugFlags::DISABLE_OPAQUE_PASS),
66
"enable_opaque_pass" => self.debug_flags.remove(DebugFlags::DISABLE_OPAQUE_PASS),
67
"disable_alpha_pass" => self.debug_flags.insert(DebugFlags::DISABLE_ALPHA_PASS),
68
"enable_alpha_pass" => self.debug_flags.remove(DebugFlags::DISABLE_ALPHA_PASS),
69
"disable_clip_masks" => self.debug_flags.insert(DebugFlags::DISABLE_CLIP_MASKS),
70
"enable_clip_masks" => self.debug_flags.remove(DebugFlags::DISABLE_CLIP_MASKS),
71
"disable_text_prims" => self.debug_flags.insert(DebugFlags::DISABLE_TEXT_PRIMS),
72
"enable_text_prims" => self.debug_flags.remove(DebugFlags::DISABLE_TEXT_PRIMS),
73
"disable_gradient_prims" => self.debug_flags.insert(DebugFlags::DISABLE_GRADIENT_PRIMS),
74
"enable_gradient_prims" => self.debug_flags.remove(DebugFlags::DISABLE_GRADIENT_PRIMS),
75
_ => set_flags = false,
76
};
77
78
let cmd = if set_flags {
79
DebugCommand::SetFlags(self.debug_flags)
80
} else {
81
match string.as_str() {
82
"fetch_passes" => DebugCommand::FetchPasses,
83
"fetch_screenshot" => DebugCommand::FetchScreenshot,
84
"fetch_documents" => DebugCommand::FetchDocuments,
85
"fetch_spatial_tree" => DebugCommand::FetchClipScrollTree,
86
"fetch_render_tasks" => DebugCommand::FetchRenderTasks,
87
msg => {
88
error!("unknown msg {}", msg);
89
return Ok(());
90
}
91
}
92
};
93
94
let msg = ApiMsg::DebugCommand(cmd);
95
self.api_tx.send(msg).unwrap();
96
}
97
ws::Message::Binary(..) => {}
98
}
99
100
Ok(())
101
}
102
}
103
104
// Spawn a thread for a given renderer, and wait for
105
// client connections.
106
pub struct DebugServerImpl {
107
join_handle: Option<thread::JoinHandle<()>>,
108
broadcaster: ws::Sender,
109
debug_rx: Receiver<DebugMsg>,
110
senders: Vec<ws::Sender>,
111
}
112
113
impl DebugServerImpl {
114
pub fn new(api_tx: MsgSender<ApiMsg>) -> DebugServerImpl {
115
let (debug_tx, debug_rx) = channel();
116
117
let socket = ws::Builder::new()
118
.build(move |out| {
119
Server {
120
ws: out,
121
debug_tx: debug_tx.clone(),
122
api_tx: api_tx.clone(),
123
debug_flags: DebugFlags::empty(),
124
}
125
})
126
.unwrap();
127
128
let broadcaster = socket.broadcaster();
129
130
let join_handle = Some(thread::spawn(move || {
131
let address = "127.0.0.1:3583";
132
debug!("WebRender debug server started: {}", address);
133
if let Err(..) = socket.listen(address) {
134
error!("ERROR: Unable to bind debugger websocket (port may be in use).");
135
}
136
}));
137
138
DebugServerImpl {
139
join_handle,
140
broadcaster,
141
debug_rx,
142
senders: Vec::new(),
143
}
144
}
145
}
146
147
impl renderer::DebugServer for DebugServerImpl {
148
fn send(&mut self, message: String) {
149
// Add any new connections that have been queued.
150
while let Ok(msg) = self.debug_rx.try_recv() {
151
match msg {
152
DebugMsg::AddSender(sender) => {
153
self.senders.push(sender);
154
}
155
DebugMsg::RemoveSender(token) => {
156
self.senders.retain(|sender| sender.token() != token);
157
}
158
}
159
}
160
161
// Broadcast the message to all senders. Keep
162
// track of the ones that failed, so they can
163
// be removed from the active sender list.
164
let mut disconnected_senders = Vec::new();
165
166
for (i, sender) in self.senders.iter().enumerate() {
167
if let Err(..) = sender.send(message.clone()) {
168
disconnected_senders.push(i);
169
}
170
}
171
172
// Remove the broken senders from the list
173
// for next broadcast. Remove in reverse
174
// order so the indices are valid for the
175
// entire loop.
176
for i in disconnected_senders.iter().rev() {
177
self.senders.remove(*i);
178
}
179
}
180
}
181
182
impl Drop for DebugServerImpl {
183
fn drop(&mut self) {
184
self.broadcaster.shutdown().ok();
185
self.join_handle.take().unwrap().join().ok();
186
}
187
}
188
189
// A serializable list of debug information about passes
190
// that can be sent to the client.
191
192
#[derive(Serialize)]
193
pub enum BatchKind {
194
Clip,
195
Cache,
196
Opaque,
197
Alpha,
198
}
199
200
#[derive(Serialize)]
201
pub struct PassList {
202
kind: &'static str,
203
passes: Vec<Pass>,
204
}
205
206
impl PassList {
207
pub fn new() -> PassList {
208
PassList {
209
kind: "passes",
210
passes: Vec::new(),
211
}
212
}
213
214
pub fn add(&mut self, pass: Pass) {
215
self.passes.push(pass);
216
}
217
}
218
219
#[derive(Serialize)]
220
pub struct Pass {
221
pub targets: Vec<Target>,
222
}
223
224
#[derive(Serialize)]
225
pub struct Target {
226
kind: &'static str,
227
batches: Vec<Batch>,
228
}
229
230
impl Target {
231
pub fn new(kind: &'static str) -> Target {
232
Target {
233
kind,
234
batches: Vec::new(),
235
}
236
}
237
238
pub fn add(&mut self, kind: BatchKind, description: &str, count: usize) {
239
if count > 0 {
240
self.batches.push(Batch {
241
kind,
242
description: description.to_owned(),
243
count,
244
});
245
}
246
}
247
}
248
249
#[derive(Serialize)]
250
struct Batch {
251
kind: BatchKind,
252
description: String,
253
count: usize,
254
}
255
256
#[derive(Serialize)]
257
pub struct TreeNode {
258
description: String,
259
children: Vec<TreeNode>,
260
}
261
262
impl TreeNode {
263
pub fn new(description: &str) -> TreeNode {
264
TreeNode {
265
description: description.to_owned(),
266
children: Vec::new(),
267
}
268
}
269
270
pub fn add_child(&mut self, child: TreeNode) {
271
self.children.push(child);
272
}
273
274
pub fn add_item(&mut self, description: &str) {
275
self.children.push(TreeNode::new(description));
276
}
277
}
278
279
#[derive(Serialize)]
280
pub struct DocumentList {
281
kind: &'static str,
282
root: TreeNode,
283
}
284
285
impl DocumentList {
286
pub fn new() -> Self {
287
DocumentList {
288
kind: "documents",
289
root: TreeNode::new("root"),
290
}
291
}
292
293
pub fn add(&mut self, item: TreeNode) {
294
self.root.add_child(item);
295
}
296
}
297
298
#[derive(Serialize)]
299
pub struct Screenshot {
300
kind: &'static str,
301
data: String
302
}
303
304
impl Screenshot {
305
pub fn new(size: DeviceIntSize, data: Vec<u8>) -> Self {
306
let mut output = Vec::with_capacity((size.width * size.height) as usize);
307
{
308
let encoder = image_loader::png::PNGEncoder::new(&mut output);
309
encoder.encode(
310
&data,
311
size.width as u32,
312
size.height as u32,
313
image_loader::ColorType::Rgba8,
314
).unwrap();
315
}
316
317
let data = encode(&output);
318
Screenshot {
319
kind: "screenshot",
320
data
321
}
322
}
323
}
324
325
// A serializable list of debug information about spatial trees
326
// that can be sent to the client
327
328
#[derive(Serialize)]
329
pub struct SpatialTreeList {
330
kind: &'static str,
331
root: TreeNode,
332
}
333
334
impl SpatialTreeList {
335
pub fn new() -> Self {
336
SpatialTreeList {
337
kind: "spatial_tree",
338
root: TreeNode::new("root"),
339
}
340
}
341
342
pub fn add(&mut self, item: TreeNode) {
343
self.root.add_child(item);
344
}
345
}
346
347
#[derive(Serialize)]
348
pub struct RenderTaskList {
349
kind: &'static str,
350
root: TreeNode,
351
}
352
353
impl RenderTaskList {
354
pub fn new() -> Self {
355
RenderTaskList {
356
kind: "render_tasks",
357
root: TreeNode::new("root"),
358
}
359
}
360
361
pub fn add(&mut self, item: TreeNode) {
362
self.root.add_child(item);
363
}
364
}
365
366
// A TreeNode-based PrintTreePrinter to serialize pretty-printed
367
// trees as json
368
pub struct TreeNodeBuilder {
369
levels: Vec<TreeNode>,
370
}
371
372
impl TreeNodeBuilder {
373
pub fn new(root: TreeNode) -> TreeNodeBuilder {
374
TreeNodeBuilder { levels: vec![root] }
375
}
376
377
fn current_level_mut(&mut self) -> &mut TreeNode {
378
assert!(!self.levels.is_empty());
379
self.levels.last_mut().unwrap()
380
}
381
382
pub fn build(mut self) -> TreeNode {
383
assert!(self.levels.len() == 1);
384
self.levels.pop().unwrap()
385
}
386
}
387
388
impl PrintTreePrinter for TreeNodeBuilder {
389
fn new_level(&mut self, title: String) {
390
let level = TreeNode::new(&title);
391
self.levels.push(level);
392
}
393
394
fn end_level(&mut self) {
395
assert!(!self.levels.is_empty());
396
let last_level = self.levels.pop().unwrap();
397
self.current_level_mut().add_child(last_level);
398
}
399
400
fn add_item(&mut self, text: String) {
401
self.current_level_mut().add_item(&text);
402
}
403
}