1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2013 Marek Olšák <maraeo@gmail.com> 4848b8605Smrg * All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the 8848b8605Smrg * "Software"), to deal in the Software without restriction, including 9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 12848b8605Smrg * the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice (including the 15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 16848b8605Smrg * of the Software. 17848b8605Smrg * 18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21848b8605Smrg * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25848b8605Smrg * 26848b8605Smrg **************************************************************************/ 27848b8605Smrg 28848b8605Smrg/* This head-up display module can draw transparent graphs on top of what 29848b8605Smrg * the app is rendering, visualizing various data like framerate, cpu load, 30848b8605Smrg * performance counters, etc. It can be hook up into any state tracker. 31848b8605Smrg * 32848b8605Smrg * The HUD is controlled with the GALLIUM_HUD environment variable. 33848b8605Smrg * Set GALLIUM_HUD=help for more info. 34848b8605Smrg */ 35848b8605Smrg 36b8e80941Smrg#include <inttypes.h> 37b8e80941Smrg#include <signal.h> 38848b8605Smrg#include <stdio.h> 39848b8605Smrg 40848b8605Smrg#include "hud/hud_context.h" 41848b8605Smrg#include "hud/hud_private.h" 42848b8605Smrg 43848b8605Smrg#include "cso_cache/cso_context.h" 44848b8605Smrg#include "util/u_draw_quad.h" 45b8e80941Smrg#include "util/u_format.h" 46848b8605Smrg#include "util/u_inlines.h" 47848b8605Smrg#include "util/u_memory.h" 48848b8605Smrg#include "util/u_math.h" 49b8e80941Smrg#include "util/u_sampler.h" 50848b8605Smrg#include "util/u_simple_shaders.h" 51848b8605Smrg#include "util/u_string.h" 52848b8605Smrg#include "util/u_upload_mgr.h" 53848b8605Smrg#include "tgsi/tgsi_text.h" 54848b8605Smrg#include "tgsi/tgsi_dump.h" 55848b8605Smrg 56b8e80941Smrg/* Control the visibility of all HUD contexts */ 57b8e80941Smrgstatic boolean huds_visible = TRUE; 58848b8605Smrg 59848b8605Smrg 60b8e80941Smrg#ifdef PIPE_OS_UNIX 61b8e80941Smrgstatic void 62b8e80941Smrgsignal_visible_handler(int sig, siginfo_t *siginfo, void *context) 63b8e80941Smrg{ 64b8e80941Smrg huds_visible = !huds_visible; 65b8e80941Smrg} 66b8e80941Smrg#endif 67848b8605Smrg 68848b8605Smrgstatic void 69848b8605Smrghud_draw_colored_prims(struct hud_context *hud, unsigned prim, 70848b8605Smrg float *buffer, unsigned num_vertices, 71848b8605Smrg float r, float g, float b, float a, 72848b8605Smrg int xoffset, int yoffset, float yscale) 73848b8605Smrg{ 74848b8605Smrg struct cso_context *cso = hud->cso; 75b8e80941Smrg unsigned size = num_vertices * hud->color_prims.vbuf.stride; 76b8e80941Smrg 77b8e80941Smrg /* If a recording context is inactive, don't draw anything. */ 78b8e80941Smrg if (size > hud->color_prims.buffer_size) 79b8e80941Smrg return; 80b8e80941Smrg 81b8e80941Smrg memcpy(hud->color_prims.vertices, buffer, size); 82848b8605Smrg 83848b8605Smrg hud->constants.color[0] = r; 84848b8605Smrg hud->constants.color[1] = g; 85848b8605Smrg hud->constants.color[2] = b; 86848b8605Smrg hud->constants.color[3] = a; 87848b8605Smrg hud->constants.translate[0] = (float) xoffset; 88848b8605Smrg hud->constants.translate[1] = (float) yoffset; 89848b8605Smrg hud->constants.scale[0] = 1; 90848b8605Smrg hud->constants.scale[1] = yscale; 91848b8605Smrg cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); 92848b8605Smrg 93b8e80941Smrg cso_set_vertex_buffers(cso, 0, 1, &hud->color_prims.vbuf); 94848b8605Smrg cso_set_fragment_shader_handle(hud->cso, hud->fs_color); 95848b8605Smrg cso_draw_arrays(cso, prim, 0, num_vertices); 96b8e80941Smrg 97b8e80941Smrg hud->color_prims.vertices += size / sizeof(float); 98b8e80941Smrg hud->color_prims.vbuf.buffer_offset += size; 99b8e80941Smrg hud->color_prims.buffer_size -= size; 100848b8605Smrg} 101848b8605Smrg 102848b8605Smrgstatic void 103848b8605Smrghud_draw_colored_quad(struct hud_context *hud, unsigned prim, 104848b8605Smrg unsigned x1, unsigned y1, unsigned x2, unsigned y2, 105848b8605Smrg float r, float g, float b, float a) 106848b8605Smrg{ 107848b8605Smrg float buffer[] = { 108848b8605Smrg (float) x1, (float) y1, 109848b8605Smrg (float) x1, (float) y2, 110848b8605Smrg (float) x2, (float) y2, 111848b8605Smrg (float) x2, (float) y1, 112848b8605Smrg }; 113848b8605Smrg 114848b8605Smrg hud_draw_colored_prims(hud, prim, buffer, 4, r, g, b, a, 0, 0, 1); 115848b8605Smrg} 116848b8605Smrg 117848b8605Smrgstatic void 118848b8605Smrghud_draw_background_quad(struct hud_context *hud, 119848b8605Smrg unsigned x1, unsigned y1, unsigned x2, unsigned y2) 120848b8605Smrg{ 121848b8605Smrg float *vertices = hud->bg.vertices + hud->bg.num_vertices*2; 122848b8605Smrg unsigned num = 0; 123848b8605Smrg 124848b8605Smrg assert(hud->bg.num_vertices + 4 <= hud->bg.max_num_vertices); 125848b8605Smrg 126848b8605Smrg vertices[num++] = (float) x1; 127848b8605Smrg vertices[num++] = (float) y1; 128848b8605Smrg 129848b8605Smrg vertices[num++] = (float) x1; 130848b8605Smrg vertices[num++] = (float) y2; 131848b8605Smrg 132848b8605Smrg vertices[num++] = (float) x2; 133848b8605Smrg vertices[num++] = (float) y2; 134848b8605Smrg 135848b8605Smrg vertices[num++] = (float) x2; 136848b8605Smrg vertices[num++] = (float) y1; 137848b8605Smrg 138848b8605Smrg hud->bg.num_vertices += num/2; 139848b8605Smrg} 140848b8605Smrg 141848b8605Smrgstatic void 142848b8605Smrghud_draw_string(struct hud_context *hud, unsigned x, unsigned y, 143848b8605Smrg const char *str, ...) 144848b8605Smrg{ 145848b8605Smrg char buf[256]; 146848b8605Smrg char *s = buf; 147848b8605Smrg float *vertices = hud->text.vertices + hud->text.num_vertices*4; 148848b8605Smrg unsigned num = 0; 149848b8605Smrg 150848b8605Smrg va_list ap; 151848b8605Smrg va_start(ap, str); 152848b8605Smrg util_vsnprintf(buf, sizeof(buf), str, ap); 153848b8605Smrg va_end(ap); 154848b8605Smrg 155848b8605Smrg if (!*s) 156848b8605Smrg return; 157848b8605Smrg 158848b8605Smrg hud_draw_background_quad(hud, 159848b8605Smrg x, y, 160848b8605Smrg x + strlen(buf)*hud->font.glyph_width, 161848b8605Smrg y + hud->font.glyph_height); 162848b8605Smrg 163848b8605Smrg while (*s) { 164848b8605Smrg unsigned x1 = x; 165848b8605Smrg unsigned y1 = y; 166848b8605Smrg unsigned x2 = x + hud->font.glyph_width; 167848b8605Smrg unsigned y2 = y + hud->font.glyph_height; 168848b8605Smrg unsigned tx1 = (*s % 16) * hud->font.glyph_width; 169848b8605Smrg unsigned ty1 = (*s / 16) * hud->font.glyph_height; 170848b8605Smrg unsigned tx2 = tx1 + hud->font.glyph_width; 171848b8605Smrg unsigned ty2 = ty1 + hud->font.glyph_height; 172848b8605Smrg 173848b8605Smrg if (*s == ' ') { 174848b8605Smrg x += hud->font.glyph_width; 175848b8605Smrg s++; 176848b8605Smrg continue; 177848b8605Smrg } 178848b8605Smrg 179848b8605Smrg assert(hud->text.num_vertices + num/4 + 4 <= hud->text.max_num_vertices); 180848b8605Smrg 181848b8605Smrg vertices[num++] = (float) x1; 182848b8605Smrg vertices[num++] = (float) y1; 183848b8605Smrg vertices[num++] = (float) tx1; 184848b8605Smrg vertices[num++] = (float) ty1; 185848b8605Smrg 186848b8605Smrg vertices[num++] = (float) x1; 187848b8605Smrg vertices[num++] = (float) y2; 188848b8605Smrg vertices[num++] = (float) tx1; 189848b8605Smrg vertices[num++] = (float) ty2; 190848b8605Smrg 191848b8605Smrg vertices[num++] = (float) x2; 192848b8605Smrg vertices[num++] = (float) y2; 193848b8605Smrg vertices[num++] = (float) tx2; 194848b8605Smrg vertices[num++] = (float) ty2; 195848b8605Smrg 196848b8605Smrg vertices[num++] = (float) x2; 197848b8605Smrg vertices[num++] = (float) y1; 198848b8605Smrg vertices[num++] = (float) tx2; 199848b8605Smrg vertices[num++] = (float) ty1; 200848b8605Smrg 201848b8605Smrg x += hud->font.glyph_width; 202848b8605Smrg s++; 203848b8605Smrg } 204848b8605Smrg 205848b8605Smrg hud->text.num_vertices += num/4; 206848b8605Smrg} 207848b8605Smrg 208848b8605Smrgstatic void 209b8e80941Smrgnumber_to_human_readable(double num, enum pipe_driver_query_type type, 210b8e80941Smrg char *out) 211848b8605Smrg{ 212848b8605Smrg static const char *byte_units[] = 213b8e80941Smrg {" B", " KB", " MB", " GB", " TB", " PB", " EB"}; 214848b8605Smrg static const char *metric_units[] = 215848b8605Smrg {"", " k", " M", " G", " T", " P", " E"}; 216b8e80941Smrg static const char *time_units[] = 217b8e80941Smrg {" us", " ms", " s"}; /* based on microseconds */ 218b8e80941Smrg static const char *hz_units[] = 219b8e80941Smrg {" Hz", " KHz", " MHz", " GHz"}; 220b8e80941Smrg static const char *percent_units[] = {"%"}; 221b8e80941Smrg static const char *dbm_units[] = {" (-dBm)"}; 222b8e80941Smrg static const char *temperature_units[] = {" C"}; 223b8e80941Smrg static const char *volt_units[] = {" mV", " V"}; 224b8e80941Smrg static const char *amp_units[] = {" mA", " A"}; 225b8e80941Smrg static const char *watt_units[] = {" mW", " W"}; 226b8e80941Smrg static const char *float_units[] = {""}; 227b8e80941Smrg 228b8e80941Smrg const char **units; 229b8e80941Smrg unsigned max_unit; 230b8e80941Smrg double divisor = (type == PIPE_DRIVER_QUERY_TYPE_BYTES) ? 1024 : 1000; 231b8e80941Smrg unsigned unit = 0; 232848b8605Smrg double d = num; 233848b8605Smrg 234b8e80941Smrg switch (type) { 235b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS: 236b8e80941Smrg max_unit = ARRAY_SIZE(time_units)-1; 237b8e80941Smrg units = time_units; 238b8e80941Smrg break; 239b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_VOLTS: 240b8e80941Smrg max_unit = ARRAY_SIZE(volt_units)-1; 241b8e80941Smrg units = volt_units; 242b8e80941Smrg break; 243b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_AMPS: 244b8e80941Smrg max_unit = ARRAY_SIZE(amp_units)-1; 245b8e80941Smrg units = amp_units; 246b8e80941Smrg break; 247b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_DBM: 248b8e80941Smrg max_unit = ARRAY_SIZE(dbm_units)-1; 249b8e80941Smrg units = dbm_units; 250b8e80941Smrg break; 251b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_TEMPERATURE: 252b8e80941Smrg max_unit = ARRAY_SIZE(temperature_units)-1; 253b8e80941Smrg units = temperature_units; 254b8e80941Smrg break; 255b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_FLOAT: 256b8e80941Smrg max_unit = ARRAY_SIZE(float_units)-1; 257b8e80941Smrg units = float_units; 258b8e80941Smrg break; 259b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE: 260b8e80941Smrg max_unit = ARRAY_SIZE(percent_units)-1; 261b8e80941Smrg units = percent_units; 262b8e80941Smrg break; 263b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_BYTES: 264b8e80941Smrg max_unit = ARRAY_SIZE(byte_units)-1; 265b8e80941Smrg units = byte_units; 266b8e80941Smrg break; 267b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_HZ: 268b8e80941Smrg max_unit = ARRAY_SIZE(hz_units)-1; 269b8e80941Smrg units = hz_units; 270b8e80941Smrg break; 271b8e80941Smrg case PIPE_DRIVER_QUERY_TYPE_WATTS: 272b8e80941Smrg max_unit = ARRAY_SIZE(watt_units)-1; 273b8e80941Smrg units = watt_units; 274b8e80941Smrg break; 275b8e80941Smrg default: 276b8e80941Smrg max_unit = ARRAY_SIZE(metric_units)-1; 277b8e80941Smrg units = metric_units; 278b8e80941Smrg } 279b8e80941Smrg 280b8e80941Smrg while (d > divisor && unit < max_unit) { 281848b8605Smrg d /= divisor; 282848b8605Smrg unit++; 283848b8605Smrg } 284848b8605Smrg 285b8e80941Smrg /* Round to 3 decimal places so as not to print trailing zeros. */ 286b8e80941Smrg if (d*1000 != (int)(d*1000)) 287b8e80941Smrg d = round(d * 1000) / 1000; 288b8e80941Smrg 289b8e80941Smrg /* Show at least 4 digits with at most 3 decimal places, but not zeros. */ 290b8e80941Smrg if (d >= 1000 || d == (int)d) 291848b8605Smrg sprintf(out, "%.0f%s", d, units[unit]); 292b8e80941Smrg else if (d >= 100 || d*10 == (int)(d*10)) 293848b8605Smrg sprintf(out, "%.1f%s", d, units[unit]); 294b8e80941Smrg else if (d >= 10 || d*100 == (int)(d*100)) 295848b8605Smrg sprintf(out, "%.2f%s", d, units[unit]); 296b8e80941Smrg else 297b8e80941Smrg sprintf(out, "%.3f%s", d, units[unit]); 298848b8605Smrg} 299848b8605Smrg 300848b8605Smrgstatic void 301848b8605Smrghud_draw_graph_line_strip(struct hud_context *hud, const struct hud_graph *gr, 302848b8605Smrg unsigned xoffset, unsigned yoffset, float yscale) 303848b8605Smrg{ 304848b8605Smrg if (gr->num_vertices <= 1) 305848b8605Smrg return; 306848b8605Smrg 307848b8605Smrg assert(gr->index <= gr->num_vertices); 308848b8605Smrg 309848b8605Smrg hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP, 310848b8605Smrg gr->vertices, gr->index, 311848b8605Smrg gr->color[0], gr->color[1], gr->color[2], 1, 312848b8605Smrg xoffset + (gr->pane->max_num_vertices - gr->index - 1) * 2 - 1, 313848b8605Smrg yoffset, yscale); 314848b8605Smrg 315848b8605Smrg if (gr->num_vertices <= gr->index) 316848b8605Smrg return; 317848b8605Smrg 318848b8605Smrg hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP, 319848b8605Smrg gr->vertices + gr->index*2, 320848b8605Smrg gr->num_vertices - gr->index, 321848b8605Smrg gr->color[0], gr->color[1], gr->color[2], 1, 322848b8605Smrg xoffset - gr->index*2 - 1, yoffset, yscale); 323848b8605Smrg} 324848b8605Smrg 325848b8605Smrgstatic void 326848b8605Smrghud_pane_accumulate_vertices(struct hud_context *hud, 327848b8605Smrg const struct hud_pane *pane) 328848b8605Smrg{ 329848b8605Smrg struct hud_graph *gr; 330848b8605Smrg float *line_verts = hud->whitelines.vertices + hud->whitelines.num_vertices*2; 331848b8605Smrg unsigned i, num = 0; 332848b8605Smrg char str[32]; 333b8e80941Smrg const unsigned last_line = pane->last_line; 334848b8605Smrg 335848b8605Smrg /* draw background */ 336848b8605Smrg hud_draw_background_quad(hud, 337848b8605Smrg pane->x1, pane->y1, 338848b8605Smrg pane->x2, pane->y2); 339848b8605Smrg 340848b8605Smrg /* draw numbers on the right-hand side */ 341b8e80941Smrg for (i = 0; i <= last_line; i++) { 342848b8605Smrg unsigned x = pane->x2 + 2; 343b8e80941Smrg unsigned y = pane->inner_y1 + 344b8e80941Smrg pane->inner_height * (last_line - i) / last_line - 345848b8605Smrg hud->font.glyph_height / 2; 346848b8605Smrg 347b8e80941Smrg number_to_human_readable(pane->max_value * i / last_line, 348b8e80941Smrg pane->type, str); 349b8e80941Smrg hud_draw_string(hud, x, y, "%s", str); 350848b8605Smrg } 351848b8605Smrg 352848b8605Smrg /* draw info below the pane */ 353848b8605Smrg i = 0; 354848b8605Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 355848b8605Smrg unsigned x = pane->x1 + 2; 356848b8605Smrg unsigned y = pane->y2 + 2 + i*hud->font.glyph_height; 357848b8605Smrg 358b8e80941Smrg number_to_human_readable(gr->current_value, pane->type, str); 359848b8605Smrg hud_draw_string(hud, x, y, " %s: %s", gr->name, str); 360848b8605Smrg i++; 361848b8605Smrg } 362848b8605Smrg 363848b8605Smrg /* draw border */ 364848b8605Smrg assert(hud->whitelines.num_vertices + num/2 + 8 <= hud->whitelines.max_num_vertices); 365848b8605Smrg line_verts[num++] = (float) pane->x1; 366848b8605Smrg line_verts[num++] = (float) pane->y1; 367848b8605Smrg line_verts[num++] = (float) pane->x2; 368848b8605Smrg line_verts[num++] = (float) pane->y1; 369848b8605Smrg 370848b8605Smrg line_verts[num++] = (float) pane->x2; 371848b8605Smrg line_verts[num++] = (float) pane->y1; 372848b8605Smrg line_verts[num++] = (float) pane->x2; 373848b8605Smrg line_verts[num++] = (float) pane->y2; 374848b8605Smrg 375848b8605Smrg line_verts[num++] = (float) pane->x1; 376848b8605Smrg line_verts[num++] = (float) pane->y2; 377848b8605Smrg line_verts[num++] = (float) pane->x2; 378848b8605Smrg line_verts[num++] = (float) pane->y2; 379848b8605Smrg 380848b8605Smrg line_verts[num++] = (float) pane->x1; 381848b8605Smrg line_verts[num++] = (float) pane->y1; 382848b8605Smrg line_verts[num++] = (float) pane->x1; 383848b8605Smrg line_verts[num++] = (float) pane->y2; 384848b8605Smrg 385848b8605Smrg /* draw horizontal lines inside the graph */ 386b8e80941Smrg for (i = 0; i <= last_line; i++) { 387b8e80941Smrg float y = round((pane->max_value * i / (double)last_line) * 388b8e80941Smrg pane->yscale + pane->inner_y2); 389848b8605Smrg 390848b8605Smrg assert(hud->whitelines.num_vertices + num/2 + 2 <= hud->whitelines.max_num_vertices); 391848b8605Smrg line_verts[num++] = pane->x1; 392848b8605Smrg line_verts[num++] = y; 393848b8605Smrg line_verts[num++] = pane->x2; 394848b8605Smrg line_verts[num++] = y; 395848b8605Smrg } 396848b8605Smrg 397848b8605Smrg hud->whitelines.num_vertices += num/2; 398848b8605Smrg} 399848b8605Smrg 400b8e80941Smrgstatic void 401b8e80941Smrghud_pane_accumulate_vertices_simple(struct hud_context *hud, 402b8e80941Smrg const struct hud_pane *pane) 403b8e80941Smrg{ 404b8e80941Smrg struct hud_graph *gr; 405b8e80941Smrg unsigned i; 406b8e80941Smrg char str[32]; 407b8e80941Smrg 408b8e80941Smrg /* draw info below the pane */ 409b8e80941Smrg i = 0; 410b8e80941Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 411b8e80941Smrg unsigned x = pane->x1; 412b8e80941Smrg unsigned y = pane->y_simple + i*hud->font.glyph_height; 413b8e80941Smrg 414b8e80941Smrg number_to_human_readable(gr->current_value, pane->type, str); 415b8e80941Smrg hud_draw_string(hud, x, y, "%s: %s", gr->name, str); 416b8e80941Smrg i++; 417b8e80941Smrg } 418b8e80941Smrg} 419b8e80941Smrg 420848b8605Smrgstatic void 421848b8605Smrghud_pane_draw_colored_objects(struct hud_context *hud, 422848b8605Smrg const struct hud_pane *pane) 423848b8605Smrg{ 424848b8605Smrg struct hud_graph *gr; 425848b8605Smrg unsigned i; 426848b8605Smrg 427848b8605Smrg /* draw colored quads below the pane */ 428848b8605Smrg i = 0; 429848b8605Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 430848b8605Smrg unsigned x = pane->x1 + 2; 431848b8605Smrg unsigned y = pane->y2 + 2 + i*hud->font.glyph_height; 432848b8605Smrg 433848b8605Smrg hud_draw_colored_quad(hud, PIPE_PRIM_QUADS, x + 1, y + 1, x + 12, y + 13, 434848b8605Smrg gr->color[0], gr->color[1], gr->color[2], 1); 435848b8605Smrg i++; 436848b8605Smrg } 437848b8605Smrg 438848b8605Smrg /* draw the line strips */ 439848b8605Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 440848b8605Smrg hud_draw_graph_line_strip(hud, gr, pane->inner_x1, pane->inner_y2, pane->yscale); 441848b8605Smrg } 442848b8605Smrg} 443848b8605Smrg 444848b8605Smrgstatic void 445b8e80941Smrghud_prepare_vertices(struct hud_context *hud, struct vertex_queue *v, 446b8e80941Smrg unsigned num_vertices, unsigned stride) 447848b8605Smrg{ 448848b8605Smrg v->num_vertices = 0; 449848b8605Smrg v->max_num_vertices = num_vertices; 450848b8605Smrg v->vbuf.stride = stride; 451b8e80941Smrg v->buffer_size = stride * num_vertices; 452848b8605Smrg} 453848b8605Smrg 454848b8605Smrg/** 455848b8605Smrg * Draw the HUD to the texture \p tex. 456848b8605Smrg * The texture is usually the back buffer being displayed. 457848b8605Smrg */ 458b8e80941Smrgstatic void 459b8e80941Smrghud_draw_results(struct hud_context *hud, struct pipe_resource *tex) 460848b8605Smrg{ 461848b8605Smrg struct cso_context *cso = hud->cso; 462848b8605Smrg struct pipe_context *pipe = hud->pipe; 463848b8605Smrg struct pipe_framebuffer_state fb; 464848b8605Smrg struct pipe_surface surf_templ, *surf; 465848b8605Smrg struct pipe_viewport_state viewport; 466848b8605Smrg const struct pipe_sampler_state *sampler_states[] = 467848b8605Smrg { &hud->font_sampler_state }; 468848b8605Smrg struct hud_pane *pane; 469b8e80941Smrg 470b8e80941Smrg if (!huds_visible) 471b8e80941Smrg return; 472848b8605Smrg 473848b8605Smrg hud->fb_width = tex->width0; 474848b8605Smrg hud->fb_height = tex->height0; 475848b8605Smrg hud->constants.two_div_fb_width = 2.0f / hud->fb_width; 476848b8605Smrg hud->constants.two_div_fb_height = 2.0f / hud->fb_height; 477848b8605Smrg 478b8e80941Smrg cso_save_state(cso, (CSO_BIT_FRAMEBUFFER | 479b8e80941Smrg CSO_BIT_SAMPLE_MASK | 480b8e80941Smrg CSO_BIT_MIN_SAMPLES | 481b8e80941Smrg CSO_BIT_BLEND | 482b8e80941Smrg CSO_BIT_DEPTH_STENCIL_ALPHA | 483b8e80941Smrg CSO_BIT_FRAGMENT_SHADER | 484b8e80941Smrg CSO_BIT_FRAGMENT_SAMPLER_VIEWS | 485b8e80941Smrg CSO_BIT_FRAGMENT_SAMPLERS | 486b8e80941Smrg CSO_BIT_RASTERIZER | 487b8e80941Smrg CSO_BIT_VIEWPORT | 488b8e80941Smrg CSO_BIT_STREAM_OUTPUTS | 489b8e80941Smrg CSO_BIT_GEOMETRY_SHADER | 490b8e80941Smrg CSO_BIT_TESSCTRL_SHADER | 491b8e80941Smrg CSO_BIT_TESSEVAL_SHADER | 492b8e80941Smrg CSO_BIT_VERTEX_SHADER | 493b8e80941Smrg CSO_BIT_VERTEX_ELEMENTS | 494b8e80941Smrg CSO_BIT_AUX_VERTEX_BUFFER_SLOT | 495b8e80941Smrg CSO_BIT_PAUSE_QUERIES | 496b8e80941Smrg CSO_BIT_RENDER_CONDITION)); 497848b8605Smrg cso_save_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); 498848b8605Smrg 499848b8605Smrg /* set states */ 500848b8605Smrg memset(&surf_templ, 0, sizeof(surf_templ)); 501848b8605Smrg surf_templ.format = tex->format; 502b8e80941Smrg 503b8e80941Smrg /* Without this, AA lines look thinner if they are between 2 pixels 504b8e80941Smrg * because the alpha is 0.5 on both pixels. (it's ugly) 505b8e80941Smrg * 506b8e80941Smrg * sRGB makes the width of all AA lines look the same. 507b8e80941Smrg */ 508b8e80941Smrg if (hud->has_srgb) { 509b8e80941Smrg enum pipe_format srgb_format = util_format_srgb(tex->format); 510b8e80941Smrg 511b8e80941Smrg if (srgb_format != PIPE_FORMAT_NONE) 512b8e80941Smrg surf_templ.format = srgb_format; 513b8e80941Smrg } 514848b8605Smrg surf = pipe->create_surface(pipe, tex, &surf_templ); 515848b8605Smrg 516848b8605Smrg memset(&fb, 0, sizeof(fb)); 517848b8605Smrg fb.nr_cbufs = 1; 518848b8605Smrg fb.cbufs[0] = surf; 519848b8605Smrg fb.zsbuf = NULL; 520848b8605Smrg fb.width = hud->fb_width; 521848b8605Smrg fb.height = hud->fb_height; 522848b8605Smrg 523848b8605Smrg viewport.scale[0] = 0.5f * hud->fb_width; 524848b8605Smrg viewport.scale[1] = 0.5f * hud->fb_height; 525848b8605Smrg viewport.scale[2] = 1.0f; 526848b8605Smrg viewport.translate[0] = 0.5f * hud->fb_width; 527848b8605Smrg viewport.translate[1] = 0.5f * hud->fb_height; 528848b8605Smrg viewport.translate[2] = 0.0f; 529848b8605Smrg 530848b8605Smrg cso_set_framebuffer(cso, &fb); 531848b8605Smrg cso_set_sample_mask(cso, ~0); 532848b8605Smrg cso_set_min_samples(cso, 1); 533848b8605Smrg cso_set_depth_stencil_alpha(cso, &hud->dsa); 534848b8605Smrg cso_set_rasterizer(cso, &hud->rasterizer); 535848b8605Smrg cso_set_viewport(cso, &viewport); 536848b8605Smrg cso_set_stream_outputs(cso, 0, NULL, NULL); 537b8e80941Smrg cso_set_tessctrl_shader_handle(cso, NULL); 538b8e80941Smrg cso_set_tesseval_shader_handle(cso, NULL); 539848b8605Smrg cso_set_geometry_shader_handle(cso, NULL); 540848b8605Smrg cso_set_vertex_shader_handle(cso, hud->vs); 541848b8605Smrg cso_set_vertex_elements(cso, 2, hud->velems); 542848b8605Smrg cso_set_render_condition(cso, NULL, FALSE, 0); 543848b8605Smrg cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1, 544848b8605Smrg &hud->font_sampler_view); 545848b8605Smrg cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, sampler_states); 546848b8605Smrg cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); 547848b8605Smrg 548848b8605Smrg /* draw accumulated vertices for background quads */ 549b8e80941Smrg cso_set_blend(cso, &hud->alpha_blend); 550848b8605Smrg cso_set_fragment_shader_handle(hud->cso, hud->fs_color); 551848b8605Smrg 552848b8605Smrg if (hud->bg.num_vertices) { 553848b8605Smrg hud->constants.color[0] = 0; 554848b8605Smrg hud->constants.color[1] = 0; 555848b8605Smrg hud->constants.color[2] = 0; 556848b8605Smrg hud->constants.color[3] = 0.666f; 557848b8605Smrg hud->constants.translate[0] = 0; 558848b8605Smrg hud->constants.translate[1] = 0; 559848b8605Smrg hud->constants.scale[0] = 1; 560848b8605Smrg hud->constants.scale[1] = 1; 561848b8605Smrg 562848b8605Smrg cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); 563b8e80941Smrg cso_set_vertex_buffers(cso, 0, 1, &hud->bg.vbuf); 564848b8605Smrg cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices); 565848b8605Smrg } 566b8e80941Smrg pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL); 567b8e80941Smrg 568b8e80941Smrg /* draw accumulated vertices for text */ 569b8e80941Smrg if (hud->text.num_vertices) { 570b8e80941Smrg cso_set_vertex_buffers(cso, 0, 1, &hud->text.vbuf); 571b8e80941Smrg cso_set_fragment_shader_handle(hud->cso, hud->fs_text); 572b8e80941Smrg cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices); 573b8e80941Smrg } 574b8e80941Smrg pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL); 575b8e80941Smrg 576b8e80941Smrg if (hud->simple) { 577b8e80941Smrg cso_restore_state(cso); 578b8e80941Smrg cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); 579b8e80941Smrg 580b8e80941Smrg pipe_surface_reference(&surf, NULL); 581b8e80941Smrg return; 582b8e80941Smrg } 583848b8605Smrg 584848b8605Smrg /* draw accumulated vertices for white lines */ 585b8e80941Smrg cso_set_blend(cso, &hud->no_blend); 586b8e80941Smrg 587848b8605Smrg hud->constants.color[0] = 1; 588848b8605Smrg hud->constants.color[1] = 1; 589848b8605Smrg hud->constants.color[2] = 1; 590848b8605Smrg hud->constants.color[3] = 1; 591848b8605Smrg hud->constants.translate[0] = 0; 592848b8605Smrg hud->constants.translate[1] = 0; 593848b8605Smrg hud->constants.scale[0] = 1; 594848b8605Smrg hud->constants.scale[1] = 1; 595848b8605Smrg cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); 596848b8605Smrg 597848b8605Smrg if (hud->whitelines.num_vertices) { 598b8e80941Smrg cso_set_vertex_buffers(cso, 0, 1, &hud->whitelines.vbuf); 599848b8605Smrg cso_set_fragment_shader_handle(hud->cso, hud->fs_color); 600848b8605Smrg cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices); 601848b8605Smrg } 602b8e80941Smrg pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL); 603848b8605Smrg 604848b8605Smrg /* draw the rest */ 605b8e80941Smrg cso_set_blend(cso, &hud->alpha_blend); 606b8e80941Smrg cso_set_rasterizer(cso, &hud->rasterizer_aa_lines); 607848b8605Smrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 608848b8605Smrg if (pane) 609848b8605Smrg hud_pane_draw_colored_objects(hud, pane); 610848b8605Smrg } 611848b8605Smrg 612b8e80941Smrg cso_restore_state(cso); 613848b8605Smrg cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); 614848b8605Smrg 615848b8605Smrg pipe_surface_reference(&surf, NULL); 616848b8605Smrg} 617848b8605Smrg 618b8e80941Smrgstatic void 619b8e80941Smrghud_start_queries(struct hud_context *hud, struct pipe_context *pipe) 620b8e80941Smrg{ 621b8e80941Smrg struct hud_pane *pane; 622b8e80941Smrg struct hud_graph *gr; 623b8e80941Smrg 624b8e80941Smrg /* Start queries. */ 625b8e80941Smrg hud_batch_query_begin(hud->batch_query, pipe); 626b8e80941Smrg 627b8e80941Smrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 628b8e80941Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 629b8e80941Smrg if (gr->begin_query) 630b8e80941Smrg gr->begin_query(gr, pipe); 631b8e80941Smrg } 632b8e80941Smrg } 633b8e80941Smrg} 634b8e80941Smrg 635b8e80941Smrg/* Stop queries, query results, and record vertices for charts. */ 636b8e80941Smrgstatic void 637b8e80941Smrghud_stop_queries(struct hud_context *hud, struct pipe_context *pipe) 638b8e80941Smrg{ 639b8e80941Smrg struct hud_pane *pane; 640b8e80941Smrg struct hud_graph *gr, *next; 641b8e80941Smrg 642b8e80941Smrg /* prepare vertex buffers */ 643b8e80941Smrg hud_prepare_vertices(hud, &hud->bg, 16 * 256, 2 * sizeof(float)); 644b8e80941Smrg hud_prepare_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float)); 645b8e80941Smrg hud_prepare_vertices(hud, &hud->text, 16 * 1024, 4 * sizeof(float)); 646b8e80941Smrg hud_prepare_vertices(hud, &hud->color_prims, 32 * 1024, 2 * sizeof(float)); 647b8e80941Smrg 648b8e80941Smrg /* Allocate everything once and divide the storage into 3 portions 649b8e80941Smrg * manually, because u_upload_alloc can unmap memory from previous calls. 650b8e80941Smrg */ 651b8e80941Smrg u_upload_alloc(pipe->stream_uploader, 0, 652b8e80941Smrg hud->bg.buffer_size + 653b8e80941Smrg hud->whitelines.buffer_size + 654b8e80941Smrg hud->text.buffer_size + 655b8e80941Smrg hud->color_prims.buffer_size, 656b8e80941Smrg 16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer.resource, 657b8e80941Smrg (void**)&hud->bg.vertices); 658b8e80941Smrg if (!hud->bg.vertices) 659b8e80941Smrg return; 660b8e80941Smrg 661b8e80941Smrg pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); 662b8e80941Smrg pipe_resource_reference(&hud->text.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); 663b8e80941Smrg pipe_resource_reference(&hud->color_prims.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); 664b8e80941Smrg 665b8e80941Smrg hud->whitelines.vbuf.buffer_offset = hud->bg.vbuf.buffer_offset + 666b8e80941Smrg hud->bg.buffer_size; 667b8e80941Smrg hud->whitelines.vertices = hud->bg.vertices + 668b8e80941Smrg hud->bg.buffer_size / sizeof(float); 669b8e80941Smrg 670b8e80941Smrg hud->text.vbuf.buffer_offset = hud->whitelines.vbuf.buffer_offset + 671b8e80941Smrg hud->whitelines.buffer_size; 672b8e80941Smrg hud->text.vertices = hud->whitelines.vertices + 673b8e80941Smrg hud->whitelines.buffer_size / sizeof(float); 674b8e80941Smrg 675b8e80941Smrg hud->color_prims.vbuf.buffer_offset = hud->text.vbuf.buffer_offset + 676b8e80941Smrg hud->text.buffer_size; 677b8e80941Smrg hud->color_prims.vertices = hud->text.vertices + 678b8e80941Smrg hud->text.buffer_size / sizeof(float); 679b8e80941Smrg 680b8e80941Smrg /* prepare all graphs */ 681b8e80941Smrg hud_batch_query_update(hud->batch_query, pipe); 682b8e80941Smrg 683b8e80941Smrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 684b8e80941Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 685b8e80941Smrg gr->query_new_value(gr, pipe); 686b8e80941Smrg } 687b8e80941Smrg 688b8e80941Smrg if (pane->sort_items) { 689b8e80941Smrg LIST_FOR_EACH_ENTRY_SAFE(gr, next, &pane->graph_list, head) { 690b8e80941Smrg /* ignore the last one */ 691b8e80941Smrg if (&gr->head == pane->graph_list.prev) 692b8e80941Smrg continue; 693b8e80941Smrg 694b8e80941Smrg /* This is an incremental bubble sort, because we only do one pass 695b8e80941Smrg * per frame. It will eventually reach an equilibrium. 696b8e80941Smrg */ 697b8e80941Smrg if (gr->current_value < 698b8e80941Smrg LIST_ENTRY(struct hud_graph, next, head)->current_value) { 699b8e80941Smrg LIST_DEL(&gr->head); 700b8e80941Smrg LIST_ADD(&gr->head, &next->head); 701b8e80941Smrg } 702b8e80941Smrg } 703b8e80941Smrg } 704b8e80941Smrg 705b8e80941Smrg if (hud->simple) 706b8e80941Smrg hud_pane_accumulate_vertices_simple(hud, pane); 707b8e80941Smrg else 708b8e80941Smrg hud_pane_accumulate_vertices(hud, pane); 709b8e80941Smrg } 710b8e80941Smrg 711b8e80941Smrg /* unmap the uploader's vertex buffer before drawing */ 712b8e80941Smrg u_upload_unmap(pipe->stream_uploader); 713b8e80941Smrg} 714b8e80941Smrg 715b8e80941Smrg/** 716b8e80941Smrg * Record queries and draw the HUD. The "cso" parameter acts as a filter. 717b8e80941Smrg * If "cso" is not the recording context, recording is skipped. 718b8e80941Smrg * If "cso" is not the drawing context, drawing is skipped. 719b8e80941Smrg * cso == NULL ignores the filter. 720b8e80941Smrg */ 721b8e80941Smrgvoid 722b8e80941Smrghud_run(struct hud_context *hud, struct cso_context *cso, 723b8e80941Smrg struct pipe_resource *tex) 724b8e80941Smrg{ 725b8e80941Smrg struct pipe_context *pipe = cso ? cso_get_pipe_context(cso) : NULL; 726b8e80941Smrg 727b8e80941Smrg /* If "cso" is the recording or drawing context or NULL, execute 728b8e80941Smrg * the operation. Otherwise, don't do anything. 729b8e80941Smrg */ 730b8e80941Smrg if (hud->record_pipe && (!pipe || pipe == hud->record_pipe)) 731b8e80941Smrg hud_stop_queries(hud, hud->record_pipe); 732b8e80941Smrg 733b8e80941Smrg if (hud->cso && (!cso || cso == hud->cso)) 734b8e80941Smrg hud_draw_results(hud, tex); 735b8e80941Smrg 736b8e80941Smrg if (hud->record_pipe && (!pipe || pipe == hud->record_pipe)) 737b8e80941Smrg hud_start_queries(hud, hud->record_pipe); 738b8e80941Smrg} 739b8e80941Smrg 740b8e80941Smrg/** 741b8e80941Smrg * Record query results and assemble vertices if "pipe" is a recording but 742b8e80941Smrg * not drawing context. 743b8e80941Smrg */ 744b8e80941Smrgvoid 745b8e80941Smrghud_record_only(struct hud_context *hud, struct pipe_context *pipe) 746b8e80941Smrg{ 747b8e80941Smrg assert(pipe); 748b8e80941Smrg 749b8e80941Smrg /* If it's a drawing context, only hud_run() records query results. */ 750b8e80941Smrg if (pipe == hud->pipe || pipe != hud->record_pipe) 751b8e80941Smrg return; 752b8e80941Smrg 753b8e80941Smrg hud_stop_queries(hud, hud->record_pipe); 754b8e80941Smrg hud_start_queries(hud, hud->record_pipe); 755b8e80941Smrg} 756b8e80941Smrg 757b8e80941Smrgstatic void 758b8e80941Smrgfixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10) 759b8e80941Smrg{ 760b8e80941Smrg if (type == PIPE_DRIVER_QUERY_TYPE_BYTES && position % 3 == 0) 761b8e80941Smrg *exp10 = (*exp10 / 1000) * 1024; 762b8e80941Smrg} 763b8e80941Smrg 764848b8605Smrg/** 765848b8605Smrg * Set the maximum value for the Y axis of the graph. 766848b8605Smrg * This scales the graph accordingly. 767848b8605Smrg */ 768848b8605Smrgvoid 769848b8605Smrghud_pane_set_max_value(struct hud_pane *pane, uint64_t value) 770848b8605Smrg{ 771b8e80941Smrg double leftmost_digit; 772b8e80941Smrg uint64_t exp10; 773b8e80941Smrg int i; 774b8e80941Smrg 775b8e80941Smrg /* The following code determines the max_value in the graph as well as 776b8e80941Smrg * how many describing lines are drawn. The max_value is rounded up, 777b8e80941Smrg * so that all drawn numbers are rounded for readability. 778b8e80941Smrg * We want to print multiples of a simple number instead of multiples of 779b8e80941Smrg * hard-to-read numbers like 1.753. 780b8e80941Smrg */ 781b8e80941Smrg 782b8e80941Smrg /* Find the left-most digit. Make sure exp10 * 10 and fixup_bytes doesn't 783b8e80941Smrg * overflow. (11 is safe) */ 784b8e80941Smrg exp10 = 1; 785b8e80941Smrg for (i = 0; exp10 <= UINT64_MAX / 11 && exp10 * 9 < value; i++) { 786b8e80941Smrg exp10 *= 10; 787b8e80941Smrg fixup_bytes(pane->type, i + 1, &exp10); 788b8e80941Smrg } 789b8e80941Smrg 790b8e80941Smrg leftmost_digit = DIV_ROUND_UP(value, exp10); 791b8e80941Smrg 792b8e80941Smrg /* Round 9 to 10. */ 793b8e80941Smrg if (leftmost_digit == 9) { 794b8e80941Smrg leftmost_digit = 1; 795b8e80941Smrg exp10 *= 10; 796b8e80941Smrg fixup_bytes(pane->type, i + 1, &exp10); 797b8e80941Smrg } 798b8e80941Smrg 799b8e80941Smrg switch ((unsigned)leftmost_digit) { 800b8e80941Smrg case 1: 801b8e80941Smrg pane->last_line = 5; /* lines in +1/5 increments */ 802b8e80941Smrg break; 803b8e80941Smrg case 2: 804b8e80941Smrg pane->last_line = 8; /* lines in +1/4 increments. */ 805b8e80941Smrg break; 806b8e80941Smrg case 3: 807b8e80941Smrg case 4: 808b8e80941Smrg pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments */ 809b8e80941Smrg break; 810b8e80941Smrg case 5: 811b8e80941Smrg case 6: 812b8e80941Smrg case 7: 813b8e80941Smrg case 8: 814b8e80941Smrg pane->last_line = leftmost_digit; /* lines in +1 increments */ 815b8e80941Smrg break; 816b8e80941Smrg default: 817b8e80941Smrg assert(0); 818b8e80941Smrg } 819b8e80941Smrg 820b8e80941Smrg /* Truncate {3,4} to {2.5, 3.5} if possible. */ 821b8e80941Smrg for (i = 3; i <= 4; i++) { 822b8e80941Smrg if (leftmost_digit == i && value <= (i - 0.5) * exp10) { 823b8e80941Smrg leftmost_digit = i - 0.5; 824b8e80941Smrg pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments. */ 825b8e80941Smrg } 826b8e80941Smrg } 827b8e80941Smrg 828b8e80941Smrg /* Truncate 2 to a multiple of 0.2 in (1, 1.6] if possible. */ 829b8e80941Smrg if (leftmost_digit == 2) { 830b8e80941Smrg for (i = 1; i <= 3; i++) { 831b8e80941Smrg if (value <= (1 + i*0.2) * exp10) { 832b8e80941Smrg leftmost_digit = 1 + i*0.2; 833b8e80941Smrg pane->last_line = 5 + i; /* lines in +1/5 increments. */ 834b8e80941Smrg break; 835b8e80941Smrg } 836b8e80941Smrg } 837b8e80941Smrg } 838b8e80941Smrg 839b8e80941Smrg pane->max_value = leftmost_digit * exp10; 840848b8605Smrg pane->yscale = -(int)pane->inner_height / (float)pane->max_value; 841848b8605Smrg} 842848b8605Smrg 843b8e80941Smrgstatic void 844b8e80941Smrghud_pane_update_dyn_ceiling(struct hud_graph *gr, struct hud_pane *pane) 845b8e80941Smrg{ 846b8e80941Smrg unsigned i; 847b8e80941Smrg float tmp = 0.0f; 848b8e80941Smrg 849b8e80941Smrg if (pane->dyn_ceil_last_ran != gr->index) { 850b8e80941Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 851b8e80941Smrg for (i = 0; i < gr->num_vertices; ++i) { 852b8e80941Smrg tmp = gr->vertices[i * 2 + 1] > tmp ? 853b8e80941Smrg gr->vertices[i * 2 + 1] : tmp; 854b8e80941Smrg } 855b8e80941Smrg } 856b8e80941Smrg 857b8e80941Smrg /* Avoid setting it lower than the initial starting height. */ 858b8e80941Smrg tmp = tmp > pane->initial_max_value ? tmp : pane->initial_max_value; 859b8e80941Smrg hud_pane_set_max_value(pane, tmp); 860b8e80941Smrg } 861b8e80941Smrg 862b8e80941Smrg /* 863b8e80941Smrg * Mark this adjustment run so we could avoid repeating a full update 864b8e80941Smrg * again needlessly in case the pane has more than one graph. 865b8e80941Smrg */ 866b8e80941Smrg pane->dyn_ceil_last_ran = gr->index; 867b8e80941Smrg} 868b8e80941Smrg 869848b8605Smrgstatic struct hud_pane * 870b8e80941Smrghud_pane_create(struct hud_context *hud, 871b8e80941Smrg unsigned x1, unsigned y1, unsigned x2, unsigned y2, 872b8e80941Smrg unsigned y_simple, 873b8e80941Smrg unsigned period, uint64_t max_value, uint64_t ceiling, 874b8e80941Smrg boolean dyn_ceiling, boolean sort_items) 875848b8605Smrg{ 876848b8605Smrg struct hud_pane *pane = CALLOC_STRUCT(hud_pane); 877848b8605Smrg 878848b8605Smrg if (!pane) 879848b8605Smrg return NULL; 880848b8605Smrg 881b8e80941Smrg pane->hud = hud; 882848b8605Smrg pane->x1 = x1; 883848b8605Smrg pane->y1 = y1; 884848b8605Smrg pane->x2 = x2; 885848b8605Smrg pane->y2 = y2; 886b8e80941Smrg pane->y_simple = y_simple; 887848b8605Smrg pane->inner_x1 = x1 + 1; 888848b8605Smrg pane->inner_x2 = x2 - 1; 889848b8605Smrg pane->inner_y1 = y1 + 1; 890848b8605Smrg pane->inner_y2 = y2 - 1; 891848b8605Smrg pane->inner_width = pane->inner_x2 - pane->inner_x1; 892848b8605Smrg pane->inner_height = pane->inner_y2 - pane->inner_y1; 893848b8605Smrg pane->period = period; 894848b8605Smrg pane->max_num_vertices = (x2 - x1 + 2) / 2; 895b8e80941Smrg pane->ceiling = ceiling; 896b8e80941Smrg pane->dyn_ceiling = dyn_ceiling; 897b8e80941Smrg pane->dyn_ceil_last_ran = 0; 898b8e80941Smrg pane->sort_items = sort_items; 899b8e80941Smrg pane->initial_max_value = max_value; 900848b8605Smrg hud_pane_set_max_value(pane, max_value); 901848b8605Smrg LIST_INITHEAD(&pane->graph_list); 902848b8605Smrg return pane; 903848b8605Smrg} 904848b8605Smrg 905b8e80941Smrg/* replace '-' with a space */ 906b8e80941Smrgstatic void 907b8e80941Smrgstrip_hyphens(char *s) 908b8e80941Smrg{ 909b8e80941Smrg while (*s) { 910b8e80941Smrg if (*s == '-') 911b8e80941Smrg *s = ' '; 912b8e80941Smrg s++; 913b8e80941Smrg } 914b8e80941Smrg} 915b8e80941Smrg 916848b8605Smrg/** 917848b8605Smrg * Add a graph to an existing pane. 918848b8605Smrg * One pane can contain multiple graphs over each other. 919848b8605Smrg */ 920848b8605Smrgvoid 921848b8605Smrghud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr) 922848b8605Smrg{ 923848b8605Smrg static const float colors[][3] = { 924848b8605Smrg {0, 1, 0}, 925848b8605Smrg {1, 0, 0}, 926848b8605Smrg {0, 1, 1}, 927848b8605Smrg {1, 0, 1}, 928848b8605Smrg {1, 1, 0}, 929b8e80941Smrg {0.5, 1, 0.5}, 930b8e80941Smrg {1, 0.5, 0.5}, 931b8e80941Smrg {0.5, 1, 1}, 932b8e80941Smrg {1, 0.5, 1}, 933b8e80941Smrg {1, 1, 0.5}, 934b8e80941Smrg {0, 0.5, 0}, 935b8e80941Smrg {0.5, 0, 0}, 936b8e80941Smrg {0, 0.5, 0.5}, 937b8e80941Smrg {0.5, 0, 0.5}, 938b8e80941Smrg {0.5, 0.5, 0}, 939848b8605Smrg }; 940b8e80941Smrg unsigned color = pane->next_color % ARRAY_SIZE(colors); 941848b8605Smrg 942b8e80941Smrg strip_hyphens(gr->name); 943848b8605Smrg 944848b8605Smrg gr->vertices = MALLOC(pane->max_num_vertices * sizeof(float) * 2); 945b8e80941Smrg gr->color[0] = colors[color][0]; 946b8e80941Smrg gr->color[1] = colors[color][1]; 947b8e80941Smrg gr->color[2] = colors[color][2]; 948848b8605Smrg gr->pane = pane; 949848b8605Smrg LIST_ADDTAIL(&gr->head, &pane->graph_list); 950848b8605Smrg pane->num_graphs++; 951b8e80941Smrg pane->next_color++; 952848b8605Smrg} 953848b8605Smrg 954848b8605Smrgvoid 955b8e80941Smrghud_graph_add_value(struct hud_graph *gr, double value) 956848b8605Smrg{ 957b8e80941Smrg gr->current_value = value; 958b8e80941Smrg value = value > gr->pane->ceiling ? gr->pane->ceiling : value; 959b8e80941Smrg 960b8e80941Smrg if (gr->fd) { 961b8e80941Smrg if (fabs(value - lround(value)) > FLT_EPSILON) { 962b8e80941Smrg fprintf(gr->fd, "%f\n", value); 963b8e80941Smrg } 964b8e80941Smrg else { 965b8e80941Smrg fprintf(gr->fd, "%" PRIu64 "\n", (uint64_t) lround(value)); 966b8e80941Smrg } 967b8e80941Smrg } 968b8e80941Smrg 969848b8605Smrg if (gr->index == gr->pane->max_num_vertices) { 970848b8605Smrg gr->vertices[0] = 0; 971848b8605Smrg gr->vertices[1] = gr->vertices[(gr->index-1)*2+1]; 972848b8605Smrg gr->index = 1; 973848b8605Smrg } 974848b8605Smrg gr->vertices[(gr->index)*2+0] = (float) (gr->index * 2); 975848b8605Smrg gr->vertices[(gr->index)*2+1] = (float) value; 976848b8605Smrg gr->index++; 977848b8605Smrg 978848b8605Smrg if (gr->num_vertices < gr->pane->max_num_vertices) { 979848b8605Smrg gr->num_vertices++; 980848b8605Smrg } 981848b8605Smrg 982b8e80941Smrg if (gr->pane->dyn_ceiling == true) { 983b8e80941Smrg hud_pane_update_dyn_ceiling(gr, gr->pane); 984b8e80941Smrg } 985848b8605Smrg if (value > gr->pane->max_value) { 986848b8605Smrg hud_pane_set_max_value(gr->pane, value); 987848b8605Smrg } 988848b8605Smrg} 989848b8605Smrg 990848b8605Smrgstatic void 991b8e80941Smrghud_graph_destroy(struct hud_graph *graph, struct pipe_context *pipe) 992848b8605Smrg{ 993848b8605Smrg FREE(graph->vertices); 994848b8605Smrg if (graph->free_query_data) 995b8e80941Smrg graph->free_query_data(graph->query_data, pipe); 996b8e80941Smrg if (graph->fd) 997b8e80941Smrg fclose(graph->fd); 998848b8605Smrg FREE(graph); 999848b8605Smrg} 1000848b8605Smrg 1001b8e80941Smrgstatic void strcat_without_spaces(char *dst, const char *src) 1002b8e80941Smrg{ 1003b8e80941Smrg dst += strlen(dst); 1004b8e80941Smrg while (*src) { 1005b8e80941Smrg if (*src == ' ') 1006b8e80941Smrg *dst++ = '_'; 1007b8e80941Smrg else 1008b8e80941Smrg *dst++ = *src; 1009b8e80941Smrg src++; 1010b8e80941Smrg } 1011b8e80941Smrg *dst = 0; 1012b8e80941Smrg} 1013b8e80941Smrg 1014b8e80941Smrg 1015b8e80941Smrg#ifdef PIPE_OS_WINDOWS 1016b8e80941Smrg#define W_OK 0 1017b8e80941Smrgstatic int 1018b8e80941Smrgaccess(const char *pathname, int mode) 1019b8e80941Smrg{ 1020b8e80941Smrg /* no-op */ 1021b8e80941Smrg return 0; 1022b8e80941Smrg} 1023b8e80941Smrg 1024b8e80941Smrg#define PATH_SEP "\\" 1025b8e80941Smrg 1026b8e80941Smrg#else 1027b8e80941Smrg 1028b8e80941Smrg#define PATH_SEP "/" 1029b8e80941Smrg 1030b8e80941Smrg#endif 1031b8e80941Smrg 1032b8e80941Smrg 1033b8e80941Smrg/** 1034b8e80941Smrg * If the GALLIUM_HUD_DUMP_DIR env var is set, we'll write the raw 1035b8e80941Smrg * HUD values to files at ${GALLIUM_HUD_DUMP_DIR}/<stat> where <stat> 1036b8e80941Smrg * is a HUD variable such as "fps", or "cpu" 1037b8e80941Smrg */ 1038b8e80941Smrgstatic void 1039b8e80941Smrghud_graph_set_dump_file(struct hud_graph *gr) 1040b8e80941Smrg{ 1041b8e80941Smrg const char *hud_dump_dir = getenv("GALLIUM_HUD_DUMP_DIR"); 1042b8e80941Smrg 1043b8e80941Smrg if (hud_dump_dir && access(hud_dump_dir, W_OK) == 0) { 1044b8e80941Smrg char *dump_file = malloc(strlen(hud_dump_dir) + sizeof(PATH_SEP) 1045b8e80941Smrg + sizeof(gr->name)); 1046b8e80941Smrg if (dump_file) { 1047b8e80941Smrg strcpy(dump_file, hud_dump_dir); 1048b8e80941Smrg strcat(dump_file, PATH_SEP); 1049b8e80941Smrg strcat_without_spaces(dump_file, gr->name); 1050b8e80941Smrg gr->fd = fopen(dump_file, "w+"); 1051b8e80941Smrg if (gr->fd) { 1052b8e80941Smrg /* flush output after each line is written */ 1053b8e80941Smrg setvbuf(gr->fd, NULL, _IOLBF, 0); 1054b8e80941Smrg } 1055b8e80941Smrg free(dump_file); 1056b8e80941Smrg } 1057b8e80941Smrg } 1058b8e80941Smrg} 1059b8e80941Smrg 1060848b8605Smrg/** 1061848b8605Smrg * Read a string from the environment variable. 1062848b8605Smrg * The separators "+", ",", ":", and ";" terminate the string. 1063848b8605Smrg * Return the number of read characters. 1064848b8605Smrg */ 1065848b8605Smrgstatic int 1066848b8605Smrgparse_string(const char *s, char *out) 1067848b8605Smrg{ 1068848b8605Smrg int i; 1069848b8605Smrg 1070b8e80941Smrg for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';' && *s != '='; 1071848b8605Smrg s++, out++, i++) 1072848b8605Smrg *out = *s; 1073848b8605Smrg 1074848b8605Smrg *out = 0; 1075848b8605Smrg 1076b8e80941Smrg if (*s && !i) { 1077848b8605Smrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) while " 1078848b8605Smrg "parsing a string\n", *s, *s); 1079b8e80941Smrg fflush(stderr); 1080b8e80941Smrg } 1081b8e80941Smrg 1082848b8605Smrg return i; 1083848b8605Smrg} 1084848b8605Smrg 1085b8e80941Smrgstatic char * 1086b8e80941Smrgread_pane_settings(char *str, unsigned * const x, unsigned * const y, 1087b8e80941Smrg unsigned * const width, unsigned * const height, 1088b8e80941Smrg uint64_t * const ceiling, boolean * const dyn_ceiling, 1089b8e80941Smrg boolean *reset_colors, boolean *sort_items) 1090b8e80941Smrg{ 1091b8e80941Smrg char *ret = str; 1092b8e80941Smrg unsigned tmp; 1093b8e80941Smrg 1094b8e80941Smrg while (*str == '.') { 1095b8e80941Smrg ++str; 1096b8e80941Smrg switch (*str) { 1097b8e80941Smrg case 'x': 1098b8e80941Smrg ++str; 1099b8e80941Smrg *x = strtoul(str, &ret, 10); 1100b8e80941Smrg str = ret; 1101b8e80941Smrg break; 1102b8e80941Smrg 1103b8e80941Smrg case 'y': 1104b8e80941Smrg ++str; 1105b8e80941Smrg *y = strtoul(str, &ret, 10); 1106b8e80941Smrg str = ret; 1107b8e80941Smrg break; 1108b8e80941Smrg 1109b8e80941Smrg case 'w': 1110b8e80941Smrg ++str; 1111b8e80941Smrg tmp = strtoul(str, &ret, 10); 1112b8e80941Smrg *width = tmp > 80 ? tmp : 80; /* 80 is chosen arbitrarily */ 1113b8e80941Smrg str = ret; 1114b8e80941Smrg break; 1115b8e80941Smrg 1116b8e80941Smrg /* 1117b8e80941Smrg * Prevent setting height to less than 50. If the height is set to less, 1118b8e80941Smrg * the text of the Y axis labels on the graph will start overlapping. 1119b8e80941Smrg */ 1120b8e80941Smrg case 'h': 1121b8e80941Smrg ++str; 1122b8e80941Smrg tmp = strtoul(str, &ret, 10); 1123b8e80941Smrg *height = tmp > 50 ? tmp : 50; 1124b8e80941Smrg str = ret; 1125b8e80941Smrg break; 1126b8e80941Smrg 1127b8e80941Smrg case 'c': 1128b8e80941Smrg ++str; 1129b8e80941Smrg tmp = strtoul(str, &ret, 10); 1130b8e80941Smrg *ceiling = tmp > 10 ? tmp : 10; 1131b8e80941Smrg str = ret; 1132b8e80941Smrg break; 1133b8e80941Smrg 1134b8e80941Smrg case 'd': 1135b8e80941Smrg ++str; 1136b8e80941Smrg ret = str; 1137b8e80941Smrg *dyn_ceiling = true; 1138b8e80941Smrg break; 1139b8e80941Smrg 1140b8e80941Smrg case 'r': 1141b8e80941Smrg ++str; 1142b8e80941Smrg ret = str; 1143b8e80941Smrg *reset_colors = true; 1144b8e80941Smrg break; 1145b8e80941Smrg 1146b8e80941Smrg case 's': 1147b8e80941Smrg ++str; 1148b8e80941Smrg ret = str; 1149b8e80941Smrg *sort_items = true; 1150b8e80941Smrg break; 1151b8e80941Smrg 1152b8e80941Smrg default: 1153b8e80941Smrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *str); 1154b8e80941Smrg fflush(stderr); 1155b8e80941Smrg } 1156b8e80941Smrg 1157b8e80941Smrg } 1158b8e80941Smrg 1159b8e80941Smrg return ret; 1160b8e80941Smrg} 1161b8e80941Smrg 1162848b8605Smrgstatic boolean 1163848b8605Smrghas_occlusion_query(struct pipe_screen *screen) 1164848b8605Smrg{ 1165848b8605Smrg return screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY) != 0; 1166848b8605Smrg} 1167848b8605Smrg 1168848b8605Smrgstatic boolean 1169848b8605Smrghas_streamout(struct pipe_screen *screen) 1170848b8605Smrg{ 1171848b8605Smrg return screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0; 1172848b8605Smrg} 1173848b8605Smrg 1174848b8605Smrgstatic boolean 1175848b8605Smrghas_pipeline_stats_query(struct pipe_screen *screen) 1176848b8605Smrg{ 1177848b8605Smrg return screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS) != 0; 1178848b8605Smrg} 1179848b8605Smrg 1180848b8605Smrgstatic void 1181b8e80941Smrghud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen, 1182b8e80941Smrg const char *env) 1183848b8605Smrg{ 1184848b8605Smrg unsigned num, i; 1185b8e80941Smrg char name_a[256], s[256]; 1186b8e80941Smrg char *name; 1187848b8605Smrg struct hud_pane *pane = NULL; 1188b8e80941Smrg unsigned x = 10, y = 10, y_simple = 10; 1189848b8605Smrg unsigned width = 251, height = 100; 1190848b8605Smrg unsigned period = 500 * 1000; /* default period (1/2 second) */ 1191b8e80941Smrg uint64_t ceiling = UINT64_MAX; 1192b8e80941Smrg unsigned column_width = 251; 1193b8e80941Smrg boolean dyn_ceiling = false; 1194b8e80941Smrg boolean reset_colors = false; 1195b8e80941Smrg boolean sort_items = false; 1196848b8605Smrg const char *period_env; 1197848b8605Smrg 1198b8e80941Smrg if (util_strncmp(env, "simple,", 7) == 0) { 1199b8e80941Smrg hud->simple = true; 1200b8e80941Smrg env += 7; 1201b8e80941Smrg } 1202b8e80941Smrg 1203848b8605Smrg /* 1204848b8605Smrg * The GALLIUM_HUD_PERIOD env var sets the graph update rate. 1205848b8605Smrg * The env var is in seconds (a float). 1206848b8605Smrg * Zero means update after every frame. 1207848b8605Smrg */ 1208848b8605Smrg period_env = getenv("GALLIUM_HUD_PERIOD"); 1209848b8605Smrg if (period_env) { 1210848b8605Smrg float p = (float) atof(period_env); 1211848b8605Smrg if (p >= 0.0f) { 1212848b8605Smrg period = (unsigned) (p * 1000 * 1000); 1213848b8605Smrg } 1214848b8605Smrg } 1215848b8605Smrg 1216b8e80941Smrg while ((num = parse_string(env, name_a)) != 0) { 1217b8e80941Smrg bool added = true; 1218b8e80941Smrg 1219848b8605Smrg env += num; 1220848b8605Smrg 1221b8e80941Smrg /* check for explicit location, size and etc. settings */ 1222b8e80941Smrg name = read_pane_settings(name_a, &x, &y, &width, &height, &ceiling, 1223b8e80941Smrg &dyn_ceiling, &reset_colors, &sort_items); 1224b8e80941Smrg 1225b8e80941Smrg /* 1226b8e80941Smrg * Keep track of overall column width to avoid pane overlapping in case 1227b8e80941Smrg * later we create a new column while the bottom pane in the current 1228b8e80941Smrg * column is less wide than the rest of the panes in it. 1229b8e80941Smrg */ 1230b8e80941Smrg column_width = width > column_width ? width : column_width; 1231b8e80941Smrg 1232848b8605Smrg if (!pane) { 1233b8e80941Smrg pane = hud_pane_create(hud, x, y, x + width, y + height, y_simple, 1234b8e80941Smrg period, 10, ceiling, dyn_ceiling, sort_items); 1235848b8605Smrg if (!pane) 1236848b8605Smrg return; 1237848b8605Smrg } 1238848b8605Smrg 1239b8e80941Smrg if (reset_colors) { 1240b8e80941Smrg pane->next_color = 0; 1241b8e80941Smrg reset_colors = false; 1242b8e80941Smrg } 1243b8e80941Smrg 1244848b8605Smrg /* Add a graph. */ 1245b8e80941Smrg#if defined(HAVE_GALLIUM_EXTRA_HUD) || defined(HAVE_LIBSENSORS) 1246b8e80941Smrg char arg_name[64]; 1247b8e80941Smrg#endif 1248848b8605Smrg /* IF YOU CHANGE THIS, UPDATE print_help! */ 1249848b8605Smrg if (strcmp(name, "fps") == 0) { 1250848b8605Smrg hud_fps_graph_install(pane); 1251848b8605Smrg } 1252b8e80941Smrg else if (strcmp(name, "frametime") == 0) { 1253b8e80941Smrg hud_frametime_graph_install(pane); 1254b8e80941Smrg } 1255848b8605Smrg else if (strcmp(name, "cpu") == 0) { 1256848b8605Smrg hud_cpu_graph_install(pane, ALL_CPUS); 1257848b8605Smrg } 1258848b8605Smrg else if (sscanf(name, "cpu%u%s", &i, s) == 1) { 1259848b8605Smrg hud_cpu_graph_install(pane, i); 1260848b8605Smrg } 1261b8e80941Smrg else if (strcmp(name, "API-thread-busy") == 0) { 1262b8e80941Smrg hud_thread_busy_install(pane, name, false); 1263b8e80941Smrg } 1264b8e80941Smrg else if (strcmp(name, "API-thread-offloaded-slots") == 0) { 1265b8e80941Smrg hud_thread_counter_install(pane, name, HUD_COUNTER_OFFLOADED); 1266b8e80941Smrg } 1267b8e80941Smrg else if (strcmp(name, "API-thread-direct-slots") == 0) { 1268b8e80941Smrg hud_thread_counter_install(pane, name, HUD_COUNTER_DIRECT); 1269b8e80941Smrg } 1270b8e80941Smrg else if (strcmp(name, "API-thread-num-syncs") == 0) { 1271b8e80941Smrg hud_thread_counter_install(pane, name, HUD_COUNTER_SYNCS); 1272b8e80941Smrg } 1273b8e80941Smrg else if (strcmp(name, "main-thread-busy") == 0) { 1274b8e80941Smrg hud_thread_busy_install(pane, name, true); 1275b8e80941Smrg } 1276b8e80941Smrg#ifdef HAVE_GALLIUM_EXTRA_HUD 1277b8e80941Smrg else if (sscanf(name, "nic-rx-%s", arg_name) == 1) { 1278b8e80941Smrg hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX); 1279b8e80941Smrg } 1280b8e80941Smrg else if (sscanf(name, "nic-tx-%s", arg_name) == 1) { 1281b8e80941Smrg hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_TX); 1282b8e80941Smrg } 1283b8e80941Smrg else if (sscanf(name, "nic-rssi-%s", arg_name) == 1) { 1284b8e80941Smrg hud_nic_graph_install(pane, arg_name, NIC_RSSI_DBM); 1285b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_DBM; 1286b8e80941Smrg } 1287b8e80941Smrg else if (sscanf(name, "diskstat-rd-%s", arg_name) == 1) { 1288b8e80941Smrg hud_diskstat_graph_install(pane, arg_name, DISKSTAT_RD); 1289b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES; 1290b8e80941Smrg } 1291b8e80941Smrg else if (sscanf(name, "diskstat-wr-%s", arg_name) == 1) { 1292b8e80941Smrg hud_diskstat_graph_install(pane, arg_name, DISKSTAT_WR); 1293b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES; 1294b8e80941Smrg } 1295b8e80941Smrg else if (sscanf(name, "cpufreq-min-cpu%u", &i) == 1) { 1296b8e80941Smrg hud_cpufreq_graph_install(pane, i, CPUFREQ_MINIMUM); 1297b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; 1298b8e80941Smrg } 1299b8e80941Smrg else if (sscanf(name, "cpufreq-cur-cpu%u", &i) == 1) { 1300b8e80941Smrg hud_cpufreq_graph_install(pane, i, CPUFREQ_CURRENT); 1301b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; 1302b8e80941Smrg } 1303b8e80941Smrg else if (sscanf(name, "cpufreq-max-cpu%u", &i) == 1) { 1304b8e80941Smrg hud_cpufreq_graph_install(pane, i, CPUFREQ_MAXIMUM); 1305b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; 1306b8e80941Smrg } 1307b8e80941Smrg#endif 1308b8e80941Smrg#ifdef HAVE_LIBSENSORS 1309b8e80941Smrg else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) { 1310b8e80941Smrg hud_sensors_temp_graph_install(pane, arg_name, 1311b8e80941Smrg SENSORS_TEMP_CURRENT); 1312b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE; 1313b8e80941Smrg } 1314b8e80941Smrg else if (sscanf(name, "sensors_temp_cr-%s", arg_name) == 1) { 1315b8e80941Smrg hud_sensors_temp_graph_install(pane, arg_name, 1316b8e80941Smrg SENSORS_TEMP_CRITICAL); 1317b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE; 1318b8e80941Smrg } 1319b8e80941Smrg else if (sscanf(name, "sensors_volt_cu-%s", arg_name) == 1) { 1320b8e80941Smrg hud_sensors_temp_graph_install(pane, arg_name, 1321b8e80941Smrg SENSORS_VOLTAGE_CURRENT); 1322b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_VOLTS; 1323b8e80941Smrg } 1324b8e80941Smrg else if (sscanf(name, "sensors_curr_cu-%s", arg_name) == 1) { 1325b8e80941Smrg hud_sensors_temp_graph_install(pane, arg_name, 1326b8e80941Smrg SENSORS_CURRENT_CURRENT); 1327b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_AMPS; 1328b8e80941Smrg } 1329b8e80941Smrg else if (sscanf(name, "sensors_pow_cu-%s", arg_name) == 1) { 1330b8e80941Smrg hud_sensors_temp_graph_install(pane, arg_name, 1331b8e80941Smrg SENSORS_POWER_CURRENT); 1332b8e80941Smrg pane->type = PIPE_DRIVER_QUERY_TYPE_WATTS; 1333b8e80941Smrg } 1334b8e80941Smrg#endif 1335848b8605Smrg else if (strcmp(name, "samples-passed") == 0 && 1336b8e80941Smrg has_occlusion_query(screen)) { 1337b8e80941Smrg hud_pipe_query_install(&hud->batch_query, pane, 1338b8e80941Smrg "samples-passed", 1339b8e80941Smrg PIPE_QUERY_OCCLUSION_COUNTER, 0, 0, 1340b8e80941Smrg PIPE_DRIVER_QUERY_TYPE_UINT64, 1341b8e80941Smrg PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE, 1342b8e80941Smrg 0); 1343848b8605Smrg } 1344848b8605Smrg else if (strcmp(name, "primitives-generated") == 0 && 1345b8e80941Smrg has_streamout(screen)) { 1346b8e80941Smrg hud_pipe_query_install(&hud->batch_query, pane, 1347b8e80941Smrg "primitives-generated", 1348b8e80941Smrg PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0, 1349b8e80941Smrg PIPE_DRIVER_QUERY_TYPE_UINT64, 1350b8e80941Smrg PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE, 1351b8e80941Smrg 0); 1352848b8605Smrg } 1353848b8605Smrg else { 1354848b8605Smrg boolean processed = FALSE; 1355848b8605Smrg 1356848b8605Smrg /* pipeline statistics queries */ 1357b8e80941Smrg if (has_pipeline_stats_query(screen)) { 1358848b8605Smrg static const char *pipeline_statistics_names[] = 1359848b8605Smrg { 1360848b8605Smrg "ia-vertices", 1361848b8605Smrg "ia-primitives", 1362848b8605Smrg "vs-invocations", 1363848b8605Smrg "gs-invocations", 1364848b8605Smrg "gs-primitives", 1365848b8605Smrg "clipper-invocations", 1366848b8605Smrg "clipper-primitives-generated", 1367848b8605Smrg "ps-invocations", 1368848b8605Smrg "hs-invocations", 1369848b8605Smrg "ds-invocations", 1370848b8605Smrg "cs-invocations" 1371848b8605Smrg }; 1372b8e80941Smrg for (i = 0; i < ARRAY_SIZE(pipeline_statistics_names); ++i) 1373848b8605Smrg if (strcmp(name, pipeline_statistics_names[i]) == 0) 1374848b8605Smrg break; 1375b8e80941Smrg if (i < ARRAY_SIZE(pipeline_statistics_names)) { 1376b8e80941Smrg hud_pipe_query_install(&hud->batch_query, pane, name, 1377848b8605Smrg PIPE_QUERY_PIPELINE_STATISTICS, i, 1378b8e80941Smrg 0, PIPE_DRIVER_QUERY_TYPE_UINT64, 1379b8e80941Smrg PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE, 1380b8e80941Smrg 0); 1381848b8605Smrg processed = TRUE; 1382848b8605Smrg } 1383848b8605Smrg } 1384848b8605Smrg 1385848b8605Smrg /* driver queries */ 1386848b8605Smrg if (!processed) { 1387b8e80941Smrg if (!hud_driver_query_install(&hud->batch_query, pane, 1388b8e80941Smrg screen, name)) { 1389848b8605Smrg fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name); 1390b8e80941Smrg fflush(stderr); 1391b8e80941Smrg added = false; 1392848b8605Smrg } 1393848b8605Smrg } 1394848b8605Smrg } 1395848b8605Smrg 1396848b8605Smrg if (*env == ':') { 1397848b8605Smrg env++; 1398848b8605Smrg 1399848b8605Smrg if (!pane) { 1400848b8605Smrg fprintf(stderr, "gallium_hud: syntax error: unexpected ':', " 1401848b8605Smrg "expected a name\n"); 1402b8e80941Smrg fflush(stderr); 1403848b8605Smrg break; 1404848b8605Smrg } 1405848b8605Smrg 1406848b8605Smrg num = parse_string(env, s); 1407848b8605Smrg env += num; 1408848b8605Smrg 1409848b8605Smrg if (num && sscanf(s, "%u", &i) == 1) { 1410848b8605Smrg hud_pane_set_max_value(pane, i); 1411b8e80941Smrg pane->initial_max_value = i; 1412848b8605Smrg } 1413848b8605Smrg else { 1414848b8605Smrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) " 1415b8e80941Smrg "after ':'\n", *env, *env); 1416b8e80941Smrg fflush(stderr); 1417b8e80941Smrg } 1418b8e80941Smrg } 1419b8e80941Smrg 1420b8e80941Smrg if (*env == '=') { 1421b8e80941Smrg env++; 1422b8e80941Smrg 1423b8e80941Smrg if (!pane) { 1424b8e80941Smrg fprintf(stderr, "gallium_hud: syntax error: unexpected '=', " 1425b8e80941Smrg "expected a name\n"); 1426b8e80941Smrg fflush(stderr); 1427b8e80941Smrg break; 1428b8e80941Smrg } 1429b8e80941Smrg 1430b8e80941Smrg num = parse_string(env, s); 1431b8e80941Smrg env += num; 1432b8e80941Smrg 1433b8e80941Smrg strip_hyphens(s); 1434b8e80941Smrg if (added && !LIST_IS_EMPTY(&pane->graph_list)) { 1435b8e80941Smrg struct hud_graph *graph; 1436b8e80941Smrg graph = LIST_ENTRY(struct hud_graph, pane->graph_list.prev, head); 1437b8e80941Smrg strncpy(graph->name, s, sizeof(graph->name)-1); 1438b8e80941Smrg graph->name[sizeof(graph->name)-1] = 0; 1439848b8605Smrg } 1440848b8605Smrg } 1441848b8605Smrg 1442848b8605Smrg if (*env == 0) 1443848b8605Smrg break; 1444848b8605Smrg 1445848b8605Smrg /* parse a separator */ 1446848b8605Smrg switch (*env) { 1447848b8605Smrg case '+': 1448848b8605Smrg env++; 1449848b8605Smrg break; 1450848b8605Smrg 1451848b8605Smrg case ',': 1452848b8605Smrg env++; 1453b8e80941Smrg if (!pane) 1454b8e80941Smrg break; 1455b8e80941Smrg 1456848b8605Smrg y += height + hud->font.glyph_height * (pane->num_graphs + 2); 1457b8e80941Smrg y_simple += hud->font.glyph_height * (pane->num_graphs + 1); 1458b8e80941Smrg height = 100; 1459848b8605Smrg 1460848b8605Smrg if (pane && pane->num_graphs) { 1461848b8605Smrg LIST_ADDTAIL(&pane->head, &hud->pane_list); 1462848b8605Smrg pane = NULL; 1463848b8605Smrg } 1464848b8605Smrg break; 1465848b8605Smrg 1466848b8605Smrg case ';': 1467848b8605Smrg env++; 1468848b8605Smrg y = 10; 1469b8e80941Smrg y_simple = 10; 1470b8e80941Smrg x += column_width + hud->font.glyph_width * 9; 1471b8e80941Smrg height = 100; 1472848b8605Smrg 1473848b8605Smrg if (pane && pane->num_graphs) { 1474848b8605Smrg LIST_ADDTAIL(&pane->head, &hud->pane_list); 1475848b8605Smrg pane = NULL; 1476848b8605Smrg } 1477b8e80941Smrg 1478b8e80941Smrg /* Starting a new column; reset column width. */ 1479b8e80941Smrg column_width = 251; 1480848b8605Smrg break; 1481848b8605Smrg 1482848b8605Smrg default: 1483848b8605Smrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *env); 1484b8e80941Smrg fflush(stderr); 1485848b8605Smrg } 1486b8e80941Smrg 1487b8e80941Smrg /* Reset to defaults for the next pane in case these were modified. */ 1488b8e80941Smrg width = 251; 1489b8e80941Smrg ceiling = UINT64_MAX; 1490b8e80941Smrg dyn_ceiling = false; 1491b8e80941Smrg sort_items = false; 1492b8e80941Smrg 1493848b8605Smrg } 1494848b8605Smrg 1495848b8605Smrg if (pane) { 1496848b8605Smrg if (pane->num_graphs) { 1497848b8605Smrg LIST_ADDTAIL(&pane->head, &hud->pane_list); 1498848b8605Smrg } 1499848b8605Smrg else { 1500848b8605Smrg FREE(pane); 1501848b8605Smrg } 1502848b8605Smrg } 1503b8e80941Smrg 1504b8e80941Smrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 1505b8e80941Smrg struct hud_graph *gr; 1506b8e80941Smrg 1507b8e80941Smrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 1508b8e80941Smrg hud_graph_set_dump_file(gr); 1509b8e80941Smrg } 1510b8e80941Smrg } 1511848b8605Smrg} 1512848b8605Smrg 1513848b8605Smrgstatic void 1514848b8605Smrgprint_help(struct pipe_screen *screen) 1515848b8605Smrg{ 1516848b8605Smrg int i, num_queries, num_cpus = hud_get_num_cpus(); 1517848b8605Smrg 1518848b8605Smrg puts("Syntax: GALLIUM_HUD=name1[+name2][...][:value1][,nameI...][;nameJ...]"); 1519848b8605Smrg puts(""); 1520848b8605Smrg puts(" Names are identifiers of data sources which will be drawn as graphs"); 1521848b8605Smrg puts(" in panes. Multiple graphs can be drawn in the same pane."); 1522848b8605Smrg puts(" There can be multiple panes placed in rows and columns."); 1523848b8605Smrg puts(""); 1524848b8605Smrg puts(" '+' separates names which will share a pane."); 1525848b8605Smrg puts(" ':[value]' specifies the initial maximum value of the Y axis"); 1526848b8605Smrg puts(" for the given pane."); 1527848b8605Smrg puts(" ',' creates a new pane below the last one."); 1528848b8605Smrg puts(" ';' creates a new pane at the top of the next column."); 1529b8e80941Smrg puts(" '=' followed by a string, changes the name of the last data source"); 1530b8e80941Smrg puts(" to that string"); 1531848b8605Smrg puts(""); 1532848b8605Smrg puts(" Example: GALLIUM_HUD=\"cpu,fps;primitives-generated\""); 1533848b8605Smrg puts(""); 1534b8e80941Smrg puts(" Additionally, by prepending '.[identifier][value]' modifiers to"); 1535b8e80941Smrg puts(" a name, it is possible to explicitly set the location and size"); 1536b8e80941Smrg puts(" of a pane, along with limiting overall maximum value of the"); 1537b8e80941Smrg puts(" Y axis and activating dynamic readjustment of the Y axis."); 1538b8e80941Smrg puts(" Several modifiers may be applied to the same pane simultaneously."); 1539b8e80941Smrg puts(""); 1540b8e80941Smrg puts(" 'x[value]' sets the location of the pane on the x axis relative"); 1541b8e80941Smrg puts(" to the upper-left corner of the viewport, in pixels."); 1542b8e80941Smrg puts(" 'y[value]' sets the location of the pane on the y axis relative"); 1543b8e80941Smrg puts(" to the upper-left corner of the viewport, in pixels."); 1544b8e80941Smrg puts(" 'w[value]' sets width of the graph pixels."); 1545b8e80941Smrg puts(" 'h[value]' sets height of the graph in pixels."); 1546b8e80941Smrg puts(" 'c[value]' sets the ceiling of the value of the Y axis."); 1547b8e80941Smrg puts(" If the graph needs to draw values higher than"); 1548b8e80941Smrg puts(" the ceiling allows, the value is clamped."); 1549b8e80941Smrg puts(" 'd' activates dynamic Y axis readjustment to set the value of"); 1550b8e80941Smrg puts(" the Y axis to match the highest value still visible in the graph."); 1551b8e80941Smrg puts(" 'r' resets the color counter (the next color will be green)"); 1552b8e80941Smrg puts(" 's' sort items below graphs in descending order"); 1553b8e80941Smrg puts(""); 1554b8e80941Smrg puts(" If 'c' and 'd' modifiers are used simultaneously, both are in effect:"); 1555b8e80941Smrg puts(" the Y axis does not go above the restriction imposed by 'c' while"); 1556b8e80941Smrg puts(" still adjusting the value of the Y axis down when appropriate."); 1557b8e80941Smrg puts(""); 1558b8e80941Smrg puts(" You can change behavior of the whole HUD by adding these options at"); 1559b8e80941Smrg puts(" the beginning of the environment variable:"); 1560b8e80941Smrg puts(" 'simple,' disables all the fancy stuff and only draws text."); 1561b8e80941Smrg puts(""); 1562b8e80941Smrg puts(" Example: GALLIUM_HUD=\".w256.h64.x1600.y520.d.c1000fps+cpu,.datom-count\""); 1563b8e80941Smrg puts(""); 1564848b8605Smrg puts(" Available names:"); 1565848b8605Smrg puts(" fps"); 1566b8e80941Smrg puts(" frametime"); 1567848b8605Smrg puts(" cpu"); 1568848b8605Smrg 1569848b8605Smrg for (i = 0; i < num_cpus; i++) 1570848b8605Smrg printf(" cpu%i\n", i); 1571848b8605Smrg 1572848b8605Smrg if (has_occlusion_query(screen)) 1573848b8605Smrg puts(" samples-passed"); 1574848b8605Smrg if (has_streamout(screen)) 1575848b8605Smrg puts(" primitives-generated"); 1576848b8605Smrg 1577848b8605Smrg if (has_pipeline_stats_query(screen)) { 1578848b8605Smrg puts(" ia-vertices"); 1579848b8605Smrg puts(" ia-primitives"); 1580848b8605Smrg puts(" vs-invocations"); 1581848b8605Smrg puts(" gs-invocations"); 1582848b8605Smrg puts(" gs-primitives"); 1583848b8605Smrg puts(" clipper-invocations"); 1584848b8605Smrg puts(" clipper-primitives-generated"); 1585848b8605Smrg puts(" ps-invocations"); 1586848b8605Smrg puts(" hs-invocations"); 1587848b8605Smrg puts(" ds-invocations"); 1588848b8605Smrg puts(" cs-invocations"); 1589848b8605Smrg } 1590848b8605Smrg 1591b8e80941Smrg#ifdef HAVE_GALLIUM_EXTRA_HUD 1592b8e80941Smrg hud_get_num_disks(1); 1593b8e80941Smrg hud_get_num_nics(1); 1594b8e80941Smrg hud_get_num_cpufreq(1); 1595b8e80941Smrg#endif 1596b8e80941Smrg#ifdef HAVE_LIBSENSORS 1597b8e80941Smrg hud_get_num_sensors(1); 1598b8e80941Smrg#endif 1599b8e80941Smrg 1600848b8605Smrg if (screen->get_driver_query_info){ 1601b8e80941Smrg boolean skipping = false; 1602848b8605Smrg struct pipe_driver_query_info info; 1603848b8605Smrg num_queries = screen->get_driver_query_info(screen, 0, NULL); 1604848b8605Smrg 1605848b8605Smrg for (i = 0; i < num_queries; i++){ 1606848b8605Smrg screen->get_driver_query_info(screen, i, &info); 1607b8e80941Smrg if (info.flags & PIPE_DRIVER_QUERY_FLAG_DONT_LIST) { 1608b8e80941Smrg if (!skipping) 1609b8e80941Smrg puts(" ..."); 1610b8e80941Smrg skipping = true; 1611b8e80941Smrg } else { 1612b8e80941Smrg printf(" %s\n", info.name); 1613b8e80941Smrg skipping = false; 1614b8e80941Smrg } 1615848b8605Smrg } 1616848b8605Smrg } 1617848b8605Smrg 1618848b8605Smrg puts(""); 1619b8e80941Smrg fflush(stdout); 1620848b8605Smrg} 1621848b8605Smrg 1622b8e80941Smrgstatic void 1623b8e80941Smrghud_unset_draw_context(struct hud_context *hud) 1624848b8605Smrg{ 1625b8e80941Smrg struct pipe_context *pipe = hud->pipe; 1626848b8605Smrg 1627b8e80941Smrg if (!pipe) 1628b8e80941Smrg return; 1629848b8605Smrg 1630b8e80941Smrg pipe_sampler_view_reference(&hud->font_sampler_view, NULL); 1631b8e80941Smrg 1632b8e80941Smrg if (hud->fs_color) { 1633b8e80941Smrg pipe->delete_fs_state(pipe, hud->fs_color); 1634b8e80941Smrg hud->fs_color = NULL; 1635b8e80941Smrg } 1636b8e80941Smrg if (hud->fs_text) { 1637b8e80941Smrg pipe->delete_fs_state(pipe, hud->fs_text); 1638b8e80941Smrg hud->fs_text = NULL; 1639b8e80941Smrg } 1640b8e80941Smrg if (hud->vs) { 1641b8e80941Smrg pipe->delete_vs_state(pipe, hud->vs); 1642b8e80941Smrg hud->vs = NULL; 1643848b8605Smrg } 1644848b8605Smrg 1645b8e80941Smrg hud->cso = NULL; 1646b8e80941Smrg hud->pipe = NULL; 1647b8e80941Smrg} 1648848b8605Smrg 1649b8e80941Smrgstatic bool 1650b8e80941Smrghud_set_draw_context(struct hud_context *hud, struct cso_context *cso) 1651b8e80941Smrg{ 1652b8e80941Smrg struct pipe_context *pipe = cso_get_pipe_context(cso); 1653b8e80941Smrg 1654b8e80941Smrg assert(!hud->pipe); 1655848b8605Smrg hud->pipe = pipe; 1656848b8605Smrg hud->cso = cso; 1657848b8605Smrg 1658b8e80941Smrg struct pipe_sampler_view view_templ; 1659b8e80941Smrg u_sampler_view_default_template( 1660b8e80941Smrg &view_templ, hud->font.texture, hud->font.texture->format); 1661b8e80941Smrg hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture, 1662b8e80941Smrg &view_templ); 1663b8e80941Smrg if (!hud->font_sampler_view) 1664b8e80941Smrg goto fail; 1665848b8605Smrg 1666848b8605Smrg /* fragment shader */ 1667848b8605Smrg hud->fs_color = 1668848b8605Smrg util_make_fragment_passthrough_shader(pipe, 1669848b8605Smrg TGSI_SEMANTIC_COLOR, 1670848b8605Smrg TGSI_INTERPOLATE_CONSTANT, 1671848b8605Smrg TRUE); 1672848b8605Smrg 1673848b8605Smrg { 1674848b8605Smrg /* Read a texture and do .xxxx swizzling. */ 1675848b8605Smrg static const char *fragment_shader_text = { 1676848b8605Smrg "FRAG\n" 1677848b8605Smrg "DCL IN[0], GENERIC[0], LINEAR\n" 1678848b8605Smrg "DCL SAMP[0]\n" 1679b8e80941Smrg "DCL SVIEW[0], RECT, FLOAT\n" 1680848b8605Smrg "DCL OUT[0], COLOR[0]\n" 1681848b8605Smrg "DCL TEMP[0]\n" 1682848b8605Smrg 1683848b8605Smrg "TEX TEMP[0], IN[0], SAMP[0], RECT\n" 1684848b8605Smrg "MOV OUT[0], TEMP[0].xxxx\n" 1685848b8605Smrg "END\n" 1686848b8605Smrg }; 1687848b8605Smrg 1688848b8605Smrg struct tgsi_token tokens[1000]; 1689b8e80941Smrg struct pipe_shader_state state; 1690848b8605Smrg 1691b8e80941Smrg if (!tgsi_text_translate(fragment_shader_text, tokens, ARRAY_SIZE(tokens))) { 1692848b8605Smrg assert(0); 1693b8e80941Smrg goto fail; 1694848b8605Smrg } 1695b8e80941Smrg pipe_shader_state_from_tgsi(&state, tokens); 1696848b8605Smrg hud->fs_text = pipe->create_fs_state(pipe, &state); 1697848b8605Smrg } 1698848b8605Smrg 1699848b8605Smrg /* vertex shader */ 1700848b8605Smrg { 1701848b8605Smrg static const char *vertex_shader_text = { 1702848b8605Smrg "VERT\n" 1703848b8605Smrg "DCL IN[0..1]\n" 1704848b8605Smrg "DCL OUT[0], POSITION\n" 1705848b8605Smrg "DCL OUT[1], COLOR[0]\n" /* color */ 1706848b8605Smrg "DCL OUT[2], GENERIC[0]\n" /* texcoord */ 1707848b8605Smrg /* [0] = color, 1708848b8605Smrg * [1] = (2/fb_width, 2/fb_height, xoffset, yoffset) 1709848b8605Smrg * [2] = (xscale, yscale, 0, 0) */ 1710b8e80941Smrg "DCL CONST[0][0..2]\n" 1711848b8605Smrg "DCL TEMP[0]\n" 1712848b8605Smrg "IMM[0] FLT32 { -1, 0, 0, 1 }\n" 1713848b8605Smrg 1714848b8605Smrg /* v = in * (xscale, yscale) + (xoffset, yoffset) */ 1715b8e80941Smrg "MAD TEMP[0].xy, IN[0], CONST[0][2].xyyy, CONST[0][1].zwww\n" 1716848b8605Smrg /* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */ 1717b8e80941Smrg "MAD OUT[0].xy, TEMP[0], CONST[0][1].xyyy, IMM[0].xxxx\n" 1718848b8605Smrg "MOV OUT[0].zw, IMM[0]\n" 1719848b8605Smrg 1720b8e80941Smrg "MOV OUT[1], CONST[0][0]\n" 1721848b8605Smrg "MOV OUT[2], IN[1]\n" 1722848b8605Smrg "END\n" 1723848b8605Smrg }; 1724848b8605Smrg 1725848b8605Smrg struct tgsi_token tokens[1000]; 1726b8e80941Smrg struct pipe_shader_state state; 1727b8e80941Smrg if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) { 1728848b8605Smrg assert(0); 1729b8e80941Smrg goto fail; 1730848b8605Smrg } 1731b8e80941Smrg pipe_shader_state_from_tgsi(&state, tokens); 1732848b8605Smrg hud->vs = pipe->create_vs_state(pipe, &state); 1733848b8605Smrg } 1734848b8605Smrg 1735b8e80941Smrg return true; 1736b8e80941Smrg 1737b8e80941Smrgfail: 1738b8e80941Smrg hud_unset_draw_context(hud); 1739b8e80941Smrg fprintf(stderr, "hud: failed to set a draw context"); 1740b8e80941Smrg return false; 1741b8e80941Smrg} 1742b8e80941Smrg 1743b8e80941Smrgstatic void 1744b8e80941Smrghud_unset_record_context(struct hud_context *hud) 1745b8e80941Smrg{ 1746b8e80941Smrg struct pipe_context *pipe = hud->record_pipe; 1747b8e80941Smrg struct hud_pane *pane, *pane_tmp; 1748b8e80941Smrg struct hud_graph *graph, *graph_tmp; 1749b8e80941Smrg 1750b8e80941Smrg if (!pipe) 1751b8e80941Smrg return; 1752b8e80941Smrg 1753b8e80941Smrg LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) { 1754b8e80941Smrg LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) { 1755b8e80941Smrg LIST_DEL(&graph->head); 1756b8e80941Smrg hud_graph_destroy(graph, pipe); 1757b8e80941Smrg } 1758b8e80941Smrg LIST_DEL(&pane->head); 1759b8e80941Smrg FREE(pane); 1760b8e80941Smrg } 1761b8e80941Smrg 1762b8e80941Smrg hud_batch_query_cleanup(&hud->batch_query, pipe); 1763b8e80941Smrg hud->record_pipe = NULL; 1764b8e80941Smrg} 1765b8e80941Smrg 1766b8e80941Smrgstatic void 1767b8e80941Smrghud_set_record_context(struct hud_context *hud, struct pipe_context *pipe) 1768b8e80941Smrg{ 1769b8e80941Smrg hud->record_pipe = pipe; 1770b8e80941Smrg} 1771b8e80941Smrg 1772b8e80941Smrg/** 1773b8e80941Smrg * Create the HUD. 1774b8e80941Smrg * 1775b8e80941Smrg * If "share" is non-NULL and GALLIUM_HUD_SHARE=x,y is set, increment the 1776b8e80941Smrg * reference counter of "share", set "cso" as the recording or drawing context 1777b8e80941Smrg * according to the environment variable, and return "share". 1778b8e80941Smrg * This allows sharing the HUD instance within a multi-context share group, 1779b8e80941Smrg * record queries in one context and draw them in another. 1780b8e80941Smrg */ 1781b8e80941Smrgstruct hud_context * 1782b8e80941Smrghud_create(struct cso_context *cso, struct hud_context *share) 1783b8e80941Smrg{ 1784b8e80941Smrg const char *share_env = debug_get_option("GALLIUM_HUD_SHARE", NULL); 1785b8e80941Smrg unsigned record_ctx = 0, draw_ctx = 0; 1786b8e80941Smrg 1787b8e80941Smrg if (share_env && sscanf(share_env, "%u,%u", &record_ctx, &draw_ctx) != 2) 1788b8e80941Smrg share_env = NULL; 1789b8e80941Smrg 1790b8e80941Smrg if (share && share_env) { 1791b8e80941Smrg /* All contexts in a share group share the HUD instance. 1792b8e80941Smrg * Only one context can record queries and only one context 1793b8e80941Smrg * can draw the HUD. 1794b8e80941Smrg * 1795b8e80941Smrg * GALLIUM_HUD_SHARE=x,y determines the context indices. 1796b8e80941Smrg */ 1797b8e80941Smrg int context_id = p_atomic_inc_return(&share->refcount) - 1; 1798b8e80941Smrg 1799b8e80941Smrg if (context_id == record_ctx) { 1800b8e80941Smrg assert(!share->record_pipe); 1801b8e80941Smrg hud_set_record_context(share, cso_get_pipe_context(cso)); 1802b8e80941Smrg } 1803b8e80941Smrg 1804b8e80941Smrg if (context_id == draw_ctx) { 1805b8e80941Smrg assert(!share->pipe); 1806b8e80941Smrg hud_set_draw_context(share, cso); 1807b8e80941Smrg } 1808b8e80941Smrg 1809b8e80941Smrg return share; 1810b8e80941Smrg } 1811b8e80941Smrg 1812b8e80941Smrg struct pipe_screen *screen = cso_get_pipe_context(cso)->screen; 1813b8e80941Smrg struct hud_context *hud; 1814b8e80941Smrg unsigned i; 1815b8e80941Smrg const char *env = debug_get_option("GALLIUM_HUD", NULL); 1816b8e80941Smrg#ifdef PIPE_OS_UNIX 1817b8e80941Smrg unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0); 1818b8e80941Smrg static boolean sig_handled = FALSE; 1819b8e80941Smrg struct sigaction action = {}; 1820b8e80941Smrg#endif 1821b8e80941Smrg huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE); 1822b8e80941Smrg 1823b8e80941Smrg if (!env || !*env) 1824b8e80941Smrg return NULL; 1825b8e80941Smrg 1826b8e80941Smrg if (strcmp(env, "help") == 0) { 1827b8e80941Smrg print_help(screen); 1828b8e80941Smrg return NULL; 1829b8e80941Smrg } 1830b8e80941Smrg 1831b8e80941Smrg hud = CALLOC_STRUCT(hud_context); 1832b8e80941Smrg if (!hud) 1833b8e80941Smrg return NULL; 1834b8e80941Smrg 1835b8e80941Smrg /* font (the context is only used for the texture upload) */ 1836b8e80941Smrg if (!util_font_create(cso_get_pipe_context(cso), 1837b8e80941Smrg UTIL_FONT_FIXED_8X13, &hud->font)) { 1838b8e80941Smrg FREE(hud); 1839b8e80941Smrg return NULL; 1840b8e80941Smrg } 1841b8e80941Smrg 1842b8e80941Smrg hud->refcount = 1; 1843b8e80941Smrg hud->has_srgb = screen->is_format_supported(screen, 1844b8e80941Smrg PIPE_FORMAT_B8G8R8A8_SRGB, 1845b8e80941Smrg PIPE_TEXTURE_2D, 0, 0, 1846b8e80941Smrg PIPE_BIND_RENDER_TARGET) != 0; 1847b8e80941Smrg 1848b8e80941Smrg /* blend state */ 1849b8e80941Smrg hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA; 1850b8e80941Smrg 1851b8e80941Smrg hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA; 1852b8e80941Smrg hud->alpha_blend.rt[0].blend_enable = 1; 1853b8e80941Smrg hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD; 1854b8e80941Smrg hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; 1855b8e80941Smrg hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; 1856b8e80941Smrg hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD; 1857b8e80941Smrg hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; 1858b8e80941Smrg hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; 1859b8e80941Smrg 1860b8e80941Smrg /* rasterizer */ 1861b8e80941Smrg hud->rasterizer.half_pixel_center = 1; 1862b8e80941Smrg hud->rasterizer.bottom_edge_rule = 1; 1863b8e80941Smrg hud->rasterizer.depth_clip_near = 1; 1864b8e80941Smrg hud->rasterizer.depth_clip_far = 1; 1865b8e80941Smrg hud->rasterizer.line_width = 1; 1866b8e80941Smrg hud->rasterizer.line_last_pixel = 1; 1867b8e80941Smrg 1868b8e80941Smrg hud->rasterizer_aa_lines = hud->rasterizer; 1869b8e80941Smrg hud->rasterizer_aa_lines.line_smooth = 1; 1870b8e80941Smrg 1871848b8605Smrg /* vertex elements */ 1872848b8605Smrg for (i = 0; i < 2; i++) { 1873848b8605Smrg hud->velems[i].src_offset = i * 2 * sizeof(float); 1874848b8605Smrg hud->velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT; 1875b8e80941Smrg hud->velems[i].vertex_buffer_index = 0; 1876848b8605Smrg } 1877848b8605Smrg 1878848b8605Smrg /* sampler state (for font drawing) */ 1879848b8605Smrg hud->font_sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 1880848b8605Smrg hud->font_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 1881848b8605Smrg hud->font_sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 1882848b8605Smrg hud->font_sampler_state.normalized_coords = 0; 1883848b8605Smrg 1884848b8605Smrg /* constants */ 1885848b8605Smrg hud->constbuf.buffer_size = sizeof(hud->constants); 1886848b8605Smrg hud->constbuf.user_buffer = &hud->constants; 1887848b8605Smrg 1888848b8605Smrg LIST_INITHEAD(&hud->pane_list); 1889848b8605Smrg 1890b8e80941Smrg /* setup sig handler once for all hud contexts */ 1891b8e80941Smrg#ifdef PIPE_OS_UNIX 1892b8e80941Smrg if (!sig_handled && signo != 0) { 1893b8e80941Smrg action.sa_sigaction = &signal_visible_handler; 1894b8e80941Smrg action.sa_flags = SA_SIGINFO; 1895b8e80941Smrg 1896b8e80941Smrg if (signo >= NSIG) 1897b8e80941Smrg fprintf(stderr, "gallium_hud: invalid signal %u\n", signo); 1898b8e80941Smrg else if (sigaction(signo, &action, NULL) < 0) 1899b8e80941Smrg fprintf(stderr, "gallium_hud: unable to set handler for signal %u\n", signo); 1900b8e80941Smrg fflush(stderr); 1901b8e80941Smrg 1902b8e80941Smrg sig_handled = TRUE; 1903b8e80941Smrg } 1904b8e80941Smrg#endif 1905b8e80941Smrg 1906b8e80941Smrg if (record_ctx == 0) 1907b8e80941Smrg hud_set_record_context(hud, cso_get_pipe_context(cso)); 1908b8e80941Smrg if (draw_ctx == 0) 1909b8e80941Smrg hud_set_draw_context(hud, cso); 1910b8e80941Smrg 1911b8e80941Smrg hud_parse_env_var(hud, screen, env); 1912848b8605Smrg return hud; 1913848b8605Smrg} 1914848b8605Smrg 1915b8e80941Smrg/** 1916b8e80941Smrg * Destroy a HUD. If the HUD has several users, decrease the reference counter 1917b8e80941Smrg * and detach the context from the HUD. 1918b8e80941Smrg */ 1919848b8605Smrgvoid 1920b8e80941Smrghud_destroy(struct hud_context *hud, struct cso_context *cso) 1921848b8605Smrg{ 1922b8e80941Smrg if (!cso || hud->record_pipe == cso_get_pipe_context(cso)) 1923b8e80941Smrg hud_unset_record_context(hud); 1924848b8605Smrg 1925b8e80941Smrg if (!cso || hud->cso == cso) 1926b8e80941Smrg hud_unset_draw_context(hud); 1927b8e80941Smrg 1928b8e80941Smrg if (p_atomic_dec_zero(&hud->refcount)) { 1929b8e80941Smrg pipe_resource_reference(&hud->font.texture, NULL); 1930b8e80941Smrg FREE(hud); 1931848b8605Smrg } 1932b8e80941Smrg} 1933848b8605Smrg 1934b8e80941Smrgvoid 1935b8e80941Smrghud_add_queue_for_monitoring(struct hud_context *hud, 1936b8e80941Smrg struct util_queue_monitoring *queue_info) 1937b8e80941Smrg{ 1938b8e80941Smrg assert(!hud->monitored_queue); 1939b8e80941Smrg hud->monitored_queue = queue_info; 1940848b8605Smrg} 1941