Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/hud/hud_context.c
4565 views
1
/**************************************************************************
2
*
3
* Copyright 2013 Marek Olšák <[email protected]>
4
* All Rights Reserved.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
16
* of the Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
* IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
22
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
*
26
**************************************************************************/
27
28
/* This head-up display module can draw transparent graphs on top of what
29
* the app is rendering, visualizing various data like framerate, cpu load,
30
* performance counters, etc. It can be hook up into any gallium frontend.
31
*
32
* The HUD is controlled with the GALLIUM_HUD environment variable.
33
* Set GALLIUM_HUD=help for more info.
34
*/
35
36
#include <inttypes.h>
37
#include <signal.h>
38
#include <stdio.h>
39
40
#include "hud/hud_context.h"
41
#include "hud/hud_private.h"
42
43
#include "frontend/api.h"
44
#include "cso_cache/cso_context.h"
45
#include "util/u_draw_quad.h"
46
#include "util/format/u_format.h"
47
#include "util/u_inlines.h"
48
#include "util/u_memory.h"
49
#include "util/u_math.h"
50
#include "util/u_sampler.h"
51
#include "util/u_simple_shaders.h"
52
#include "util/u_string.h"
53
#include "util/u_upload_mgr.h"
54
#include "tgsi/tgsi_text.h"
55
#include "tgsi/tgsi_dump.h"
56
57
/* Control the visibility of all HUD contexts */
58
static boolean huds_visible = TRUE;
59
static int hud_scale = 1;
60
61
62
#ifdef PIPE_OS_UNIX
63
static void
64
signal_visible_handler(int sig, siginfo_t *siginfo, void *context)
65
{
66
huds_visible = !huds_visible;
67
}
68
#endif
69
70
static void
71
hud_draw_colored_prims(struct hud_context *hud, unsigned prim,
72
float *buffer, unsigned num_vertices,
73
float r, float g, float b, float a,
74
int xoffset, int yoffset, float yscale)
75
{
76
struct cso_context *cso = hud->cso;
77
struct pipe_context *pipe = hud->pipe;
78
struct pipe_vertex_buffer vbuffer = {0};
79
80
hud->constants.color[0] = r;
81
hud->constants.color[1] = g;
82
hud->constants.color[2] = b;
83
hud->constants.color[3] = a;
84
hud->constants.translate[0] = (float) (xoffset * hud_scale);
85
hud->constants.translate[1] = (float) (yoffset * hud_scale);
86
hud->constants.scale[0] = hud_scale;
87
hud->constants.scale[1] = yscale * hud_scale;
88
pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf);
89
90
u_upload_data(hud->pipe->stream_uploader, 0,
91
num_vertices * 2 * sizeof(float), 16, buffer,
92
&vbuffer.buffer_offset, &vbuffer.buffer.resource);
93
u_upload_unmap(hud->pipe->stream_uploader);
94
vbuffer.stride = 2 * sizeof(float);
95
96
cso_set_vertex_buffers(cso, 0, 1, &vbuffer);
97
pipe_resource_reference(&vbuffer.buffer.resource, NULL);
98
cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
99
cso_draw_arrays(cso, prim, 0, num_vertices);
100
}
101
102
static void
103
hud_draw_colored_quad(struct hud_context *hud, unsigned prim,
104
unsigned x1, unsigned y1, unsigned x2, unsigned y2,
105
float r, float g, float b, float a)
106
{
107
float buffer[] = {
108
(float) x1, (float) y1,
109
(float) x1, (float) y2,
110
(float) x2, (float) y2,
111
(float) x2, (float) y1,
112
};
113
114
hud_draw_colored_prims(hud, prim, buffer, 4, r, g, b, a, 0, 0, 1);
115
}
116
117
static void
118
hud_draw_background_quad(struct hud_context *hud,
119
unsigned x1, unsigned y1, unsigned x2, unsigned y2)
120
{
121
float *vertices = hud->bg.vertices + hud->bg.num_vertices*2;
122
unsigned num = 0;
123
124
assert(hud->bg.num_vertices + 4 <= hud->bg.max_num_vertices);
125
126
vertices[num++] = (float) x1;
127
vertices[num++] = (float) y1;
128
129
vertices[num++] = (float) x1;
130
vertices[num++] = (float) y2;
131
132
vertices[num++] = (float) x2;
133
vertices[num++] = (float) y2;
134
135
vertices[num++] = (float) x2;
136
vertices[num++] = (float) y1;
137
138
hud->bg.num_vertices += num/2;
139
}
140
141
static void
142
hud_draw_string(struct hud_context *hud, unsigned x, unsigned y,
143
const char *str, ...)
144
{
145
char buf[256];
146
char *s = buf;
147
float *vertices = hud->text.vertices + hud->text.num_vertices*4;
148
unsigned num = 0;
149
150
va_list ap;
151
va_start(ap, str);
152
vsnprintf(buf, sizeof(buf), str, ap);
153
va_end(ap);
154
155
if (!*s)
156
return;
157
158
hud_draw_background_quad(hud,
159
x, y,
160
x + strlen(buf)*hud->font.glyph_width,
161
y + hud->font.glyph_height);
162
163
while (*s) {
164
unsigned x1 = x;
165
unsigned y1 = y;
166
unsigned x2 = x + hud->font.glyph_width;
167
unsigned y2 = y + hud->font.glyph_height;
168
unsigned tx1 = (*s % 16) * hud->font.glyph_width;
169
unsigned ty1 = (*s / 16) * hud->font.glyph_height;
170
unsigned tx2 = tx1 + hud->font.glyph_width;
171
unsigned ty2 = ty1 + hud->font.glyph_height;
172
173
if (*s == ' ') {
174
x += hud->font.glyph_width;
175
s++;
176
continue;
177
}
178
179
assert(hud->text.num_vertices + num/4 + 4 <= hud->text.max_num_vertices);
180
181
vertices[num++] = (float) x1;
182
vertices[num++] = (float) y1;
183
vertices[num++] = (float) tx1;
184
vertices[num++] = (float) ty1;
185
186
vertices[num++] = (float) x1;
187
vertices[num++] = (float) y2;
188
vertices[num++] = (float) tx1;
189
vertices[num++] = (float) ty2;
190
191
vertices[num++] = (float) x2;
192
vertices[num++] = (float) y2;
193
vertices[num++] = (float) tx2;
194
vertices[num++] = (float) ty2;
195
196
vertices[num++] = (float) x2;
197
vertices[num++] = (float) y1;
198
vertices[num++] = (float) tx2;
199
vertices[num++] = (float) ty1;
200
201
x += hud->font.glyph_width;
202
s++;
203
}
204
205
hud->text.num_vertices += num/4;
206
}
207
208
static void
209
number_to_human_readable(double num, enum pipe_driver_query_type type,
210
char *out)
211
{
212
static const char *byte_units[] =
213
{" B", " KB", " MB", " GB", " TB", " PB", " EB"};
214
static const char *metric_units[] =
215
{"", " k", " M", " G", " T", " P", " E"};
216
static const char *time_units[] =
217
{" us", " ms", " s"}; /* based on microseconds */
218
static const char *hz_units[] =
219
{" Hz", " KHz", " MHz", " GHz"};
220
static const char *percent_units[] = {"%"};
221
static const char *dbm_units[] = {" (-dBm)"};
222
static const char *temperature_units[] = {" C"};
223
static const char *volt_units[] = {" mV", " V"};
224
static const char *amp_units[] = {" mA", " A"};
225
static const char *watt_units[] = {" mW", " W"};
226
static const char *float_units[] = {""};
227
228
const char **units;
229
unsigned max_unit;
230
double divisor = (type == PIPE_DRIVER_QUERY_TYPE_BYTES) ? 1024 : 1000;
231
unsigned unit = 0;
232
double d = num;
233
234
switch (type) {
235
case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS:
236
max_unit = ARRAY_SIZE(time_units)-1;
237
units = time_units;
238
break;
239
case PIPE_DRIVER_QUERY_TYPE_VOLTS:
240
max_unit = ARRAY_SIZE(volt_units)-1;
241
units = volt_units;
242
break;
243
case PIPE_DRIVER_QUERY_TYPE_AMPS:
244
max_unit = ARRAY_SIZE(amp_units)-1;
245
units = amp_units;
246
break;
247
case PIPE_DRIVER_QUERY_TYPE_DBM:
248
max_unit = ARRAY_SIZE(dbm_units)-1;
249
units = dbm_units;
250
break;
251
case PIPE_DRIVER_QUERY_TYPE_TEMPERATURE:
252
max_unit = ARRAY_SIZE(temperature_units)-1;
253
units = temperature_units;
254
break;
255
case PIPE_DRIVER_QUERY_TYPE_FLOAT:
256
max_unit = ARRAY_SIZE(float_units)-1;
257
units = float_units;
258
break;
259
case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE:
260
max_unit = ARRAY_SIZE(percent_units)-1;
261
units = percent_units;
262
break;
263
case PIPE_DRIVER_QUERY_TYPE_BYTES:
264
max_unit = ARRAY_SIZE(byte_units)-1;
265
units = byte_units;
266
break;
267
case PIPE_DRIVER_QUERY_TYPE_HZ:
268
max_unit = ARRAY_SIZE(hz_units)-1;
269
units = hz_units;
270
break;
271
case PIPE_DRIVER_QUERY_TYPE_WATTS:
272
max_unit = ARRAY_SIZE(watt_units)-1;
273
units = watt_units;
274
break;
275
default:
276
max_unit = ARRAY_SIZE(metric_units)-1;
277
units = metric_units;
278
}
279
280
while (d > divisor && unit < max_unit) {
281
d /= divisor;
282
unit++;
283
}
284
285
/* Round to 3 decimal places so as not to print trailing zeros. */
286
if (d*1000 != (int)(d*1000))
287
d = round(d * 1000) / 1000;
288
289
/* Show at least 4 digits with at most 3 decimal places, but not zeros. */
290
if (d >= 1000 || d == (int)d)
291
sprintf(out, "%.0f%s", d, units[unit]);
292
else if (d >= 100 || d*10 == (int)(d*10))
293
sprintf(out, "%.1f%s", d, units[unit]);
294
else if (d >= 10 || d*100 == (int)(d*100))
295
sprintf(out, "%.2f%s", d, units[unit]);
296
else
297
sprintf(out, "%.3f%s", d, units[unit]);
298
}
299
300
static void
301
hud_draw_graph_line_strip(struct hud_context *hud, const struct hud_graph *gr,
302
unsigned xoffset, unsigned yoffset, float yscale)
303
{
304
if (gr->num_vertices <= 1)
305
return;
306
307
assert(gr->index <= gr->num_vertices);
308
309
hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP,
310
gr->vertices, gr->index,
311
gr->color[0], gr->color[1], gr->color[2], 1,
312
xoffset + (gr->pane->max_num_vertices - gr->index - 1) * 2 - 1,
313
yoffset, yscale);
314
315
if (gr->num_vertices <= gr->index)
316
return;
317
318
hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP,
319
gr->vertices + gr->index*2,
320
gr->num_vertices - gr->index,
321
gr->color[0], gr->color[1], gr->color[2], 1,
322
xoffset - gr->index*2 - 1, yoffset, yscale);
323
}
324
325
static void
326
hud_pane_accumulate_vertices(struct hud_context *hud,
327
const struct hud_pane *pane)
328
{
329
struct hud_graph *gr;
330
float *line_verts = hud->whitelines.vertices + hud->whitelines.num_vertices*2;
331
unsigned i, num = 0;
332
char str[32];
333
const unsigned last_line = pane->last_line;
334
335
/* draw background */
336
hud_draw_background_quad(hud,
337
pane->x1, pane->y1,
338
pane->x2, pane->y2);
339
340
/* draw numbers on the right-hand side */
341
for (i = 0; i <= last_line; i++) {
342
unsigned x = pane->x2 + 2;
343
unsigned y = pane->inner_y1 +
344
pane->inner_height * (last_line - i) / last_line -
345
hud->font.glyph_height / 2;
346
347
number_to_human_readable(pane->max_value * i / last_line,
348
pane->type, str);
349
hud_draw_string(hud, x, y, "%s", str);
350
}
351
352
/* draw info below the pane */
353
i = 0;
354
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
355
unsigned x = pane->x1 + 2;
356
unsigned y = pane->y2 + 2 + i*hud->font.glyph_height;
357
358
number_to_human_readable(gr->current_value, pane->type, str);
359
hud_draw_string(hud, x, y, " %s: %s", gr->name, str);
360
i++;
361
}
362
363
/* draw border */
364
assert(hud->whitelines.num_vertices + num/2 + 8 <= hud->whitelines.max_num_vertices);
365
line_verts[num++] = (float) pane->x1;
366
line_verts[num++] = (float) pane->y1;
367
line_verts[num++] = (float) pane->x2;
368
line_verts[num++] = (float) pane->y1;
369
370
line_verts[num++] = (float) pane->x2;
371
line_verts[num++] = (float) pane->y1;
372
line_verts[num++] = (float) pane->x2;
373
line_verts[num++] = (float) pane->y2;
374
375
line_verts[num++] = (float) pane->x1;
376
line_verts[num++] = (float) pane->y2;
377
line_verts[num++] = (float) pane->x2;
378
line_verts[num++] = (float) pane->y2;
379
380
line_verts[num++] = (float) pane->x1;
381
line_verts[num++] = (float) pane->y1;
382
line_verts[num++] = (float) pane->x1;
383
line_verts[num++] = (float) pane->y2;
384
385
/* draw horizontal lines inside the graph */
386
for (i = 0; i <= last_line; i++) {
387
float y = round((pane->max_value * i / (double)last_line) *
388
pane->yscale + pane->inner_y2);
389
390
assert(hud->whitelines.num_vertices + num/2 + 2 <= hud->whitelines.max_num_vertices);
391
line_verts[num++] = pane->x1;
392
line_verts[num++] = y;
393
line_verts[num++] = pane->x2;
394
line_verts[num++] = y;
395
}
396
397
hud->whitelines.num_vertices += num/2;
398
}
399
400
static void
401
hud_pane_accumulate_vertices_simple(struct hud_context *hud,
402
const struct hud_pane *pane)
403
{
404
struct hud_graph *gr;
405
unsigned i;
406
char str[32];
407
408
/* draw info below the pane */
409
i = 0;
410
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
411
unsigned x = pane->x1;
412
unsigned y = pane->y_simple + i*hud->font.glyph_height;
413
414
number_to_human_readable(gr->current_value, pane->type, str);
415
hud_draw_string(hud, x, y, "%s: %s", gr->name, str);
416
i++;
417
}
418
}
419
420
static void
421
hud_pane_draw_colored_objects(struct hud_context *hud,
422
const struct hud_pane *pane)
423
{
424
struct hud_graph *gr;
425
unsigned i;
426
427
/* draw colored quads below the pane */
428
i = 0;
429
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
430
unsigned x = pane->x1 + 2;
431
unsigned y = pane->y2 + 2 + i*hud->font.glyph_height;
432
433
hud_draw_colored_quad(hud, PIPE_PRIM_QUADS, x + 1, y + 1, x + 12, y + 13,
434
gr->color[0], gr->color[1], gr->color[2], 1);
435
i++;
436
}
437
438
/* draw the line strips */
439
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
440
hud_draw_graph_line_strip(hud, gr, pane->inner_x1, pane->inner_y2, pane->yscale);
441
}
442
}
443
444
static void
445
hud_prepare_vertices(struct hud_context *hud, struct vertex_queue *v,
446
unsigned num_vertices, unsigned stride)
447
{
448
v->num_vertices = 0;
449
v->max_num_vertices = num_vertices;
450
v->vbuf.stride = stride;
451
v->buffer_size = stride * num_vertices;
452
}
453
454
/**
455
* Draw the HUD to the texture \p tex.
456
* The texture is usually the back buffer being displayed.
457
*/
458
static void
459
hud_draw_results(struct hud_context *hud, struct pipe_resource *tex)
460
{
461
struct cso_context *cso = hud->cso;
462
struct pipe_context *pipe = hud->pipe;
463
struct pipe_framebuffer_state fb;
464
struct pipe_surface surf_templ, *surf;
465
struct pipe_viewport_state viewport;
466
const struct pipe_sampler_state *sampler_states[] =
467
{ &hud->font_sampler_state };
468
struct hud_pane *pane;
469
470
if (!huds_visible)
471
return;
472
473
hud->fb_width = tex->width0;
474
hud->fb_height = tex->height0;
475
hud->constants.two_div_fb_width = 2.0f / hud->fb_width;
476
hud->constants.two_div_fb_height = 2.0f / hud->fb_height;
477
478
cso_save_state(cso, (CSO_BIT_FRAMEBUFFER |
479
CSO_BIT_SAMPLE_MASK |
480
CSO_BIT_MIN_SAMPLES |
481
CSO_BIT_BLEND |
482
CSO_BIT_DEPTH_STENCIL_ALPHA |
483
CSO_BIT_FRAGMENT_SHADER |
484
CSO_BIT_FRAGMENT_SAMPLERS |
485
CSO_BIT_RASTERIZER |
486
CSO_BIT_VIEWPORT |
487
CSO_BIT_STREAM_OUTPUTS |
488
CSO_BIT_GEOMETRY_SHADER |
489
CSO_BIT_TESSCTRL_SHADER |
490
CSO_BIT_TESSEVAL_SHADER |
491
CSO_BIT_VERTEX_SHADER |
492
CSO_BIT_VERTEX_ELEMENTS |
493
CSO_BIT_PAUSE_QUERIES |
494
CSO_BIT_RENDER_CONDITION));
495
496
/* set states */
497
memset(&surf_templ, 0, sizeof(surf_templ));
498
surf_templ.format = tex->format;
499
500
/* Without this, AA lines look thinner if they are between 2 pixels
501
* because the alpha is 0.5 on both pixels. (it's ugly)
502
*
503
* sRGB makes the width of all AA lines look the same.
504
*/
505
if (hud->has_srgb) {
506
enum pipe_format srgb_format = util_format_srgb(tex->format);
507
508
if (srgb_format != PIPE_FORMAT_NONE)
509
surf_templ.format = srgb_format;
510
}
511
surf = pipe->create_surface(pipe, tex, &surf_templ);
512
513
memset(&fb, 0, sizeof(fb));
514
fb.nr_cbufs = 1;
515
fb.cbufs[0] = surf;
516
fb.zsbuf = NULL;
517
fb.width = hud->fb_width;
518
fb.height = hud->fb_height;
519
520
viewport.scale[0] = 0.5f * hud->fb_width;
521
viewport.scale[1] = 0.5f * hud->fb_height;
522
viewport.scale[2] = 0.0f;
523
viewport.translate[0] = 0.5f * hud->fb_width;
524
viewport.translate[1] = 0.5f * hud->fb_height;
525
viewport.translate[2] = 0.0f;
526
viewport.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X;
527
viewport.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y;
528
viewport.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z;
529
viewport.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W;
530
531
cso_set_framebuffer(cso, &fb);
532
cso_set_sample_mask(cso, ~0);
533
cso_set_min_samples(cso, 1);
534
cso_set_depth_stencil_alpha(cso, &hud->dsa);
535
cso_set_rasterizer(cso, &hud->rasterizer);
536
cso_set_viewport(cso, &viewport);
537
cso_set_stream_outputs(cso, 0, NULL, NULL);
538
cso_set_tessctrl_shader_handle(cso, NULL);
539
cso_set_tesseval_shader_handle(cso, NULL);
540
cso_set_geometry_shader_handle(cso, NULL);
541
cso_set_vertex_shader_handle(cso, hud->vs_color);
542
cso_set_vertex_elements(cso, &hud->velems);
543
cso_set_render_condition(cso, NULL, FALSE, 0);
544
pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, 0,
545
&hud->font_sampler_view);
546
cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, sampler_states);
547
pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf);
548
549
/* draw accumulated vertices for background quads */
550
cso_set_blend(cso, &hud->alpha_blend);
551
cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
552
553
if (hud->bg.num_vertices) {
554
hud->constants.color[0] = 0;
555
hud->constants.color[1] = 0;
556
hud->constants.color[2] = 0;
557
hud->constants.color[3] = 0.666f;
558
hud->constants.translate[0] = 0;
559
hud->constants.translate[1] = 0;
560
hud->constants.scale[0] = hud_scale;
561
hud->constants.scale[1] = hud_scale;
562
563
pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf);
564
565
cso_set_vertex_buffers(cso, 0, 1, &hud->bg.vbuf);
566
cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices);
567
}
568
pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL);
569
570
/* draw accumulated vertices for text */
571
if (hud->text.num_vertices) {
572
cso_set_vertex_shader_handle(cso, hud->vs_text);
573
cso_set_vertex_buffers(cso, 0, 1, &hud->text.vbuf);
574
cso_set_fragment_shader_handle(hud->cso, hud->fs_text);
575
cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices);
576
}
577
pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL);
578
579
if (hud->simple)
580
goto done;
581
582
/* draw accumulated vertices for white lines */
583
cso_set_blend(cso, &hud->no_blend);
584
585
hud->constants.color[0] = 1;
586
hud->constants.color[1] = 1;
587
hud->constants.color[2] = 1;
588
hud->constants.color[3] = 1;
589
hud->constants.translate[0] = 0;
590
hud->constants.translate[1] = 0;
591
hud->constants.scale[0] = hud_scale;
592
hud->constants.scale[1] = hud_scale;
593
pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf);
594
595
if (hud->whitelines.num_vertices) {
596
cso_set_vertex_shader_handle(cso, hud->vs_color);
597
cso_set_vertex_buffers(cso, 0, 1, &hud->whitelines.vbuf);
598
cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
599
cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices);
600
}
601
pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL);
602
603
/* draw the rest */
604
cso_set_blend(cso, &hud->alpha_blend);
605
cso_set_rasterizer(cso, &hud->rasterizer_aa_lines);
606
LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
607
if (pane)
608
hud_pane_draw_colored_objects(hud, pane);
609
}
610
611
done:
612
cso_restore_state(cso);
613
614
/* Unbind resources that we have bound. */
615
pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, NULL);
616
pipe->set_vertex_buffers(pipe, 0, 0, 1, false, NULL);
617
pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 0, 1, NULL);
618
619
/* restore states not restored by cso */
620
if (hud->st) {
621
hud->st->invalidate_state(hud->st,
622
ST_INVALIDATE_FS_SAMPLER_VIEWS |
623
ST_INVALIDATE_VS_CONSTBUF0 |
624
ST_INVALIDATE_VERTEX_BUFFERS);
625
}
626
627
pipe_surface_reference(&surf, NULL);
628
}
629
630
static void
631
hud_start_queries(struct hud_context *hud, struct pipe_context *pipe)
632
{
633
struct hud_pane *pane;
634
struct hud_graph *gr;
635
636
/* Start queries. */
637
hud_batch_query_begin(hud->batch_query, pipe);
638
639
LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
640
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
641
if (gr->begin_query)
642
gr->begin_query(gr, pipe);
643
}
644
}
645
}
646
647
/* Stop queries, query results, and record vertices for charts. */
648
static void
649
hud_stop_queries(struct hud_context *hud, struct pipe_context *pipe)
650
{
651
struct hud_pane *pane;
652
struct hud_graph *gr, *next;
653
654
/* prepare vertex buffers */
655
hud_prepare_vertices(hud, &hud->bg, 16 * 256, 2 * sizeof(float));
656
hud_prepare_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float));
657
hud_prepare_vertices(hud, &hud->text, 16 * 1024, 4 * sizeof(float));
658
659
/* Allocate everything once and divide the storage into 3 portions
660
* manually, because u_upload_alloc can unmap memory from previous calls.
661
*/
662
u_upload_alloc(pipe->stream_uploader, 0,
663
hud->bg.buffer_size +
664
hud->whitelines.buffer_size +
665
hud->text.buffer_size,
666
16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer.resource,
667
(void**)&hud->bg.vertices);
668
if (!hud->bg.vertices)
669
return;
670
671
pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
672
pipe_resource_reference(&hud->text.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
673
674
hud->whitelines.vbuf.buffer_offset = hud->bg.vbuf.buffer_offset +
675
hud->bg.buffer_size;
676
hud->whitelines.vertices = hud->bg.vertices +
677
hud->bg.buffer_size / sizeof(float);
678
679
hud->text.vbuf.buffer_offset = hud->whitelines.vbuf.buffer_offset +
680
hud->whitelines.buffer_size;
681
hud->text.vertices = hud->whitelines.vertices +
682
hud->whitelines.buffer_size / sizeof(float);
683
684
/* prepare all graphs */
685
hud_batch_query_update(hud->batch_query, pipe);
686
687
LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
688
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
689
gr->query_new_value(gr, pipe);
690
}
691
692
if (pane->sort_items) {
693
LIST_FOR_EACH_ENTRY_SAFE(gr, next, &pane->graph_list, head) {
694
/* ignore the last one */
695
if (&gr->head == pane->graph_list.prev)
696
continue;
697
698
/* This is an incremental bubble sort, because we only do one pass
699
* per frame. It will eventually reach an equilibrium.
700
*/
701
if (gr->current_value <
702
LIST_ENTRY(struct hud_graph, next, head)->current_value) {
703
list_del(&gr->head);
704
list_add(&gr->head, &next->head);
705
}
706
}
707
}
708
709
if (hud->simple)
710
hud_pane_accumulate_vertices_simple(hud, pane);
711
else
712
hud_pane_accumulate_vertices(hud, pane);
713
}
714
715
/* unmap the uploader's vertex buffer before drawing */
716
u_upload_unmap(pipe->stream_uploader);
717
}
718
719
/**
720
* Record queries and draw the HUD. The "cso" parameter acts as a filter.
721
* If "cso" is not the recording context, recording is skipped.
722
* If "cso" is not the drawing context, drawing is skipped.
723
* cso == NULL ignores the filter.
724
*/
725
void
726
hud_run(struct hud_context *hud, struct cso_context *cso,
727
struct pipe_resource *tex)
728
{
729
struct pipe_context *pipe = cso ? cso_get_pipe_context(cso) : NULL;
730
731
/* If "cso" is the recording or drawing context or NULL, execute
732
* the operation. Otherwise, don't do anything.
733
*/
734
if (hud->record_pipe && (!pipe || pipe == hud->record_pipe))
735
hud_stop_queries(hud, hud->record_pipe);
736
737
if (hud->cso && (!cso || cso == hud->cso))
738
hud_draw_results(hud, tex);
739
740
if (hud->record_pipe && (!pipe || pipe == hud->record_pipe))
741
hud_start_queries(hud, hud->record_pipe);
742
}
743
744
/**
745
* Record query results and assemble vertices if "pipe" is a recording but
746
* not drawing context.
747
*/
748
void
749
hud_record_only(struct hud_context *hud, struct pipe_context *pipe)
750
{
751
assert(pipe);
752
753
/* If it's a drawing context, only hud_run() records query results. */
754
if (pipe == hud->pipe || pipe != hud->record_pipe)
755
return;
756
757
hud_stop_queries(hud, hud->record_pipe);
758
hud_start_queries(hud, hud->record_pipe);
759
}
760
761
static void
762
fixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10)
763
{
764
if (type == PIPE_DRIVER_QUERY_TYPE_BYTES && position % 3 == 0)
765
*exp10 = (*exp10 / 1000) * 1024;
766
}
767
768
/**
769
* Set the maximum value for the Y axis of the graph.
770
* This scales the graph accordingly.
771
*/
772
void
773
hud_pane_set_max_value(struct hud_pane *pane, uint64_t value)
774
{
775
double leftmost_digit;
776
uint64_t exp10;
777
int i;
778
779
/* The following code determines the max_value in the graph as well as
780
* how many describing lines are drawn. The max_value is rounded up,
781
* so that all drawn numbers are rounded for readability.
782
* We want to print multiples of a simple number instead of multiples of
783
* hard-to-read numbers like 1.753.
784
*/
785
786
/* Find the left-most digit. Make sure exp10 * 10 and fixup_bytes doesn't
787
* overflow. (11 is safe) */
788
exp10 = 1;
789
for (i = 0; exp10 <= UINT64_MAX / 11 && exp10 * 9 < value; i++) {
790
exp10 *= 10;
791
fixup_bytes(pane->type, i + 1, &exp10);
792
}
793
794
leftmost_digit = DIV_ROUND_UP(value, exp10);
795
796
/* Round 9 to 10. */
797
if (leftmost_digit == 9) {
798
leftmost_digit = 1;
799
exp10 *= 10;
800
fixup_bytes(pane->type, i + 1, &exp10);
801
}
802
803
switch ((unsigned)leftmost_digit) {
804
case 1:
805
pane->last_line = 5; /* lines in +1/5 increments */
806
break;
807
case 2:
808
pane->last_line = 8; /* lines in +1/4 increments. */
809
break;
810
case 3:
811
case 4:
812
pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments */
813
break;
814
case 5:
815
case 6:
816
case 7:
817
case 8:
818
pane->last_line = leftmost_digit; /* lines in +1 increments */
819
break;
820
default:
821
assert(0);
822
}
823
824
/* Truncate {3,4} to {2.5, 3.5} if possible. */
825
for (i = 3; i <= 4; i++) {
826
if (leftmost_digit == i && value <= (i - 0.5) * exp10) {
827
leftmost_digit = i - 0.5;
828
pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments. */
829
}
830
}
831
832
/* Truncate 2 to a multiple of 0.2 in (1, 1.6] if possible. */
833
if (leftmost_digit == 2) {
834
for (i = 1; i <= 3; i++) {
835
if (value <= (1 + i*0.2) * exp10) {
836
leftmost_digit = 1 + i*0.2;
837
pane->last_line = 5 + i; /* lines in +1/5 increments. */
838
break;
839
}
840
}
841
}
842
843
pane->max_value = leftmost_digit * exp10;
844
pane->yscale = -(int)pane->inner_height / (float)pane->max_value;
845
}
846
847
static void
848
hud_pane_update_dyn_ceiling(struct hud_graph *gr, struct hud_pane *pane)
849
{
850
unsigned i;
851
float tmp = 0.0f;
852
853
if (pane->dyn_ceil_last_ran != gr->index) {
854
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
855
for (i = 0; i < gr->num_vertices; ++i) {
856
tmp = gr->vertices[i * 2 + 1] > tmp ?
857
gr->vertices[i * 2 + 1] : tmp;
858
}
859
}
860
861
/* Avoid setting it lower than the initial starting height. */
862
tmp = tmp > pane->initial_max_value ? tmp : pane->initial_max_value;
863
hud_pane_set_max_value(pane, tmp);
864
}
865
866
/*
867
* Mark this adjustment run so we could avoid repeating a full update
868
* again needlessly in case the pane has more than one graph.
869
*/
870
pane->dyn_ceil_last_ran = gr->index;
871
}
872
873
static struct hud_pane *
874
hud_pane_create(struct hud_context *hud,
875
unsigned x1, unsigned y1, unsigned x2, unsigned y2,
876
unsigned y_simple,
877
unsigned period, uint64_t max_value, uint64_t ceiling,
878
boolean dyn_ceiling, boolean sort_items)
879
{
880
struct hud_pane *pane = CALLOC_STRUCT(hud_pane);
881
882
if (!pane)
883
return NULL;
884
885
pane->hud = hud;
886
pane->x1 = x1;
887
pane->y1 = y1;
888
pane->x2 = x2;
889
pane->y2 = y2;
890
pane->y_simple = y_simple;
891
pane->inner_x1 = x1 + 1;
892
pane->inner_x2 = x2 - 1;
893
pane->inner_y1 = y1 + 1;
894
pane->inner_y2 = y2 - 1;
895
pane->inner_width = pane->inner_x2 - pane->inner_x1;
896
pane->inner_height = pane->inner_y2 - pane->inner_y1;
897
pane->period = period;
898
pane->max_num_vertices = (x2 - x1 + 2) / 2;
899
pane->ceiling = ceiling;
900
pane->dyn_ceiling = dyn_ceiling;
901
pane->dyn_ceil_last_ran = 0;
902
pane->sort_items = sort_items;
903
pane->initial_max_value = max_value;
904
hud_pane_set_max_value(pane, max_value);
905
list_inithead(&pane->graph_list);
906
return pane;
907
}
908
909
/* replace '-' with a space */
910
static void
911
strip_hyphens(char *s)
912
{
913
while (*s) {
914
if (*s == '-')
915
*s = ' ';
916
s++;
917
}
918
}
919
920
/**
921
* Add a graph to an existing pane.
922
* One pane can contain multiple graphs over each other.
923
*/
924
void
925
hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr)
926
{
927
static const float colors[][3] = {
928
{0, 1, 0},
929
{1, 0, 0},
930
{0, 1, 1},
931
{1, 0, 1},
932
{1, 1, 0},
933
{0.5, 1, 0.5},
934
{1, 0.5, 0.5},
935
{0.5, 1, 1},
936
{1, 0.5, 1},
937
{1, 1, 0.5},
938
{0, 0.5, 0},
939
{0.5, 0, 0},
940
{0, 0.5, 0.5},
941
{0.5, 0, 0.5},
942
{0.5, 0.5, 0},
943
};
944
unsigned color = pane->next_color % ARRAY_SIZE(colors);
945
946
strip_hyphens(gr->name);
947
948
gr->vertices = MALLOC(pane->max_num_vertices * sizeof(float) * 2);
949
gr->color[0] = colors[color][0];
950
gr->color[1] = colors[color][1];
951
gr->color[2] = colors[color][2];
952
gr->pane = pane;
953
list_addtail(&gr->head, &pane->graph_list);
954
pane->num_graphs++;
955
pane->next_color++;
956
}
957
958
void
959
hud_graph_add_value(struct hud_graph *gr, double value)
960
{
961
gr->current_value = value;
962
value = value > gr->pane->ceiling ? gr->pane->ceiling : value;
963
964
if (gr->fd) {
965
if (fabs(value - lround(value)) > FLT_EPSILON) {
966
fprintf(gr->fd, "%f\n", value);
967
}
968
else {
969
fprintf(gr->fd, "%" PRIu64 "\n", (uint64_t) lround(value));
970
}
971
}
972
973
if (gr->index == gr->pane->max_num_vertices) {
974
gr->vertices[0] = 0;
975
gr->vertices[1] = gr->vertices[(gr->index-1)*2+1];
976
gr->index = 1;
977
}
978
gr->vertices[(gr->index)*2+0] = (float) (gr->index * 2);
979
gr->vertices[(gr->index)*2+1] = (float) value;
980
gr->index++;
981
982
if (gr->num_vertices < gr->pane->max_num_vertices) {
983
gr->num_vertices++;
984
}
985
986
if (gr->pane->dyn_ceiling == true) {
987
hud_pane_update_dyn_ceiling(gr, gr->pane);
988
}
989
if (value > gr->pane->max_value) {
990
hud_pane_set_max_value(gr->pane, value);
991
}
992
}
993
994
static void
995
hud_graph_destroy(struct hud_graph *graph, struct pipe_context *pipe)
996
{
997
FREE(graph->vertices);
998
if (graph->free_query_data)
999
graph->free_query_data(graph->query_data, pipe);
1000
if (graph->fd)
1001
fclose(graph->fd);
1002
FREE(graph);
1003
}
1004
1005
static void strcat_without_spaces(char *dst, const char *src)
1006
{
1007
dst += strlen(dst);
1008
while (*src) {
1009
if (*src == ' ')
1010
*dst++ = '_';
1011
else
1012
*dst++ = *src;
1013
src++;
1014
}
1015
*dst = 0;
1016
}
1017
1018
1019
#ifdef PIPE_OS_WINDOWS
1020
#define W_OK 0
1021
static int
1022
access(const char *pathname, int mode)
1023
{
1024
/* no-op */
1025
return 0;
1026
}
1027
1028
#define PATH_SEP "\\"
1029
1030
#else
1031
1032
#define PATH_SEP "/"
1033
1034
#endif
1035
1036
1037
/**
1038
* If the GALLIUM_HUD_DUMP_DIR env var is set, we'll write the raw
1039
* HUD values to files at ${GALLIUM_HUD_DUMP_DIR}/<stat> where <stat>
1040
* is a HUD variable such as "fps", or "cpu"
1041
*/
1042
static void
1043
hud_graph_set_dump_file(struct hud_graph *gr)
1044
{
1045
const char *hud_dump_dir = getenv("GALLIUM_HUD_DUMP_DIR");
1046
1047
if (hud_dump_dir && access(hud_dump_dir, W_OK) == 0) {
1048
char *dump_file = malloc(strlen(hud_dump_dir) + sizeof(PATH_SEP)
1049
+ sizeof(gr->name));
1050
if (dump_file) {
1051
strcpy(dump_file, hud_dump_dir);
1052
strcat(dump_file, PATH_SEP);
1053
strcat_without_spaces(dump_file, gr->name);
1054
gr->fd = fopen(dump_file, "w+");
1055
if (gr->fd) {
1056
/* flush output after each line is written */
1057
setvbuf(gr->fd, NULL, _IOLBF, 0);
1058
}
1059
free(dump_file);
1060
}
1061
}
1062
}
1063
1064
/**
1065
* Read a string from the environment variable.
1066
* The separators "+", ",", ":", and ";" terminate the string.
1067
* Return the number of read characters.
1068
*/
1069
static int
1070
parse_string(const char *s, char *out)
1071
{
1072
int i;
1073
1074
for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';' && *s != '=';
1075
s++, out++, i++)
1076
*out = *s;
1077
1078
*out = 0;
1079
1080
if (*s && !i) {
1081
fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) while "
1082
"parsing a string\n", *s, *s);
1083
fflush(stderr);
1084
}
1085
1086
return i;
1087
}
1088
1089
static char *
1090
read_pane_settings(char *str, unsigned * const x, unsigned * const y,
1091
unsigned * const width, unsigned * const height,
1092
uint64_t * const ceiling, boolean * const dyn_ceiling,
1093
boolean *reset_colors, boolean *sort_items)
1094
{
1095
char *ret = str;
1096
unsigned tmp;
1097
1098
while (*str == '.') {
1099
++str;
1100
switch (*str) {
1101
case 'x':
1102
++str;
1103
*x = strtoul(str, &ret, 10);
1104
str = ret;
1105
break;
1106
1107
case 'y':
1108
++str;
1109
*y = strtoul(str, &ret, 10);
1110
str = ret;
1111
break;
1112
1113
case 'w':
1114
++str;
1115
tmp = strtoul(str, &ret, 10);
1116
*width = tmp > 80 ? tmp : 80; /* 80 is chosen arbitrarily */
1117
str = ret;
1118
break;
1119
1120
/*
1121
* Prevent setting height to less than 50. If the height is set to less,
1122
* the text of the Y axis labels on the graph will start overlapping.
1123
*/
1124
case 'h':
1125
++str;
1126
tmp = strtoul(str, &ret, 10);
1127
*height = tmp > 50 ? tmp : 50;
1128
str = ret;
1129
break;
1130
1131
case 'c':
1132
++str;
1133
tmp = strtoul(str, &ret, 10);
1134
*ceiling = tmp > 10 ? tmp : 10;
1135
str = ret;
1136
break;
1137
1138
case 'd':
1139
++str;
1140
ret = str;
1141
*dyn_ceiling = true;
1142
break;
1143
1144
case 'r':
1145
++str;
1146
ret = str;
1147
*reset_colors = true;
1148
break;
1149
1150
case 's':
1151
++str;
1152
ret = str;
1153
*sort_items = true;
1154
break;
1155
1156
default:
1157
fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *str);
1158
fflush(stderr);
1159
}
1160
1161
}
1162
1163
return ret;
1164
}
1165
1166
static boolean
1167
has_occlusion_query(struct pipe_screen *screen)
1168
{
1169
return screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY) != 0;
1170
}
1171
1172
static boolean
1173
has_streamout(struct pipe_screen *screen)
1174
{
1175
return screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0;
1176
}
1177
1178
static boolean
1179
has_pipeline_stats_query(struct pipe_screen *screen)
1180
{
1181
return screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS) != 0;
1182
}
1183
1184
static void
1185
hud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen,
1186
const char *env)
1187
{
1188
unsigned num, i;
1189
char name_a[256], s[256];
1190
char *name;
1191
struct hud_pane *pane = NULL;
1192
unsigned x = 10, y = 10, y_simple = 10;
1193
unsigned width = 251, height = 100;
1194
unsigned period = 500 * 1000; /* default period (1/2 second) */
1195
uint64_t ceiling = UINT64_MAX;
1196
unsigned column_width = 251;
1197
boolean dyn_ceiling = false;
1198
boolean reset_colors = false;
1199
boolean sort_items = false;
1200
const char *period_env;
1201
1202
if (strncmp(env, "simple,", 7) == 0) {
1203
hud->simple = true;
1204
env += 7;
1205
}
1206
1207
/*
1208
* The GALLIUM_HUD_PERIOD env var sets the graph update rate.
1209
* The env var is in seconds (a float).
1210
* Zero means update after every frame.
1211
*/
1212
period_env = getenv("GALLIUM_HUD_PERIOD");
1213
if (period_env) {
1214
float p = (float) atof(period_env);
1215
if (p >= 0.0f) {
1216
period = (unsigned) (p * 1000 * 1000);
1217
}
1218
}
1219
1220
while ((num = parse_string(env, name_a)) != 0) {
1221
bool added = true;
1222
1223
env += num;
1224
1225
/* check for explicit location, size and etc. settings */
1226
name = read_pane_settings(name_a, &x, &y, &width, &height, &ceiling,
1227
&dyn_ceiling, &reset_colors, &sort_items);
1228
1229
/*
1230
* Keep track of overall column width to avoid pane overlapping in case
1231
* later we create a new column while the bottom pane in the current
1232
* column is less wide than the rest of the panes in it.
1233
*/
1234
column_width = width > column_width ? width : column_width;
1235
1236
if (!pane) {
1237
pane = hud_pane_create(hud, x, y, x + width, y + height, y_simple,
1238
period, 10, ceiling, dyn_ceiling, sort_items);
1239
if (!pane)
1240
return;
1241
}
1242
1243
if (reset_colors) {
1244
pane->next_color = 0;
1245
reset_colors = false;
1246
}
1247
1248
/* Add a graph. */
1249
#if defined(HAVE_GALLIUM_EXTRA_HUD) || defined(HAVE_LIBSENSORS)
1250
char arg_name[64];
1251
#endif
1252
/* IF YOU CHANGE THIS, UPDATE print_help! */
1253
if (strcmp(name, "fps") == 0) {
1254
hud_fps_graph_install(pane);
1255
}
1256
else if (strcmp(name, "frametime") == 0) {
1257
hud_frametime_graph_install(pane);
1258
}
1259
else if (strcmp(name, "cpu") == 0) {
1260
hud_cpu_graph_install(pane, ALL_CPUS);
1261
}
1262
else if (sscanf(name, "cpu%u%s", &i, s) == 1) {
1263
hud_cpu_graph_install(pane, i);
1264
}
1265
else if (strcmp(name, "API-thread-busy") == 0) {
1266
hud_thread_busy_install(pane, name, false);
1267
}
1268
else if (strcmp(name, "API-thread-offloaded-slots") == 0) {
1269
hud_thread_counter_install(pane, name, HUD_COUNTER_OFFLOADED);
1270
}
1271
else if (strcmp(name, "API-thread-direct-slots") == 0) {
1272
hud_thread_counter_install(pane, name, HUD_COUNTER_DIRECT);
1273
}
1274
else if (strcmp(name, "API-thread-num-syncs") == 0) {
1275
hud_thread_counter_install(pane, name, HUD_COUNTER_SYNCS);
1276
}
1277
else if (strcmp(name, "main-thread-busy") == 0) {
1278
hud_thread_busy_install(pane, name, true);
1279
}
1280
#ifdef HAVE_GALLIUM_EXTRA_HUD
1281
else if (sscanf(name, "nic-rx-%s", arg_name) == 1) {
1282
hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX);
1283
}
1284
else if (sscanf(name, "nic-tx-%s", arg_name) == 1) {
1285
hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_TX);
1286
}
1287
else if (sscanf(name, "nic-rssi-%s", arg_name) == 1) {
1288
hud_nic_graph_install(pane, arg_name, NIC_RSSI_DBM);
1289
pane->type = PIPE_DRIVER_QUERY_TYPE_DBM;
1290
}
1291
else if (sscanf(name, "diskstat-rd-%s", arg_name) == 1) {
1292
hud_diskstat_graph_install(pane, arg_name, DISKSTAT_RD);
1293
pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES;
1294
}
1295
else if (sscanf(name, "diskstat-wr-%s", arg_name) == 1) {
1296
hud_diskstat_graph_install(pane, arg_name, DISKSTAT_WR);
1297
pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES;
1298
}
1299
else if (sscanf(name, "cpufreq-min-cpu%u", &i) == 1) {
1300
hud_cpufreq_graph_install(pane, i, CPUFREQ_MINIMUM);
1301
pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
1302
}
1303
else if (sscanf(name, "cpufreq-cur-cpu%u", &i) == 1) {
1304
hud_cpufreq_graph_install(pane, i, CPUFREQ_CURRENT);
1305
pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
1306
}
1307
else if (sscanf(name, "cpufreq-max-cpu%u", &i) == 1) {
1308
hud_cpufreq_graph_install(pane, i, CPUFREQ_MAXIMUM);
1309
pane->type = PIPE_DRIVER_QUERY_TYPE_HZ;
1310
}
1311
#endif
1312
#ifdef HAVE_LIBSENSORS
1313
else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) {
1314
hud_sensors_temp_graph_install(pane, arg_name,
1315
SENSORS_TEMP_CURRENT);
1316
pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE;
1317
}
1318
else if (sscanf(name, "sensors_temp_cr-%s", arg_name) == 1) {
1319
hud_sensors_temp_graph_install(pane, arg_name,
1320
SENSORS_TEMP_CRITICAL);
1321
pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE;
1322
}
1323
else if (sscanf(name, "sensors_volt_cu-%s", arg_name) == 1) {
1324
hud_sensors_temp_graph_install(pane, arg_name,
1325
SENSORS_VOLTAGE_CURRENT);
1326
pane->type = PIPE_DRIVER_QUERY_TYPE_VOLTS;
1327
}
1328
else if (sscanf(name, "sensors_curr_cu-%s", arg_name) == 1) {
1329
hud_sensors_temp_graph_install(pane, arg_name,
1330
SENSORS_CURRENT_CURRENT);
1331
pane->type = PIPE_DRIVER_QUERY_TYPE_AMPS;
1332
}
1333
else if (sscanf(name, "sensors_pow_cu-%s", arg_name) == 1) {
1334
hud_sensors_temp_graph_install(pane, arg_name,
1335
SENSORS_POWER_CURRENT);
1336
pane->type = PIPE_DRIVER_QUERY_TYPE_WATTS;
1337
}
1338
#endif
1339
else if (strcmp(name, "samples-passed") == 0 &&
1340
has_occlusion_query(screen)) {
1341
hud_pipe_query_install(&hud->batch_query, pane,
1342
"samples-passed",
1343
PIPE_QUERY_OCCLUSION_COUNTER, 0, 0,
1344
PIPE_DRIVER_QUERY_TYPE_UINT64,
1345
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
1346
0);
1347
}
1348
else if (strcmp(name, "primitives-generated") == 0 &&
1349
has_streamout(screen)) {
1350
hud_pipe_query_install(&hud->batch_query, pane,
1351
"primitives-generated",
1352
PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0,
1353
PIPE_DRIVER_QUERY_TYPE_UINT64,
1354
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
1355
0);
1356
}
1357
else {
1358
boolean processed = FALSE;
1359
1360
/* pipeline statistics queries */
1361
if (has_pipeline_stats_query(screen)) {
1362
static const char *pipeline_statistics_names[] =
1363
{
1364
"ia-vertices",
1365
"ia-primitives",
1366
"vs-invocations",
1367
"gs-invocations",
1368
"gs-primitives",
1369
"clipper-invocations",
1370
"clipper-primitives-generated",
1371
"ps-invocations",
1372
"hs-invocations",
1373
"ds-invocations",
1374
"cs-invocations"
1375
};
1376
for (i = 0; i < ARRAY_SIZE(pipeline_statistics_names); ++i)
1377
if (strcmp(name, pipeline_statistics_names[i]) == 0)
1378
break;
1379
if (i < ARRAY_SIZE(pipeline_statistics_names)) {
1380
hud_pipe_query_install(&hud->batch_query, pane, name,
1381
PIPE_QUERY_PIPELINE_STATISTICS, i,
1382
0, PIPE_DRIVER_QUERY_TYPE_UINT64,
1383
PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
1384
0);
1385
processed = TRUE;
1386
}
1387
}
1388
1389
/* driver queries */
1390
if (!processed) {
1391
if (!hud_driver_query_install(&hud->batch_query, pane,
1392
screen, name)) {
1393
fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name);
1394
fflush(stderr);
1395
added = false;
1396
}
1397
}
1398
}
1399
1400
if (*env == ':') {
1401
env++;
1402
1403
if (!pane) {
1404
fprintf(stderr, "gallium_hud: syntax error: unexpected ':', "
1405
"expected a name\n");
1406
fflush(stderr);
1407
break;
1408
}
1409
1410
num = parse_string(env, s);
1411
env += num;
1412
1413
if (num && sscanf(s, "%u", &i) == 1) {
1414
hud_pane_set_max_value(pane, i);
1415
pane->initial_max_value = i;
1416
}
1417
else {
1418
fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) "
1419
"after ':'\n", *env, *env);
1420
fflush(stderr);
1421
}
1422
}
1423
1424
if (*env == '=') {
1425
env++;
1426
1427
if (!pane) {
1428
fprintf(stderr, "gallium_hud: syntax error: unexpected '=', "
1429
"expected a name\n");
1430
fflush(stderr);
1431
break;
1432
}
1433
1434
num = parse_string(env, s);
1435
env += num;
1436
1437
strip_hyphens(s);
1438
if (added && !list_is_empty(&pane->graph_list)) {
1439
struct hud_graph *graph;
1440
graph = LIST_ENTRY(struct hud_graph, pane->graph_list.prev, head);
1441
strncpy(graph->name, s, sizeof(graph->name)-1);
1442
graph->name[sizeof(graph->name)-1] = 0;
1443
}
1444
}
1445
1446
if (*env == 0)
1447
break;
1448
1449
/* parse a separator */
1450
switch (*env) {
1451
case '+':
1452
env++;
1453
break;
1454
1455
case ',':
1456
env++;
1457
if (!pane)
1458
break;
1459
1460
y += height + hud->font.glyph_height * (pane->num_graphs + 2);
1461
y_simple += hud->font.glyph_height * (pane->num_graphs + 1);
1462
height = 100;
1463
1464
if (pane && pane->num_graphs) {
1465
list_addtail(&pane->head, &hud->pane_list);
1466
pane = NULL;
1467
}
1468
break;
1469
1470
case ';':
1471
env++;
1472
y = 10;
1473
y_simple = 10;
1474
x += column_width + hud->font.glyph_width * 9;
1475
height = 100;
1476
1477
if (pane && pane->num_graphs) {
1478
list_addtail(&pane->head, &hud->pane_list);
1479
pane = NULL;
1480
}
1481
1482
/* Starting a new column; reset column width. */
1483
column_width = 251;
1484
break;
1485
1486
default:
1487
fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *env);
1488
fflush(stderr);
1489
}
1490
1491
/* Reset to defaults for the next pane in case these were modified. */
1492
width = 251;
1493
ceiling = UINT64_MAX;
1494
dyn_ceiling = false;
1495
sort_items = false;
1496
1497
}
1498
1499
if (pane) {
1500
if (pane->num_graphs) {
1501
list_addtail(&pane->head, &hud->pane_list);
1502
}
1503
else {
1504
FREE(pane);
1505
}
1506
}
1507
1508
LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
1509
struct hud_graph *gr;
1510
1511
LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
1512
hud_graph_set_dump_file(gr);
1513
}
1514
}
1515
}
1516
1517
static void
1518
print_help(struct pipe_screen *screen)
1519
{
1520
int i, num_queries, num_cpus = hud_get_num_cpus();
1521
1522
puts("Syntax: GALLIUM_HUD=name1[+name2][...][:value1][,nameI...][;nameJ...]");
1523
puts("");
1524
puts(" Names are identifiers of data sources which will be drawn as graphs");
1525
puts(" in panes. Multiple graphs can be drawn in the same pane.");
1526
puts(" There can be multiple panes placed in rows and columns.");
1527
puts("");
1528
puts(" '+' separates names which will share a pane.");
1529
puts(" ':[value]' specifies the initial maximum value of the Y axis");
1530
puts(" for the given pane.");
1531
puts(" ',' creates a new pane below the last one.");
1532
puts(" ';' creates a new pane at the top of the next column.");
1533
puts(" '=' followed by a string, changes the name of the last data source");
1534
puts(" to that string");
1535
puts("");
1536
puts(" Example: GALLIUM_HUD=\"cpu,fps;primitives-generated\"");
1537
puts("");
1538
puts(" Additionally, by prepending '.[identifier][value]' modifiers to");
1539
puts(" a name, it is possible to explicitly set the location and size");
1540
puts(" of a pane, along with limiting overall maximum value of the");
1541
puts(" Y axis and activating dynamic readjustment of the Y axis.");
1542
puts(" Several modifiers may be applied to the same pane simultaneously.");
1543
puts("");
1544
puts(" 'x[value]' sets the location of the pane on the x axis relative");
1545
puts(" to the upper-left corner of the viewport, in pixels.");
1546
puts(" 'y[value]' sets the location of the pane on the y axis relative");
1547
puts(" to the upper-left corner of the viewport, in pixels.");
1548
puts(" 'w[value]' sets width of the graph pixels.");
1549
puts(" 'h[value]' sets height of the graph in pixels.");
1550
puts(" 'c[value]' sets the ceiling of the value of the Y axis.");
1551
puts(" If the graph needs to draw values higher than");
1552
puts(" the ceiling allows, the value is clamped.");
1553
puts(" 'd' activates dynamic Y axis readjustment to set the value of");
1554
puts(" the Y axis to match the highest value still visible in the graph.");
1555
puts(" 'r' resets the color counter (the next color will be green)");
1556
puts(" 's' sort items below graphs in descending order");
1557
puts("");
1558
puts(" If 'c' and 'd' modifiers are used simultaneously, both are in effect:");
1559
puts(" the Y axis does not go above the restriction imposed by 'c' while");
1560
puts(" still adjusting the value of the Y axis down when appropriate.");
1561
puts("");
1562
puts(" You can change behavior of the whole HUD by adding these options at");
1563
puts(" the beginning of the environment variable:");
1564
puts(" 'simple,' disables all the fancy stuff and only draws text.");
1565
puts("");
1566
puts(" Example: GALLIUM_HUD=\".w256.h64.x1600.y520.d.c1000fps+cpu,.datom-count\"");
1567
puts("");
1568
puts(" Available names:");
1569
puts(" fps");
1570
puts(" frametime");
1571
puts(" cpu");
1572
1573
for (i = 0; i < num_cpus; i++)
1574
printf(" cpu%i\n", i);
1575
1576
if (has_occlusion_query(screen))
1577
puts(" samples-passed");
1578
if (has_streamout(screen))
1579
puts(" primitives-generated");
1580
1581
if (has_pipeline_stats_query(screen)) {
1582
puts(" ia-vertices");
1583
puts(" ia-primitives");
1584
puts(" vs-invocations");
1585
puts(" gs-invocations");
1586
puts(" gs-primitives");
1587
puts(" clipper-invocations");
1588
puts(" clipper-primitives-generated");
1589
puts(" ps-invocations");
1590
puts(" hs-invocations");
1591
puts(" ds-invocations");
1592
puts(" cs-invocations");
1593
}
1594
1595
#ifdef HAVE_GALLIUM_EXTRA_HUD
1596
hud_get_num_disks(1);
1597
hud_get_num_nics(1);
1598
hud_get_num_cpufreq(1);
1599
#endif
1600
#ifdef HAVE_LIBSENSORS
1601
hud_get_num_sensors(1);
1602
#endif
1603
1604
if (screen->get_driver_query_info){
1605
boolean skipping = false;
1606
struct pipe_driver_query_info info;
1607
num_queries = screen->get_driver_query_info(screen, 0, NULL);
1608
1609
for (i = 0; i < num_queries; i++){
1610
screen->get_driver_query_info(screen, i, &info);
1611
if (info.flags & PIPE_DRIVER_QUERY_FLAG_DONT_LIST) {
1612
if (!skipping)
1613
puts(" ...");
1614
skipping = true;
1615
} else {
1616
printf(" %s\n", info.name);
1617
skipping = false;
1618
}
1619
}
1620
}
1621
1622
puts("");
1623
fflush(stdout);
1624
}
1625
1626
static void
1627
hud_unset_draw_context(struct hud_context *hud)
1628
{
1629
struct pipe_context *pipe = hud->pipe;
1630
1631
if (!pipe)
1632
return;
1633
1634
pipe_sampler_view_reference(&hud->font_sampler_view, NULL);
1635
1636
if (hud->fs_color) {
1637
pipe->delete_fs_state(pipe, hud->fs_color);
1638
hud->fs_color = NULL;
1639
}
1640
if (hud->fs_text) {
1641
pipe->delete_fs_state(pipe, hud->fs_text);
1642
hud->fs_text = NULL;
1643
}
1644
if (hud->vs_color) {
1645
pipe->delete_vs_state(pipe, hud->vs_color);
1646
hud->vs_color = NULL;
1647
}
1648
if (hud->vs_text) {
1649
pipe->delete_vs_state(pipe, hud->vs_text);
1650
hud->vs_text = NULL;
1651
}
1652
1653
hud->cso = NULL;
1654
hud->pipe = NULL;
1655
}
1656
1657
static bool
1658
hud_set_draw_context(struct hud_context *hud, struct cso_context *cso,
1659
struct st_context_iface *st)
1660
{
1661
struct pipe_context *pipe = cso_get_pipe_context(cso);
1662
1663
assert(!hud->pipe);
1664
hud->pipe = pipe;
1665
hud->cso = cso;
1666
hud->st = st;
1667
1668
struct pipe_sampler_view view_templ;
1669
u_sampler_view_default_template(
1670
&view_templ, hud->font.texture, hud->font.texture->format);
1671
hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture,
1672
&view_templ);
1673
if (!hud->font_sampler_view)
1674
goto fail;
1675
1676
/* color fragment shader */
1677
hud->fs_color =
1678
util_make_fragment_passthrough_shader(pipe,
1679
TGSI_SEMANTIC_COLOR,
1680
TGSI_INTERPOLATE_CONSTANT,
1681
TRUE);
1682
1683
/* text fragment shader */
1684
{
1685
/* Read a texture and do .xxxx swizzling. */
1686
static const char *fragment_shader_text = {
1687
"FRAG\n"
1688
"DCL IN[0], GENERIC[0], LINEAR\n"
1689
"DCL SAMP[0]\n"
1690
"DCL SVIEW[0], RECT, FLOAT\n"
1691
"DCL OUT[0], COLOR[0]\n"
1692
"DCL TEMP[0]\n"
1693
1694
"TEX TEMP[0], IN[0], SAMP[0], RECT\n"
1695
"MOV OUT[0], TEMP[0].xxxx\n"
1696
"END\n"
1697
};
1698
1699
struct tgsi_token tokens[1000];
1700
struct pipe_shader_state state = {0};
1701
1702
if (!tgsi_text_translate(fragment_shader_text, tokens, ARRAY_SIZE(tokens))) {
1703
assert(0);
1704
goto fail;
1705
}
1706
pipe_shader_state_from_tgsi(&state, tokens);
1707
hud->fs_text = pipe->create_fs_state(pipe, &state);
1708
}
1709
1710
/* color vertex shader */
1711
{
1712
static const char *vertex_shader_text = {
1713
"VERT\n"
1714
"DCL IN[0..1]\n"
1715
"DCL OUT[0], POSITION\n"
1716
"DCL OUT[1], COLOR[0]\n" /* color */
1717
"DCL OUT[2], GENERIC[0]\n" /* texcoord */
1718
/* [0] = color,
1719
* [1] = (2/fb_width, 2/fb_height, xoffset, yoffset)
1720
* [2] = (xscale, yscale, 0, 0) */
1721
"DCL CONST[0][0..2]\n"
1722
"DCL TEMP[0]\n"
1723
"IMM[0] FLT32 { -1, 0, 0, 1 }\n"
1724
1725
/* v = in * (xscale, yscale) + (xoffset, yoffset) */
1726
"MAD TEMP[0].xy, IN[0], CONST[0][2].xyyy, CONST[0][1].zwww\n"
1727
/* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */
1728
"MAD OUT[0].xy, TEMP[0], CONST[0][1].xyyy, IMM[0].xxxx\n"
1729
"MOV OUT[0].zw, IMM[0]\n"
1730
1731
"MOV OUT[1], CONST[0][0]\n"
1732
"MOV OUT[2], IN[1]\n"
1733
"END\n"
1734
};
1735
1736
struct tgsi_token tokens[1000];
1737
struct pipe_shader_state state = {0};
1738
if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) {
1739
assert(0);
1740
goto fail;
1741
}
1742
pipe_shader_state_from_tgsi(&state, tokens);
1743
hud->vs_color = pipe->create_vs_state(pipe, &state);
1744
}
1745
1746
/* text vertex shader */
1747
{
1748
/* similar to the above, without the color component
1749
* to match the varyings in fs_text */
1750
static const char *vertex_shader_text = {
1751
"VERT\n"
1752
"DCL IN[0..1]\n"
1753
"DCL OUT[0], POSITION\n"
1754
"DCL OUT[1], GENERIC[0]\n" /* texcoord */
1755
/* [0] = color,
1756
* [1] = (2/fb_width, 2/fb_height, xoffset, yoffset)
1757
* [2] = (xscale, yscale, 0, 0) */
1758
"DCL CONST[0][0..2]\n"
1759
"DCL TEMP[0]\n"
1760
"IMM[0] FLT32 { -1, 0, 0, 1 }\n"
1761
1762
/* v = in * (xscale, yscale) + (xoffset, yoffset) */
1763
"MAD TEMP[0].xy, IN[0], CONST[0][2].xyyy, CONST[0][1].zwww\n"
1764
/* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */
1765
"MAD OUT[0].xy, TEMP[0], CONST[0][1].xyyy, IMM[0].xxxx\n"
1766
"MOV OUT[0].zw, IMM[0]\n"
1767
1768
"MOV OUT[1], IN[1]\n"
1769
"END\n"
1770
};
1771
1772
struct tgsi_token tokens[1000];
1773
struct pipe_shader_state state = {0};
1774
if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) {
1775
assert(0);
1776
goto fail;
1777
}
1778
pipe_shader_state_from_tgsi(&state, tokens);
1779
hud->vs_text = pipe->create_vs_state(pipe, &state);
1780
}
1781
1782
return true;
1783
1784
fail:
1785
hud_unset_draw_context(hud);
1786
fprintf(stderr, "hud: failed to set a draw context");
1787
return false;
1788
}
1789
1790
static void
1791
hud_unset_record_context(struct hud_context *hud)
1792
{
1793
struct pipe_context *pipe = hud->record_pipe;
1794
struct hud_pane *pane, *pane_tmp;
1795
struct hud_graph *graph, *graph_tmp;
1796
1797
if (!pipe)
1798
return;
1799
1800
LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) {
1801
LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) {
1802
list_del(&graph->head);
1803
hud_graph_destroy(graph, pipe);
1804
}
1805
list_del(&pane->head);
1806
FREE(pane);
1807
}
1808
1809
hud_batch_query_cleanup(&hud->batch_query, pipe);
1810
hud->record_pipe = NULL;
1811
}
1812
1813
static void
1814
hud_set_record_context(struct hud_context *hud, struct pipe_context *pipe)
1815
{
1816
hud->record_pipe = pipe;
1817
}
1818
1819
/**
1820
* Create the HUD.
1821
*
1822
* If "share" is non-NULL and GALLIUM_HUD_SHARE=x,y is set, increment the
1823
* reference counter of "share", set "cso" as the recording or drawing context
1824
* according to the environment variable, and return "share".
1825
* This allows sharing the HUD instance within a multi-context share group,
1826
* record queries in one context and draw them in another.
1827
*/
1828
struct hud_context *
1829
hud_create(struct cso_context *cso, struct st_context_iface *st,
1830
struct hud_context *share)
1831
{
1832
const char *share_env = debug_get_option("GALLIUM_HUD_SHARE", NULL);
1833
unsigned record_ctx = 0, draw_ctx = 0;
1834
1835
if (share_env && sscanf(share_env, "%u,%u", &record_ctx, &draw_ctx) != 2)
1836
share_env = NULL;
1837
1838
if (share && share_env) {
1839
/* All contexts in a share group share the HUD instance.
1840
* Only one context can record queries and only one context
1841
* can draw the HUD.
1842
*
1843
* GALLIUM_HUD_SHARE=x,y determines the context indices.
1844
*/
1845
int context_id = p_atomic_inc_return(&share->refcount) - 1;
1846
1847
if (context_id == record_ctx) {
1848
assert(!share->record_pipe);
1849
hud_set_record_context(share, cso_get_pipe_context(cso));
1850
}
1851
1852
if (context_id == draw_ctx) {
1853
assert(!share->pipe);
1854
hud_set_draw_context(share, cso, st);
1855
}
1856
1857
return share;
1858
}
1859
1860
struct pipe_screen *screen = cso_get_pipe_context(cso)->screen;
1861
struct hud_context *hud;
1862
unsigned i;
1863
const char *env = debug_get_option("GALLIUM_HUD", NULL);
1864
#ifdef PIPE_OS_UNIX
1865
unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0);
1866
static boolean sig_handled = FALSE;
1867
struct sigaction action;
1868
1869
memset(&action, 0, sizeof(action));
1870
#endif
1871
huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE);
1872
hud_scale = debug_get_num_option("GALLIUM_HUD_SCALE", 1);
1873
1874
if (!env || !*env)
1875
return NULL;
1876
1877
if (strcmp(env, "help") == 0) {
1878
print_help(screen);
1879
return NULL;
1880
}
1881
1882
hud = CALLOC_STRUCT(hud_context);
1883
if (!hud)
1884
return NULL;
1885
1886
/* font (the context is only used for the texture upload) */
1887
if (!util_font_create(cso_get_pipe_context(cso),
1888
UTIL_FONT_FIXED_8X13, &hud->font)) {
1889
FREE(hud);
1890
return NULL;
1891
}
1892
1893
hud->refcount = 1;
1894
1895
static const enum pipe_format srgb_formats[] = {
1896
PIPE_FORMAT_B8G8R8A8_SRGB,
1897
PIPE_FORMAT_B8G8R8X8_SRGB
1898
};
1899
for (i = 0; i < ARRAY_SIZE(srgb_formats); i++) {
1900
if (!screen->is_format_supported(screen, srgb_formats[i],
1901
PIPE_TEXTURE_2D, 0, 0,
1902
PIPE_BIND_RENDER_TARGET))
1903
break;
1904
}
1905
1906
hud->has_srgb = (i == ARRAY_SIZE(srgb_formats));
1907
1908
/* blend state */
1909
hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA;
1910
1911
hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA;
1912
hud->alpha_blend.rt[0].blend_enable = 1;
1913
hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD;
1914
hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
1915
hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
1916
hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD;
1917
hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
1918
hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
1919
1920
/* rasterizer */
1921
hud->rasterizer.half_pixel_center = 1;
1922
hud->rasterizer.bottom_edge_rule = 1;
1923
hud->rasterizer.depth_clip_near = 1;
1924
hud->rasterizer.depth_clip_far = 1;
1925
hud->rasterizer.line_width = 1;
1926
hud->rasterizer.line_last_pixel = 1;
1927
1928
hud->rasterizer_aa_lines = hud->rasterizer;
1929
hud->rasterizer_aa_lines.line_smooth = 1;
1930
1931
/* vertex elements */
1932
hud->velems.count = 2;
1933
for (i = 0; i < 2; i++) {
1934
hud->velems.velems[i].src_offset = i * 2 * sizeof(float);
1935
hud->velems.velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT;
1936
hud->velems.velems[i].vertex_buffer_index = 0;
1937
}
1938
1939
/* sampler state (for font drawing) */
1940
hud->font_sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1941
hud->font_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1942
hud->font_sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1943
hud->font_sampler_state.normalized_coords = 0;
1944
1945
/* constants */
1946
hud->constbuf.buffer_size = sizeof(hud->constants);
1947
hud->constbuf.user_buffer = &hud->constants;
1948
1949
list_inithead(&hud->pane_list);
1950
1951
/* setup sig handler once for all hud contexts */
1952
#ifdef PIPE_OS_UNIX
1953
if (!sig_handled && signo != 0) {
1954
action.sa_sigaction = &signal_visible_handler;
1955
action.sa_flags = SA_SIGINFO;
1956
1957
if (signo >= NSIG)
1958
fprintf(stderr, "gallium_hud: invalid signal %u\n", signo);
1959
else if (sigaction(signo, &action, NULL) < 0)
1960
fprintf(stderr, "gallium_hud: unable to set handler for signal %u\n", signo);
1961
fflush(stderr);
1962
1963
sig_handled = TRUE;
1964
}
1965
#endif
1966
1967
if (record_ctx == 0)
1968
hud_set_record_context(hud, cso_get_pipe_context(cso));
1969
if (draw_ctx == 0)
1970
hud_set_draw_context(hud, cso, st);
1971
1972
hud_parse_env_var(hud, screen, env);
1973
return hud;
1974
}
1975
1976
/**
1977
* Destroy a HUD. If the HUD has several users, decrease the reference counter
1978
* and detach the context from the HUD.
1979
*/
1980
void
1981
hud_destroy(struct hud_context *hud, struct cso_context *cso)
1982
{
1983
if (!cso || hud->record_pipe == cso_get_pipe_context(cso))
1984
hud_unset_record_context(hud);
1985
1986
if (!cso || hud->cso == cso)
1987
hud_unset_draw_context(hud);
1988
1989
if (p_atomic_dec_zero(&hud->refcount)) {
1990
pipe_resource_reference(&hud->font.texture, NULL);
1991
FREE(hud);
1992
}
1993
}
1994
1995
void
1996
hud_add_queue_for_monitoring(struct hud_context *hud,
1997
struct util_queue_monitoring *queue_info)
1998
{
1999
assert(!hud->monitored_queue);
2000
hud->monitored_queue = queue_info;
2001
}
2002
2003