1af69d88dSmrg/************************************************************************** 2af69d88dSmrg * 3af69d88dSmrg * Copyright 2013 Marek Olšák <maraeo@gmail.com> 4af69d88dSmrg * All Rights Reserved. 5af69d88dSmrg * 6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 7af69d88dSmrg * copy of this software and associated documentation files (the 8af69d88dSmrg * "Software"), to deal in the Software without restriction, including 9af69d88dSmrg * without limitation the rights to use, copy, modify, merge, publish, 10af69d88dSmrg * distribute, sub license, and/or sell copies of the Software, and to 11af69d88dSmrg * permit persons to whom the Software is furnished to do so, subject to 12af69d88dSmrg * the following conditions: 13af69d88dSmrg * 14af69d88dSmrg * The above copyright notice and this permission notice (including the 15af69d88dSmrg * next paragraph) shall be included in all copies or substantial portions 16af69d88dSmrg * of the Software. 17af69d88dSmrg * 18af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20af69d88dSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21af69d88dSmrg * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 22af69d88dSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23af69d88dSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24af69d88dSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25af69d88dSmrg * 26af69d88dSmrg **************************************************************************/ 27af69d88dSmrg 28af69d88dSmrg/* This head-up display module can draw transparent graphs on top of what 29af69d88dSmrg * the app is rendering, visualizing various data like framerate, cpu load, 307ec681f3Smrg * performance counters, etc. It can be hook up into any gallium frontend. 31af69d88dSmrg * 32af69d88dSmrg * The HUD is controlled with the GALLIUM_HUD environment variable. 33af69d88dSmrg * Set GALLIUM_HUD=help for more info. 34af69d88dSmrg */ 35af69d88dSmrg 3601e04c3fSmrg#include <inttypes.h> 3701e04c3fSmrg#include <signal.h> 38af69d88dSmrg#include <stdio.h> 39af69d88dSmrg 40af69d88dSmrg#include "hud/hud_context.h" 41af69d88dSmrg#include "hud/hud_private.h" 42af69d88dSmrg 437ec681f3Smrg#include "frontend/api.h" 44af69d88dSmrg#include "cso_cache/cso_context.h" 45af69d88dSmrg#include "util/u_draw_quad.h" 467ec681f3Smrg#include "util/format/u_format.h" 47af69d88dSmrg#include "util/u_inlines.h" 48af69d88dSmrg#include "util/u_memory.h" 49af69d88dSmrg#include "util/u_math.h" 5001e04c3fSmrg#include "util/u_sampler.h" 51af69d88dSmrg#include "util/u_simple_shaders.h" 52af69d88dSmrg#include "util/u_string.h" 53af69d88dSmrg#include "util/u_upload_mgr.h" 54af69d88dSmrg#include "tgsi/tgsi_text.h" 55af69d88dSmrg#include "tgsi/tgsi_dump.h" 56af69d88dSmrg 5701e04c3fSmrg/* Control the visibility of all HUD contexts */ 5801e04c3fSmrgstatic boolean huds_visible = TRUE; 597ec681f3Smrgstatic int hud_scale = 1; 60af69d88dSmrg 61af69d88dSmrg 6201e04c3fSmrg#ifdef PIPE_OS_UNIX 6301e04c3fSmrgstatic void 6401e04c3fSmrgsignal_visible_handler(int sig, siginfo_t *siginfo, void *context) 6501e04c3fSmrg{ 6601e04c3fSmrg huds_visible = !huds_visible; 6701e04c3fSmrg} 6801e04c3fSmrg#endif 69af69d88dSmrg 70af69d88dSmrgstatic void 71af69d88dSmrghud_draw_colored_prims(struct hud_context *hud, unsigned prim, 72af69d88dSmrg float *buffer, unsigned num_vertices, 73af69d88dSmrg float r, float g, float b, float a, 74af69d88dSmrg int xoffset, int yoffset, float yscale) 75af69d88dSmrg{ 76af69d88dSmrg struct cso_context *cso = hud->cso; 777ec681f3Smrg struct pipe_context *pipe = hud->pipe; 787ec681f3Smrg struct pipe_vertex_buffer vbuffer = {0}; 79af69d88dSmrg 80af69d88dSmrg hud->constants.color[0] = r; 81af69d88dSmrg hud->constants.color[1] = g; 82af69d88dSmrg hud->constants.color[2] = b; 83af69d88dSmrg hud->constants.color[3] = a; 847ec681f3Smrg hud->constants.translate[0] = (float) (xoffset * hud_scale); 857ec681f3Smrg hud->constants.translate[1] = (float) (yoffset * hud_scale); 867ec681f3Smrg hud->constants.scale[0] = hud_scale; 877ec681f3Smrg hud->constants.scale[1] = yscale * hud_scale; 887ec681f3Smrg pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf); 897ec681f3Smrg 907ec681f3Smrg u_upload_data(hud->pipe->stream_uploader, 0, 917ec681f3Smrg num_vertices * 2 * sizeof(float), 16, buffer, 927ec681f3Smrg &vbuffer.buffer_offset, &vbuffer.buffer.resource); 937ec681f3Smrg u_upload_unmap(hud->pipe->stream_uploader); 947ec681f3Smrg vbuffer.stride = 2 * sizeof(float); 957ec681f3Smrg 967ec681f3Smrg cso_set_vertex_buffers(cso, 0, 1, &vbuffer); 977ec681f3Smrg pipe_resource_reference(&vbuffer.buffer.resource, NULL); 98af69d88dSmrg cso_set_fragment_shader_handle(hud->cso, hud->fs_color); 99af69d88dSmrg cso_draw_arrays(cso, prim, 0, num_vertices); 100af69d88dSmrg} 101af69d88dSmrg 102af69d88dSmrgstatic void 103af69d88dSmrghud_draw_colored_quad(struct hud_context *hud, unsigned prim, 104af69d88dSmrg unsigned x1, unsigned y1, unsigned x2, unsigned y2, 105af69d88dSmrg float r, float g, float b, float a) 106af69d88dSmrg{ 107af69d88dSmrg float buffer[] = { 108af69d88dSmrg (float) x1, (float) y1, 109af69d88dSmrg (float) x1, (float) y2, 110af69d88dSmrg (float) x2, (float) y2, 111af69d88dSmrg (float) x2, (float) y1, 112af69d88dSmrg }; 113af69d88dSmrg 114af69d88dSmrg hud_draw_colored_prims(hud, prim, buffer, 4, r, g, b, a, 0, 0, 1); 115af69d88dSmrg} 116af69d88dSmrg 117af69d88dSmrgstatic void 118af69d88dSmrghud_draw_background_quad(struct hud_context *hud, 119af69d88dSmrg unsigned x1, unsigned y1, unsigned x2, unsigned y2) 120af69d88dSmrg{ 121af69d88dSmrg float *vertices = hud->bg.vertices + hud->bg.num_vertices*2; 122af69d88dSmrg unsigned num = 0; 123af69d88dSmrg 124af69d88dSmrg assert(hud->bg.num_vertices + 4 <= hud->bg.max_num_vertices); 125af69d88dSmrg 126af69d88dSmrg vertices[num++] = (float) x1; 127af69d88dSmrg vertices[num++] = (float) y1; 128af69d88dSmrg 129af69d88dSmrg vertices[num++] = (float) x1; 130af69d88dSmrg vertices[num++] = (float) y2; 131af69d88dSmrg 132af69d88dSmrg vertices[num++] = (float) x2; 133af69d88dSmrg vertices[num++] = (float) y2; 134af69d88dSmrg 135af69d88dSmrg vertices[num++] = (float) x2; 136af69d88dSmrg vertices[num++] = (float) y1; 137af69d88dSmrg 138af69d88dSmrg hud->bg.num_vertices += num/2; 139af69d88dSmrg} 140af69d88dSmrg 141af69d88dSmrgstatic void 142af69d88dSmrghud_draw_string(struct hud_context *hud, unsigned x, unsigned y, 143af69d88dSmrg const char *str, ...) 144af69d88dSmrg{ 145af69d88dSmrg char buf[256]; 146af69d88dSmrg char *s = buf; 147af69d88dSmrg float *vertices = hud->text.vertices + hud->text.num_vertices*4; 148af69d88dSmrg unsigned num = 0; 149af69d88dSmrg 150af69d88dSmrg va_list ap; 151af69d88dSmrg va_start(ap, str); 1527ec681f3Smrg vsnprintf(buf, sizeof(buf), str, ap); 153af69d88dSmrg va_end(ap); 154af69d88dSmrg 155af69d88dSmrg if (!*s) 156af69d88dSmrg return; 157af69d88dSmrg 158af69d88dSmrg hud_draw_background_quad(hud, 159af69d88dSmrg x, y, 160af69d88dSmrg x + strlen(buf)*hud->font.glyph_width, 161af69d88dSmrg y + hud->font.glyph_height); 162af69d88dSmrg 163af69d88dSmrg while (*s) { 164af69d88dSmrg unsigned x1 = x; 165af69d88dSmrg unsigned y1 = y; 166af69d88dSmrg unsigned x2 = x + hud->font.glyph_width; 167af69d88dSmrg unsigned y2 = y + hud->font.glyph_height; 168af69d88dSmrg unsigned tx1 = (*s % 16) * hud->font.glyph_width; 169af69d88dSmrg unsigned ty1 = (*s / 16) * hud->font.glyph_height; 170af69d88dSmrg unsigned tx2 = tx1 + hud->font.glyph_width; 171af69d88dSmrg unsigned ty2 = ty1 + hud->font.glyph_height; 172af69d88dSmrg 173af69d88dSmrg if (*s == ' ') { 174af69d88dSmrg x += hud->font.glyph_width; 175af69d88dSmrg s++; 176af69d88dSmrg continue; 177af69d88dSmrg } 178af69d88dSmrg 179af69d88dSmrg assert(hud->text.num_vertices + num/4 + 4 <= hud->text.max_num_vertices); 180af69d88dSmrg 181af69d88dSmrg vertices[num++] = (float) x1; 182af69d88dSmrg vertices[num++] = (float) y1; 183af69d88dSmrg vertices[num++] = (float) tx1; 184af69d88dSmrg vertices[num++] = (float) ty1; 185af69d88dSmrg 186af69d88dSmrg vertices[num++] = (float) x1; 187af69d88dSmrg vertices[num++] = (float) y2; 188af69d88dSmrg vertices[num++] = (float) tx1; 189af69d88dSmrg vertices[num++] = (float) ty2; 190af69d88dSmrg 191af69d88dSmrg vertices[num++] = (float) x2; 192af69d88dSmrg vertices[num++] = (float) y2; 193af69d88dSmrg vertices[num++] = (float) tx2; 194af69d88dSmrg vertices[num++] = (float) ty2; 195af69d88dSmrg 196af69d88dSmrg vertices[num++] = (float) x2; 197af69d88dSmrg vertices[num++] = (float) y1; 198af69d88dSmrg vertices[num++] = (float) tx2; 199af69d88dSmrg vertices[num++] = (float) ty1; 200af69d88dSmrg 201af69d88dSmrg x += hud->font.glyph_width; 202af69d88dSmrg s++; 203af69d88dSmrg } 204af69d88dSmrg 205af69d88dSmrg hud->text.num_vertices += num/4; 206af69d88dSmrg} 207af69d88dSmrg 208af69d88dSmrgstatic void 20901e04c3fSmrgnumber_to_human_readable(double num, enum pipe_driver_query_type type, 21001e04c3fSmrg char *out) 211af69d88dSmrg{ 212af69d88dSmrg static const char *byte_units[] = 21301e04c3fSmrg {" B", " KB", " MB", " GB", " TB", " PB", " EB"}; 214af69d88dSmrg static const char *metric_units[] = 215af69d88dSmrg {"", " k", " M", " G", " T", " P", " E"}; 21601e04c3fSmrg static const char *time_units[] = 21701e04c3fSmrg {" us", " ms", " s"}; /* based on microseconds */ 21801e04c3fSmrg static const char *hz_units[] = 21901e04c3fSmrg {" Hz", " KHz", " MHz", " GHz"}; 22001e04c3fSmrg static const char *percent_units[] = {"%"}; 22101e04c3fSmrg static const char *dbm_units[] = {" (-dBm)"}; 22201e04c3fSmrg static const char *temperature_units[] = {" C"}; 22301e04c3fSmrg static const char *volt_units[] = {" mV", " V"}; 22401e04c3fSmrg static const char *amp_units[] = {" mA", " A"}; 22501e04c3fSmrg static const char *watt_units[] = {" mW", " W"}; 22601e04c3fSmrg static const char *float_units[] = {""}; 22701e04c3fSmrg 22801e04c3fSmrg const char **units; 22901e04c3fSmrg unsigned max_unit; 23001e04c3fSmrg double divisor = (type == PIPE_DRIVER_QUERY_TYPE_BYTES) ? 1024 : 1000; 23101e04c3fSmrg unsigned unit = 0; 232af69d88dSmrg double d = num; 233af69d88dSmrg 23401e04c3fSmrg switch (type) { 23501e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS: 23601e04c3fSmrg max_unit = ARRAY_SIZE(time_units)-1; 23701e04c3fSmrg units = time_units; 23801e04c3fSmrg break; 23901e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_VOLTS: 24001e04c3fSmrg max_unit = ARRAY_SIZE(volt_units)-1; 24101e04c3fSmrg units = volt_units; 24201e04c3fSmrg break; 24301e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_AMPS: 24401e04c3fSmrg max_unit = ARRAY_SIZE(amp_units)-1; 24501e04c3fSmrg units = amp_units; 24601e04c3fSmrg break; 24701e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_DBM: 24801e04c3fSmrg max_unit = ARRAY_SIZE(dbm_units)-1; 24901e04c3fSmrg units = dbm_units; 25001e04c3fSmrg break; 25101e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_TEMPERATURE: 25201e04c3fSmrg max_unit = ARRAY_SIZE(temperature_units)-1; 25301e04c3fSmrg units = temperature_units; 25401e04c3fSmrg break; 25501e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_FLOAT: 25601e04c3fSmrg max_unit = ARRAY_SIZE(float_units)-1; 25701e04c3fSmrg units = float_units; 25801e04c3fSmrg break; 25901e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE: 26001e04c3fSmrg max_unit = ARRAY_SIZE(percent_units)-1; 26101e04c3fSmrg units = percent_units; 26201e04c3fSmrg break; 26301e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_BYTES: 26401e04c3fSmrg max_unit = ARRAY_SIZE(byte_units)-1; 26501e04c3fSmrg units = byte_units; 26601e04c3fSmrg break; 26701e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_HZ: 26801e04c3fSmrg max_unit = ARRAY_SIZE(hz_units)-1; 26901e04c3fSmrg units = hz_units; 27001e04c3fSmrg break; 27101e04c3fSmrg case PIPE_DRIVER_QUERY_TYPE_WATTS: 27201e04c3fSmrg max_unit = ARRAY_SIZE(watt_units)-1; 27301e04c3fSmrg units = watt_units; 27401e04c3fSmrg break; 27501e04c3fSmrg default: 27601e04c3fSmrg max_unit = ARRAY_SIZE(metric_units)-1; 27701e04c3fSmrg units = metric_units; 27801e04c3fSmrg } 27901e04c3fSmrg 28001e04c3fSmrg while (d > divisor && unit < max_unit) { 281af69d88dSmrg d /= divisor; 282af69d88dSmrg unit++; 283af69d88dSmrg } 284af69d88dSmrg 28501e04c3fSmrg /* Round to 3 decimal places so as not to print trailing zeros. */ 28601e04c3fSmrg if (d*1000 != (int)(d*1000)) 28701e04c3fSmrg d = round(d * 1000) / 1000; 28801e04c3fSmrg 28901e04c3fSmrg /* Show at least 4 digits with at most 3 decimal places, but not zeros. */ 29001e04c3fSmrg if (d >= 1000 || d == (int)d) 291af69d88dSmrg sprintf(out, "%.0f%s", d, units[unit]); 29201e04c3fSmrg else if (d >= 100 || d*10 == (int)(d*10)) 293af69d88dSmrg sprintf(out, "%.1f%s", d, units[unit]); 29401e04c3fSmrg else if (d >= 10 || d*100 == (int)(d*100)) 295af69d88dSmrg sprintf(out, "%.2f%s", d, units[unit]); 29601e04c3fSmrg else 29701e04c3fSmrg sprintf(out, "%.3f%s", d, units[unit]); 298af69d88dSmrg} 299af69d88dSmrg 300af69d88dSmrgstatic void 301af69d88dSmrghud_draw_graph_line_strip(struct hud_context *hud, const struct hud_graph *gr, 302af69d88dSmrg unsigned xoffset, unsigned yoffset, float yscale) 303af69d88dSmrg{ 304af69d88dSmrg if (gr->num_vertices <= 1) 305af69d88dSmrg return; 306af69d88dSmrg 307af69d88dSmrg assert(gr->index <= gr->num_vertices); 308af69d88dSmrg 309af69d88dSmrg hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP, 310af69d88dSmrg gr->vertices, gr->index, 311af69d88dSmrg gr->color[0], gr->color[1], gr->color[2], 1, 312af69d88dSmrg xoffset + (gr->pane->max_num_vertices - gr->index - 1) * 2 - 1, 313af69d88dSmrg yoffset, yscale); 314af69d88dSmrg 315af69d88dSmrg if (gr->num_vertices <= gr->index) 316af69d88dSmrg return; 317af69d88dSmrg 318af69d88dSmrg hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP, 319af69d88dSmrg gr->vertices + gr->index*2, 320af69d88dSmrg gr->num_vertices - gr->index, 321af69d88dSmrg gr->color[0], gr->color[1], gr->color[2], 1, 322af69d88dSmrg xoffset - gr->index*2 - 1, yoffset, yscale); 323af69d88dSmrg} 324af69d88dSmrg 325af69d88dSmrgstatic void 326af69d88dSmrghud_pane_accumulate_vertices(struct hud_context *hud, 327af69d88dSmrg const struct hud_pane *pane) 328af69d88dSmrg{ 329af69d88dSmrg struct hud_graph *gr; 330af69d88dSmrg float *line_verts = hud->whitelines.vertices + hud->whitelines.num_vertices*2; 331af69d88dSmrg unsigned i, num = 0; 332af69d88dSmrg char str[32]; 33301e04c3fSmrg const unsigned last_line = pane->last_line; 334af69d88dSmrg 335af69d88dSmrg /* draw background */ 336af69d88dSmrg hud_draw_background_quad(hud, 337af69d88dSmrg pane->x1, pane->y1, 338af69d88dSmrg pane->x2, pane->y2); 339af69d88dSmrg 340af69d88dSmrg /* draw numbers on the right-hand side */ 34101e04c3fSmrg for (i = 0; i <= last_line; i++) { 342af69d88dSmrg unsigned x = pane->x2 + 2; 34301e04c3fSmrg unsigned y = pane->inner_y1 + 34401e04c3fSmrg pane->inner_height * (last_line - i) / last_line - 345af69d88dSmrg hud->font.glyph_height / 2; 346af69d88dSmrg 34701e04c3fSmrg number_to_human_readable(pane->max_value * i / last_line, 34801e04c3fSmrg pane->type, str); 34901e04c3fSmrg hud_draw_string(hud, x, y, "%s", str); 350af69d88dSmrg } 351af69d88dSmrg 352af69d88dSmrg /* draw info below the pane */ 353af69d88dSmrg i = 0; 354af69d88dSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 355af69d88dSmrg unsigned x = pane->x1 + 2; 356af69d88dSmrg unsigned y = pane->y2 + 2 + i*hud->font.glyph_height; 357af69d88dSmrg 35801e04c3fSmrg number_to_human_readable(gr->current_value, pane->type, str); 359af69d88dSmrg hud_draw_string(hud, x, y, " %s: %s", gr->name, str); 360af69d88dSmrg i++; 361af69d88dSmrg } 362af69d88dSmrg 363af69d88dSmrg /* draw border */ 364af69d88dSmrg assert(hud->whitelines.num_vertices + num/2 + 8 <= hud->whitelines.max_num_vertices); 365af69d88dSmrg line_verts[num++] = (float) pane->x1; 366af69d88dSmrg line_verts[num++] = (float) pane->y1; 367af69d88dSmrg line_verts[num++] = (float) pane->x2; 368af69d88dSmrg line_verts[num++] = (float) pane->y1; 369af69d88dSmrg 370af69d88dSmrg line_verts[num++] = (float) pane->x2; 371af69d88dSmrg line_verts[num++] = (float) pane->y1; 372af69d88dSmrg line_verts[num++] = (float) pane->x2; 373af69d88dSmrg line_verts[num++] = (float) pane->y2; 374af69d88dSmrg 375af69d88dSmrg line_verts[num++] = (float) pane->x1; 376af69d88dSmrg line_verts[num++] = (float) pane->y2; 377af69d88dSmrg line_verts[num++] = (float) pane->x2; 378af69d88dSmrg line_verts[num++] = (float) pane->y2; 379af69d88dSmrg 380af69d88dSmrg line_verts[num++] = (float) pane->x1; 381af69d88dSmrg line_verts[num++] = (float) pane->y1; 382af69d88dSmrg line_verts[num++] = (float) pane->x1; 383af69d88dSmrg line_verts[num++] = (float) pane->y2; 384af69d88dSmrg 385af69d88dSmrg /* draw horizontal lines inside the graph */ 38601e04c3fSmrg for (i = 0; i <= last_line; i++) { 38701e04c3fSmrg float y = round((pane->max_value * i / (double)last_line) * 38801e04c3fSmrg pane->yscale + pane->inner_y2); 389af69d88dSmrg 390af69d88dSmrg assert(hud->whitelines.num_vertices + num/2 + 2 <= hud->whitelines.max_num_vertices); 391af69d88dSmrg line_verts[num++] = pane->x1; 392af69d88dSmrg line_verts[num++] = y; 393af69d88dSmrg line_verts[num++] = pane->x2; 394af69d88dSmrg line_verts[num++] = y; 395af69d88dSmrg } 396af69d88dSmrg 397af69d88dSmrg hud->whitelines.num_vertices += num/2; 398af69d88dSmrg} 399af69d88dSmrg 40001e04c3fSmrgstatic void 40101e04c3fSmrghud_pane_accumulate_vertices_simple(struct hud_context *hud, 40201e04c3fSmrg const struct hud_pane *pane) 40301e04c3fSmrg{ 40401e04c3fSmrg struct hud_graph *gr; 40501e04c3fSmrg unsigned i; 40601e04c3fSmrg char str[32]; 40701e04c3fSmrg 40801e04c3fSmrg /* draw info below the pane */ 40901e04c3fSmrg i = 0; 41001e04c3fSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 41101e04c3fSmrg unsigned x = pane->x1; 41201e04c3fSmrg unsigned y = pane->y_simple + i*hud->font.glyph_height; 41301e04c3fSmrg 41401e04c3fSmrg number_to_human_readable(gr->current_value, pane->type, str); 41501e04c3fSmrg hud_draw_string(hud, x, y, "%s: %s", gr->name, str); 41601e04c3fSmrg i++; 41701e04c3fSmrg } 41801e04c3fSmrg} 41901e04c3fSmrg 420af69d88dSmrgstatic void 421af69d88dSmrghud_pane_draw_colored_objects(struct hud_context *hud, 422af69d88dSmrg const struct hud_pane *pane) 423af69d88dSmrg{ 424af69d88dSmrg struct hud_graph *gr; 425af69d88dSmrg unsigned i; 426af69d88dSmrg 427af69d88dSmrg /* draw colored quads below the pane */ 428af69d88dSmrg i = 0; 429af69d88dSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 430af69d88dSmrg unsigned x = pane->x1 + 2; 431af69d88dSmrg unsigned y = pane->y2 + 2 + i*hud->font.glyph_height; 432af69d88dSmrg 433af69d88dSmrg hud_draw_colored_quad(hud, PIPE_PRIM_QUADS, x + 1, y + 1, x + 12, y + 13, 434af69d88dSmrg gr->color[0], gr->color[1], gr->color[2], 1); 435af69d88dSmrg i++; 436af69d88dSmrg } 437af69d88dSmrg 438af69d88dSmrg /* draw the line strips */ 439af69d88dSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 440af69d88dSmrg hud_draw_graph_line_strip(hud, gr, pane->inner_x1, pane->inner_y2, pane->yscale); 441af69d88dSmrg } 442af69d88dSmrg} 443af69d88dSmrg 444af69d88dSmrgstatic void 44501e04c3fSmrghud_prepare_vertices(struct hud_context *hud, struct vertex_queue *v, 44601e04c3fSmrg unsigned num_vertices, unsigned stride) 447af69d88dSmrg{ 448af69d88dSmrg v->num_vertices = 0; 449af69d88dSmrg v->max_num_vertices = num_vertices; 450af69d88dSmrg v->vbuf.stride = stride; 45101e04c3fSmrg v->buffer_size = stride * num_vertices; 452af69d88dSmrg} 453af69d88dSmrg 454af69d88dSmrg/** 455af69d88dSmrg * Draw the HUD to the texture \p tex. 456af69d88dSmrg * The texture is usually the back buffer being displayed. 457af69d88dSmrg */ 45801e04c3fSmrgstatic void 45901e04c3fSmrghud_draw_results(struct hud_context *hud, struct pipe_resource *tex) 460af69d88dSmrg{ 461af69d88dSmrg struct cso_context *cso = hud->cso; 462af69d88dSmrg struct pipe_context *pipe = hud->pipe; 463af69d88dSmrg struct pipe_framebuffer_state fb; 464af69d88dSmrg struct pipe_surface surf_templ, *surf; 465af69d88dSmrg struct pipe_viewport_state viewport; 466af69d88dSmrg const struct pipe_sampler_state *sampler_states[] = 467af69d88dSmrg { &hud->font_sampler_state }; 468af69d88dSmrg struct hud_pane *pane; 46901e04c3fSmrg 47001e04c3fSmrg if (!huds_visible) 47101e04c3fSmrg return; 472af69d88dSmrg 473af69d88dSmrg hud->fb_width = tex->width0; 474af69d88dSmrg hud->fb_height = tex->height0; 475af69d88dSmrg hud->constants.two_div_fb_width = 2.0f / hud->fb_width; 476af69d88dSmrg hud->constants.two_div_fb_height = 2.0f / hud->fb_height; 477af69d88dSmrg 47801e04c3fSmrg cso_save_state(cso, (CSO_BIT_FRAMEBUFFER | 47901e04c3fSmrg CSO_BIT_SAMPLE_MASK | 48001e04c3fSmrg CSO_BIT_MIN_SAMPLES | 48101e04c3fSmrg CSO_BIT_BLEND | 48201e04c3fSmrg CSO_BIT_DEPTH_STENCIL_ALPHA | 48301e04c3fSmrg CSO_BIT_FRAGMENT_SHADER | 48401e04c3fSmrg CSO_BIT_FRAGMENT_SAMPLERS | 48501e04c3fSmrg CSO_BIT_RASTERIZER | 48601e04c3fSmrg CSO_BIT_VIEWPORT | 48701e04c3fSmrg CSO_BIT_STREAM_OUTPUTS | 48801e04c3fSmrg CSO_BIT_GEOMETRY_SHADER | 48901e04c3fSmrg CSO_BIT_TESSCTRL_SHADER | 49001e04c3fSmrg CSO_BIT_TESSEVAL_SHADER | 49101e04c3fSmrg CSO_BIT_VERTEX_SHADER | 49201e04c3fSmrg CSO_BIT_VERTEX_ELEMENTS | 49301e04c3fSmrg CSO_BIT_PAUSE_QUERIES | 49401e04c3fSmrg CSO_BIT_RENDER_CONDITION)); 495af69d88dSmrg 496af69d88dSmrg /* set states */ 497af69d88dSmrg memset(&surf_templ, 0, sizeof(surf_templ)); 498af69d88dSmrg surf_templ.format = tex->format; 49901e04c3fSmrg 50001e04c3fSmrg /* Without this, AA lines look thinner if they are between 2 pixels 50101e04c3fSmrg * because the alpha is 0.5 on both pixels. (it's ugly) 50201e04c3fSmrg * 50301e04c3fSmrg * sRGB makes the width of all AA lines look the same. 50401e04c3fSmrg */ 50501e04c3fSmrg if (hud->has_srgb) { 50601e04c3fSmrg enum pipe_format srgb_format = util_format_srgb(tex->format); 50701e04c3fSmrg 50801e04c3fSmrg if (srgb_format != PIPE_FORMAT_NONE) 50901e04c3fSmrg surf_templ.format = srgb_format; 51001e04c3fSmrg } 511af69d88dSmrg surf = pipe->create_surface(pipe, tex, &surf_templ); 512af69d88dSmrg 513af69d88dSmrg memset(&fb, 0, sizeof(fb)); 514af69d88dSmrg fb.nr_cbufs = 1; 515af69d88dSmrg fb.cbufs[0] = surf; 516af69d88dSmrg fb.zsbuf = NULL; 517af69d88dSmrg fb.width = hud->fb_width; 518af69d88dSmrg fb.height = hud->fb_height; 519af69d88dSmrg 520af69d88dSmrg viewport.scale[0] = 0.5f * hud->fb_width; 521af69d88dSmrg viewport.scale[1] = 0.5f * hud->fb_height; 5227ec681f3Smrg viewport.scale[2] = 0.0f; 523af69d88dSmrg viewport.translate[0] = 0.5f * hud->fb_width; 524af69d88dSmrg viewport.translate[1] = 0.5f * hud->fb_height; 525af69d88dSmrg viewport.translate[2] = 0.0f; 5267ec681f3Smrg viewport.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X; 5277ec681f3Smrg viewport.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y; 5287ec681f3Smrg viewport.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z; 5297ec681f3Smrg viewport.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W; 530af69d88dSmrg 531af69d88dSmrg cso_set_framebuffer(cso, &fb); 532af69d88dSmrg cso_set_sample_mask(cso, ~0); 533af69d88dSmrg cso_set_min_samples(cso, 1); 534af69d88dSmrg cso_set_depth_stencil_alpha(cso, &hud->dsa); 535af69d88dSmrg cso_set_rasterizer(cso, &hud->rasterizer); 536af69d88dSmrg cso_set_viewport(cso, &viewport); 537af69d88dSmrg cso_set_stream_outputs(cso, 0, NULL, NULL); 53801e04c3fSmrg cso_set_tessctrl_shader_handle(cso, NULL); 53901e04c3fSmrg cso_set_tesseval_shader_handle(cso, NULL); 540af69d88dSmrg cso_set_geometry_shader_handle(cso, NULL); 5417ec681f3Smrg cso_set_vertex_shader_handle(cso, hud->vs_color); 5427ec681f3Smrg cso_set_vertex_elements(cso, &hud->velems); 543af69d88dSmrg cso_set_render_condition(cso, NULL, FALSE, 0); 5447ec681f3Smrg pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, 0, false, 5457ec681f3Smrg &hud->font_sampler_view); 546af69d88dSmrg cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, sampler_states); 5477ec681f3Smrg pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf); 548af69d88dSmrg 549af69d88dSmrg /* draw accumulated vertices for background quads */ 55001e04c3fSmrg cso_set_blend(cso, &hud->alpha_blend); 551af69d88dSmrg cso_set_fragment_shader_handle(hud->cso, hud->fs_color); 552af69d88dSmrg 553af69d88dSmrg if (hud->bg.num_vertices) { 554af69d88dSmrg hud->constants.color[0] = 0; 555af69d88dSmrg hud->constants.color[1] = 0; 556af69d88dSmrg hud->constants.color[2] = 0; 557af69d88dSmrg hud->constants.color[3] = 0.666f; 558af69d88dSmrg hud->constants.translate[0] = 0; 559af69d88dSmrg hud->constants.translate[1] = 0; 5607ec681f3Smrg hud->constants.scale[0] = hud_scale; 5617ec681f3Smrg hud->constants.scale[1] = hud_scale; 5627ec681f3Smrg 5637ec681f3Smrg pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf); 564af69d88dSmrg 56501e04c3fSmrg cso_set_vertex_buffers(cso, 0, 1, &hud->bg.vbuf); 566af69d88dSmrg cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices); 567af69d88dSmrg } 56801e04c3fSmrg pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL); 56901e04c3fSmrg 57001e04c3fSmrg /* draw accumulated vertices for text */ 57101e04c3fSmrg if (hud->text.num_vertices) { 5727ec681f3Smrg cso_set_vertex_shader_handle(cso, hud->vs_text); 57301e04c3fSmrg cso_set_vertex_buffers(cso, 0, 1, &hud->text.vbuf); 57401e04c3fSmrg cso_set_fragment_shader_handle(hud->cso, hud->fs_text); 57501e04c3fSmrg cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices); 57601e04c3fSmrg } 57701e04c3fSmrg pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL); 57801e04c3fSmrg 5797ec681f3Smrg if (hud->simple) 5807ec681f3Smrg goto done; 581af69d88dSmrg 582af69d88dSmrg /* draw accumulated vertices for white lines */ 58301e04c3fSmrg cso_set_blend(cso, &hud->no_blend); 58401e04c3fSmrg 585af69d88dSmrg hud->constants.color[0] = 1; 586af69d88dSmrg hud->constants.color[1] = 1; 587af69d88dSmrg hud->constants.color[2] = 1; 588af69d88dSmrg hud->constants.color[3] = 1; 589af69d88dSmrg hud->constants.translate[0] = 0; 590af69d88dSmrg hud->constants.translate[1] = 0; 5917ec681f3Smrg hud->constants.scale[0] = hud_scale; 5927ec681f3Smrg hud->constants.scale[1] = hud_scale; 5937ec681f3Smrg pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, false, &hud->constbuf); 594af69d88dSmrg 595af69d88dSmrg if (hud->whitelines.num_vertices) { 5967ec681f3Smrg cso_set_vertex_shader_handle(cso, hud->vs_color); 59701e04c3fSmrg cso_set_vertex_buffers(cso, 0, 1, &hud->whitelines.vbuf); 598af69d88dSmrg cso_set_fragment_shader_handle(hud->cso, hud->fs_color); 599af69d88dSmrg cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices); 600af69d88dSmrg } 60101e04c3fSmrg pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL); 602af69d88dSmrg 603af69d88dSmrg /* draw the rest */ 60401e04c3fSmrg cso_set_blend(cso, &hud->alpha_blend); 60501e04c3fSmrg cso_set_rasterizer(cso, &hud->rasterizer_aa_lines); 606af69d88dSmrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 607af69d88dSmrg if (pane) 608af69d88dSmrg hud_pane_draw_colored_objects(hud, pane); 609af69d88dSmrg } 610af69d88dSmrg 6117ec681f3Smrgdone: 6127ec681f3Smrg cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEW0 | CSO_UNBIND_VS_CONSTANTS | CSO_UNBIND_VERTEX_BUFFER0); 6137ec681f3Smrg 6147ec681f3Smrg /* restore states not restored by cso */ 6157ec681f3Smrg if (hud->st) { 6167ec681f3Smrg hud->st->invalidate_state(hud->st, 6177ec681f3Smrg ST_INVALIDATE_FS_SAMPLER_VIEWS | 6187ec681f3Smrg ST_INVALIDATE_VS_CONSTBUF0 | 6197ec681f3Smrg ST_INVALIDATE_VERTEX_BUFFERS); 6207ec681f3Smrg } 621af69d88dSmrg 622af69d88dSmrg pipe_surface_reference(&surf, NULL); 623af69d88dSmrg} 624af69d88dSmrg 62501e04c3fSmrgstatic void 62601e04c3fSmrghud_start_queries(struct hud_context *hud, struct pipe_context *pipe) 62701e04c3fSmrg{ 62801e04c3fSmrg struct hud_pane *pane; 62901e04c3fSmrg struct hud_graph *gr; 63001e04c3fSmrg 63101e04c3fSmrg /* Start queries. */ 63201e04c3fSmrg hud_batch_query_begin(hud->batch_query, pipe); 63301e04c3fSmrg 63401e04c3fSmrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 63501e04c3fSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 63601e04c3fSmrg if (gr->begin_query) 63701e04c3fSmrg gr->begin_query(gr, pipe); 63801e04c3fSmrg } 63901e04c3fSmrg } 64001e04c3fSmrg} 64101e04c3fSmrg 64201e04c3fSmrg/* Stop queries, query results, and record vertices for charts. */ 64301e04c3fSmrgstatic void 64401e04c3fSmrghud_stop_queries(struct hud_context *hud, struct pipe_context *pipe) 64501e04c3fSmrg{ 64601e04c3fSmrg struct hud_pane *pane; 64701e04c3fSmrg struct hud_graph *gr, *next; 64801e04c3fSmrg 64901e04c3fSmrg /* prepare vertex buffers */ 65001e04c3fSmrg hud_prepare_vertices(hud, &hud->bg, 16 * 256, 2 * sizeof(float)); 65101e04c3fSmrg hud_prepare_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float)); 65201e04c3fSmrg hud_prepare_vertices(hud, &hud->text, 16 * 1024, 4 * sizeof(float)); 65301e04c3fSmrg 65401e04c3fSmrg /* Allocate everything once and divide the storage into 3 portions 65501e04c3fSmrg * manually, because u_upload_alloc can unmap memory from previous calls. 65601e04c3fSmrg */ 65701e04c3fSmrg u_upload_alloc(pipe->stream_uploader, 0, 65801e04c3fSmrg hud->bg.buffer_size + 65901e04c3fSmrg hud->whitelines.buffer_size + 6607ec681f3Smrg hud->text.buffer_size, 66101e04c3fSmrg 16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer.resource, 66201e04c3fSmrg (void**)&hud->bg.vertices); 66301e04c3fSmrg if (!hud->bg.vertices) 66401e04c3fSmrg return; 66501e04c3fSmrg 66601e04c3fSmrg pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); 66701e04c3fSmrg pipe_resource_reference(&hud->text.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource); 66801e04c3fSmrg 66901e04c3fSmrg hud->whitelines.vbuf.buffer_offset = hud->bg.vbuf.buffer_offset + 67001e04c3fSmrg hud->bg.buffer_size; 67101e04c3fSmrg hud->whitelines.vertices = hud->bg.vertices + 67201e04c3fSmrg hud->bg.buffer_size / sizeof(float); 67301e04c3fSmrg 67401e04c3fSmrg hud->text.vbuf.buffer_offset = hud->whitelines.vbuf.buffer_offset + 67501e04c3fSmrg hud->whitelines.buffer_size; 67601e04c3fSmrg hud->text.vertices = hud->whitelines.vertices + 67701e04c3fSmrg hud->whitelines.buffer_size / sizeof(float); 67801e04c3fSmrg 67901e04c3fSmrg /* prepare all graphs */ 68001e04c3fSmrg hud_batch_query_update(hud->batch_query, pipe); 68101e04c3fSmrg 68201e04c3fSmrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 68301e04c3fSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 68401e04c3fSmrg gr->query_new_value(gr, pipe); 68501e04c3fSmrg } 68601e04c3fSmrg 68701e04c3fSmrg if (pane->sort_items) { 68801e04c3fSmrg LIST_FOR_EACH_ENTRY_SAFE(gr, next, &pane->graph_list, head) { 68901e04c3fSmrg /* ignore the last one */ 69001e04c3fSmrg if (&gr->head == pane->graph_list.prev) 69101e04c3fSmrg continue; 69201e04c3fSmrg 69301e04c3fSmrg /* This is an incremental bubble sort, because we only do one pass 69401e04c3fSmrg * per frame. It will eventually reach an equilibrium. 69501e04c3fSmrg */ 69601e04c3fSmrg if (gr->current_value < 69701e04c3fSmrg LIST_ENTRY(struct hud_graph, next, head)->current_value) { 6987ec681f3Smrg list_del(&gr->head); 6997ec681f3Smrg list_add(&gr->head, &next->head); 70001e04c3fSmrg } 70101e04c3fSmrg } 70201e04c3fSmrg } 70301e04c3fSmrg 70401e04c3fSmrg if (hud->simple) 70501e04c3fSmrg hud_pane_accumulate_vertices_simple(hud, pane); 70601e04c3fSmrg else 70701e04c3fSmrg hud_pane_accumulate_vertices(hud, pane); 70801e04c3fSmrg } 70901e04c3fSmrg 71001e04c3fSmrg /* unmap the uploader's vertex buffer before drawing */ 71101e04c3fSmrg u_upload_unmap(pipe->stream_uploader); 71201e04c3fSmrg} 71301e04c3fSmrg 71401e04c3fSmrg/** 71501e04c3fSmrg * Record queries and draw the HUD. The "cso" parameter acts as a filter. 71601e04c3fSmrg * If "cso" is not the recording context, recording is skipped. 71701e04c3fSmrg * If "cso" is not the drawing context, drawing is skipped. 71801e04c3fSmrg * cso == NULL ignores the filter. 71901e04c3fSmrg */ 72001e04c3fSmrgvoid 72101e04c3fSmrghud_run(struct hud_context *hud, struct cso_context *cso, 72201e04c3fSmrg struct pipe_resource *tex) 72301e04c3fSmrg{ 72401e04c3fSmrg struct pipe_context *pipe = cso ? cso_get_pipe_context(cso) : NULL; 72501e04c3fSmrg 72601e04c3fSmrg /* If "cso" is the recording or drawing context or NULL, execute 72701e04c3fSmrg * the operation. Otherwise, don't do anything. 72801e04c3fSmrg */ 72901e04c3fSmrg if (hud->record_pipe && (!pipe || pipe == hud->record_pipe)) 73001e04c3fSmrg hud_stop_queries(hud, hud->record_pipe); 73101e04c3fSmrg 73201e04c3fSmrg if (hud->cso && (!cso || cso == hud->cso)) 73301e04c3fSmrg hud_draw_results(hud, tex); 73401e04c3fSmrg 73501e04c3fSmrg if (hud->record_pipe && (!pipe || pipe == hud->record_pipe)) 73601e04c3fSmrg hud_start_queries(hud, hud->record_pipe); 73701e04c3fSmrg} 73801e04c3fSmrg 73901e04c3fSmrg/** 74001e04c3fSmrg * Record query results and assemble vertices if "pipe" is a recording but 74101e04c3fSmrg * not drawing context. 74201e04c3fSmrg */ 74301e04c3fSmrgvoid 74401e04c3fSmrghud_record_only(struct hud_context *hud, struct pipe_context *pipe) 74501e04c3fSmrg{ 74601e04c3fSmrg assert(pipe); 74701e04c3fSmrg 74801e04c3fSmrg /* If it's a drawing context, only hud_run() records query results. */ 74901e04c3fSmrg if (pipe == hud->pipe || pipe != hud->record_pipe) 75001e04c3fSmrg return; 75101e04c3fSmrg 75201e04c3fSmrg hud_stop_queries(hud, hud->record_pipe); 75301e04c3fSmrg hud_start_queries(hud, hud->record_pipe); 75401e04c3fSmrg} 75501e04c3fSmrg 75601e04c3fSmrgstatic void 75701e04c3fSmrgfixup_bytes(enum pipe_driver_query_type type, int position, uint64_t *exp10) 75801e04c3fSmrg{ 75901e04c3fSmrg if (type == PIPE_DRIVER_QUERY_TYPE_BYTES && position % 3 == 0) 76001e04c3fSmrg *exp10 = (*exp10 / 1000) * 1024; 76101e04c3fSmrg} 76201e04c3fSmrg 763af69d88dSmrg/** 764af69d88dSmrg * Set the maximum value for the Y axis of the graph. 765af69d88dSmrg * This scales the graph accordingly. 766af69d88dSmrg */ 767af69d88dSmrgvoid 768af69d88dSmrghud_pane_set_max_value(struct hud_pane *pane, uint64_t value) 769af69d88dSmrg{ 77001e04c3fSmrg double leftmost_digit; 77101e04c3fSmrg uint64_t exp10; 77201e04c3fSmrg int i; 77301e04c3fSmrg 77401e04c3fSmrg /* The following code determines the max_value in the graph as well as 77501e04c3fSmrg * how many describing lines are drawn. The max_value is rounded up, 77601e04c3fSmrg * so that all drawn numbers are rounded for readability. 77701e04c3fSmrg * We want to print multiples of a simple number instead of multiples of 77801e04c3fSmrg * hard-to-read numbers like 1.753. 77901e04c3fSmrg */ 78001e04c3fSmrg 78101e04c3fSmrg /* Find the left-most digit. Make sure exp10 * 10 and fixup_bytes doesn't 78201e04c3fSmrg * overflow. (11 is safe) */ 78301e04c3fSmrg exp10 = 1; 78401e04c3fSmrg for (i = 0; exp10 <= UINT64_MAX / 11 && exp10 * 9 < value; i++) { 78501e04c3fSmrg exp10 *= 10; 78601e04c3fSmrg fixup_bytes(pane->type, i + 1, &exp10); 78701e04c3fSmrg } 78801e04c3fSmrg 78901e04c3fSmrg leftmost_digit = DIV_ROUND_UP(value, exp10); 79001e04c3fSmrg 79101e04c3fSmrg /* Round 9 to 10. */ 79201e04c3fSmrg if (leftmost_digit == 9) { 79301e04c3fSmrg leftmost_digit = 1; 79401e04c3fSmrg exp10 *= 10; 79501e04c3fSmrg fixup_bytes(pane->type, i + 1, &exp10); 79601e04c3fSmrg } 79701e04c3fSmrg 79801e04c3fSmrg switch ((unsigned)leftmost_digit) { 79901e04c3fSmrg case 1: 80001e04c3fSmrg pane->last_line = 5; /* lines in +1/5 increments */ 80101e04c3fSmrg break; 80201e04c3fSmrg case 2: 80301e04c3fSmrg pane->last_line = 8; /* lines in +1/4 increments. */ 80401e04c3fSmrg break; 80501e04c3fSmrg case 3: 80601e04c3fSmrg case 4: 80701e04c3fSmrg pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments */ 80801e04c3fSmrg break; 80901e04c3fSmrg case 5: 81001e04c3fSmrg case 6: 81101e04c3fSmrg case 7: 81201e04c3fSmrg case 8: 81301e04c3fSmrg pane->last_line = leftmost_digit; /* lines in +1 increments */ 81401e04c3fSmrg break; 81501e04c3fSmrg default: 81601e04c3fSmrg assert(0); 81701e04c3fSmrg } 81801e04c3fSmrg 81901e04c3fSmrg /* Truncate {3,4} to {2.5, 3.5} if possible. */ 82001e04c3fSmrg for (i = 3; i <= 4; i++) { 82101e04c3fSmrg if (leftmost_digit == i && value <= (i - 0.5) * exp10) { 82201e04c3fSmrg leftmost_digit = i - 0.5; 82301e04c3fSmrg pane->last_line = leftmost_digit * 2; /* lines in +1/2 increments. */ 82401e04c3fSmrg } 82501e04c3fSmrg } 82601e04c3fSmrg 82701e04c3fSmrg /* Truncate 2 to a multiple of 0.2 in (1, 1.6] if possible. */ 82801e04c3fSmrg if (leftmost_digit == 2) { 82901e04c3fSmrg for (i = 1; i <= 3; i++) { 83001e04c3fSmrg if (value <= (1 + i*0.2) * exp10) { 83101e04c3fSmrg leftmost_digit = 1 + i*0.2; 83201e04c3fSmrg pane->last_line = 5 + i; /* lines in +1/5 increments. */ 83301e04c3fSmrg break; 83401e04c3fSmrg } 83501e04c3fSmrg } 83601e04c3fSmrg } 83701e04c3fSmrg 83801e04c3fSmrg pane->max_value = leftmost_digit * exp10; 839af69d88dSmrg pane->yscale = -(int)pane->inner_height / (float)pane->max_value; 840af69d88dSmrg} 841af69d88dSmrg 84201e04c3fSmrgstatic void 84301e04c3fSmrghud_pane_update_dyn_ceiling(struct hud_graph *gr, struct hud_pane *pane) 84401e04c3fSmrg{ 84501e04c3fSmrg unsigned i; 84601e04c3fSmrg float tmp = 0.0f; 84701e04c3fSmrg 84801e04c3fSmrg if (pane->dyn_ceil_last_ran != gr->index) { 84901e04c3fSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 85001e04c3fSmrg for (i = 0; i < gr->num_vertices; ++i) { 85101e04c3fSmrg tmp = gr->vertices[i * 2 + 1] > tmp ? 85201e04c3fSmrg gr->vertices[i * 2 + 1] : tmp; 85301e04c3fSmrg } 85401e04c3fSmrg } 85501e04c3fSmrg 85601e04c3fSmrg /* Avoid setting it lower than the initial starting height. */ 85701e04c3fSmrg tmp = tmp > pane->initial_max_value ? tmp : pane->initial_max_value; 85801e04c3fSmrg hud_pane_set_max_value(pane, tmp); 85901e04c3fSmrg } 86001e04c3fSmrg 86101e04c3fSmrg /* 86201e04c3fSmrg * Mark this adjustment run so we could avoid repeating a full update 86301e04c3fSmrg * again needlessly in case the pane has more than one graph. 86401e04c3fSmrg */ 86501e04c3fSmrg pane->dyn_ceil_last_ran = gr->index; 86601e04c3fSmrg} 86701e04c3fSmrg 868af69d88dSmrgstatic struct hud_pane * 86901e04c3fSmrghud_pane_create(struct hud_context *hud, 87001e04c3fSmrg unsigned x1, unsigned y1, unsigned x2, unsigned y2, 87101e04c3fSmrg unsigned y_simple, 87201e04c3fSmrg unsigned period, uint64_t max_value, uint64_t ceiling, 87301e04c3fSmrg boolean dyn_ceiling, boolean sort_items) 874af69d88dSmrg{ 875af69d88dSmrg struct hud_pane *pane = CALLOC_STRUCT(hud_pane); 876af69d88dSmrg 877af69d88dSmrg if (!pane) 878af69d88dSmrg return NULL; 879af69d88dSmrg 88001e04c3fSmrg pane->hud = hud; 881af69d88dSmrg pane->x1 = x1; 882af69d88dSmrg pane->y1 = y1; 883af69d88dSmrg pane->x2 = x2; 884af69d88dSmrg pane->y2 = y2; 88501e04c3fSmrg pane->y_simple = y_simple; 886af69d88dSmrg pane->inner_x1 = x1 + 1; 887af69d88dSmrg pane->inner_x2 = x2 - 1; 888af69d88dSmrg pane->inner_y1 = y1 + 1; 889af69d88dSmrg pane->inner_y2 = y2 - 1; 890af69d88dSmrg pane->inner_width = pane->inner_x2 - pane->inner_x1; 891af69d88dSmrg pane->inner_height = pane->inner_y2 - pane->inner_y1; 892af69d88dSmrg pane->period = period; 893af69d88dSmrg pane->max_num_vertices = (x2 - x1 + 2) / 2; 89401e04c3fSmrg pane->ceiling = ceiling; 89501e04c3fSmrg pane->dyn_ceiling = dyn_ceiling; 89601e04c3fSmrg pane->dyn_ceil_last_ran = 0; 89701e04c3fSmrg pane->sort_items = sort_items; 89801e04c3fSmrg pane->initial_max_value = max_value; 899af69d88dSmrg hud_pane_set_max_value(pane, max_value); 9007ec681f3Smrg list_inithead(&pane->graph_list); 901af69d88dSmrg return pane; 902af69d88dSmrg} 903af69d88dSmrg 90401e04c3fSmrg/* replace '-' with a space */ 90501e04c3fSmrgstatic void 90601e04c3fSmrgstrip_hyphens(char *s) 90701e04c3fSmrg{ 90801e04c3fSmrg while (*s) { 90901e04c3fSmrg if (*s == '-') 91001e04c3fSmrg *s = ' '; 91101e04c3fSmrg s++; 91201e04c3fSmrg } 91301e04c3fSmrg} 91401e04c3fSmrg 915af69d88dSmrg/** 916af69d88dSmrg * Add a graph to an existing pane. 917af69d88dSmrg * One pane can contain multiple graphs over each other. 918af69d88dSmrg */ 919af69d88dSmrgvoid 920af69d88dSmrghud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr) 921af69d88dSmrg{ 922af69d88dSmrg static const float colors[][3] = { 923af69d88dSmrg {0, 1, 0}, 924af69d88dSmrg {1, 0, 0}, 925af69d88dSmrg {0, 1, 1}, 926af69d88dSmrg {1, 0, 1}, 927af69d88dSmrg {1, 1, 0}, 92801e04c3fSmrg {0.5, 1, 0.5}, 92901e04c3fSmrg {1, 0.5, 0.5}, 93001e04c3fSmrg {0.5, 1, 1}, 93101e04c3fSmrg {1, 0.5, 1}, 93201e04c3fSmrg {1, 1, 0.5}, 93301e04c3fSmrg {0, 0.5, 0}, 93401e04c3fSmrg {0.5, 0, 0}, 93501e04c3fSmrg {0, 0.5, 0.5}, 93601e04c3fSmrg {0.5, 0, 0.5}, 93701e04c3fSmrg {0.5, 0.5, 0}, 938af69d88dSmrg }; 93901e04c3fSmrg unsigned color = pane->next_color % ARRAY_SIZE(colors); 940af69d88dSmrg 94101e04c3fSmrg strip_hyphens(gr->name); 942af69d88dSmrg 943af69d88dSmrg gr->vertices = MALLOC(pane->max_num_vertices * sizeof(float) * 2); 94401e04c3fSmrg gr->color[0] = colors[color][0]; 94501e04c3fSmrg gr->color[1] = colors[color][1]; 94601e04c3fSmrg gr->color[2] = colors[color][2]; 947af69d88dSmrg gr->pane = pane; 9487ec681f3Smrg list_addtail(&gr->head, &pane->graph_list); 949af69d88dSmrg pane->num_graphs++; 95001e04c3fSmrg pane->next_color++; 951af69d88dSmrg} 952af69d88dSmrg 953af69d88dSmrgvoid 95401e04c3fSmrghud_graph_add_value(struct hud_graph *gr, double value) 955af69d88dSmrg{ 95601e04c3fSmrg gr->current_value = value; 95701e04c3fSmrg value = value > gr->pane->ceiling ? gr->pane->ceiling : value; 95801e04c3fSmrg 95901e04c3fSmrg if (gr->fd) { 96001e04c3fSmrg if (fabs(value - lround(value)) > FLT_EPSILON) { 96101e04c3fSmrg fprintf(gr->fd, "%f\n", value); 96201e04c3fSmrg } 96301e04c3fSmrg else { 96401e04c3fSmrg fprintf(gr->fd, "%" PRIu64 "\n", (uint64_t) lround(value)); 96501e04c3fSmrg } 96601e04c3fSmrg } 96701e04c3fSmrg 968af69d88dSmrg if (gr->index == gr->pane->max_num_vertices) { 969af69d88dSmrg gr->vertices[0] = 0; 970af69d88dSmrg gr->vertices[1] = gr->vertices[(gr->index-1)*2+1]; 971af69d88dSmrg gr->index = 1; 972af69d88dSmrg } 973af69d88dSmrg gr->vertices[(gr->index)*2+0] = (float) (gr->index * 2); 974af69d88dSmrg gr->vertices[(gr->index)*2+1] = (float) value; 975af69d88dSmrg gr->index++; 976af69d88dSmrg 977af69d88dSmrg if (gr->num_vertices < gr->pane->max_num_vertices) { 978af69d88dSmrg gr->num_vertices++; 979af69d88dSmrg } 980af69d88dSmrg 98101e04c3fSmrg if (gr->pane->dyn_ceiling == true) { 98201e04c3fSmrg hud_pane_update_dyn_ceiling(gr, gr->pane); 98301e04c3fSmrg } 984af69d88dSmrg if (value > gr->pane->max_value) { 985af69d88dSmrg hud_pane_set_max_value(gr->pane, value); 986af69d88dSmrg } 987af69d88dSmrg} 988af69d88dSmrg 989af69d88dSmrgstatic void 99001e04c3fSmrghud_graph_destroy(struct hud_graph *graph, struct pipe_context *pipe) 991af69d88dSmrg{ 992af69d88dSmrg FREE(graph->vertices); 993af69d88dSmrg if (graph->free_query_data) 99401e04c3fSmrg graph->free_query_data(graph->query_data, pipe); 99501e04c3fSmrg if (graph->fd) 99601e04c3fSmrg fclose(graph->fd); 997af69d88dSmrg FREE(graph); 998af69d88dSmrg} 999af69d88dSmrg 100001e04c3fSmrgstatic void strcat_without_spaces(char *dst, const char *src) 100101e04c3fSmrg{ 100201e04c3fSmrg dst += strlen(dst); 100301e04c3fSmrg while (*src) { 100401e04c3fSmrg if (*src == ' ') 100501e04c3fSmrg *dst++ = '_'; 100601e04c3fSmrg else 100701e04c3fSmrg *dst++ = *src; 100801e04c3fSmrg src++; 100901e04c3fSmrg } 101001e04c3fSmrg *dst = 0; 101101e04c3fSmrg} 101201e04c3fSmrg 101301e04c3fSmrg 101401e04c3fSmrg#ifdef PIPE_OS_WINDOWS 101501e04c3fSmrg#define W_OK 0 101601e04c3fSmrgstatic int 101701e04c3fSmrgaccess(const char *pathname, int mode) 101801e04c3fSmrg{ 101901e04c3fSmrg /* no-op */ 102001e04c3fSmrg return 0; 102101e04c3fSmrg} 102201e04c3fSmrg 102301e04c3fSmrg#define PATH_SEP "\\" 102401e04c3fSmrg 102501e04c3fSmrg#else 102601e04c3fSmrg 102701e04c3fSmrg#define PATH_SEP "/" 102801e04c3fSmrg 102901e04c3fSmrg#endif 103001e04c3fSmrg 103101e04c3fSmrg 103201e04c3fSmrg/** 103301e04c3fSmrg * If the GALLIUM_HUD_DUMP_DIR env var is set, we'll write the raw 103401e04c3fSmrg * HUD values to files at ${GALLIUM_HUD_DUMP_DIR}/<stat> where <stat> 103501e04c3fSmrg * is a HUD variable such as "fps", or "cpu" 103601e04c3fSmrg */ 103701e04c3fSmrgstatic void 103801e04c3fSmrghud_graph_set_dump_file(struct hud_graph *gr) 103901e04c3fSmrg{ 104001e04c3fSmrg const char *hud_dump_dir = getenv("GALLIUM_HUD_DUMP_DIR"); 104101e04c3fSmrg 104201e04c3fSmrg if (hud_dump_dir && access(hud_dump_dir, W_OK) == 0) { 104301e04c3fSmrg char *dump_file = malloc(strlen(hud_dump_dir) + sizeof(PATH_SEP) 104401e04c3fSmrg + sizeof(gr->name)); 104501e04c3fSmrg if (dump_file) { 104601e04c3fSmrg strcpy(dump_file, hud_dump_dir); 104701e04c3fSmrg strcat(dump_file, PATH_SEP); 104801e04c3fSmrg strcat_without_spaces(dump_file, gr->name); 104901e04c3fSmrg gr->fd = fopen(dump_file, "w+"); 105001e04c3fSmrg if (gr->fd) { 105101e04c3fSmrg /* flush output after each line is written */ 105201e04c3fSmrg setvbuf(gr->fd, NULL, _IOLBF, 0); 105301e04c3fSmrg } 105401e04c3fSmrg free(dump_file); 105501e04c3fSmrg } 105601e04c3fSmrg } 105701e04c3fSmrg} 105801e04c3fSmrg 1059af69d88dSmrg/** 1060af69d88dSmrg * Read a string from the environment variable. 1061af69d88dSmrg * The separators "+", ",", ":", and ";" terminate the string. 1062af69d88dSmrg * Return the number of read characters. 1063af69d88dSmrg */ 1064af69d88dSmrgstatic int 1065af69d88dSmrgparse_string(const char *s, char *out) 1066af69d88dSmrg{ 1067af69d88dSmrg int i; 1068af69d88dSmrg 106901e04c3fSmrg for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';' && *s != '='; 1070af69d88dSmrg s++, out++, i++) 1071af69d88dSmrg *out = *s; 1072af69d88dSmrg 1073af69d88dSmrg *out = 0; 1074af69d88dSmrg 107501e04c3fSmrg if (*s && !i) { 1076af69d88dSmrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) while " 1077af69d88dSmrg "parsing a string\n", *s, *s); 107801e04c3fSmrg fflush(stderr); 107901e04c3fSmrg } 108001e04c3fSmrg 1081af69d88dSmrg return i; 1082af69d88dSmrg} 1083af69d88dSmrg 108401e04c3fSmrgstatic char * 108501e04c3fSmrgread_pane_settings(char *str, unsigned * const x, unsigned * const y, 108601e04c3fSmrg unsigned * const width, unsigned * const height, 108701e04c3fSmrg uint64_t * const ceiling, boolean * const dyn_ceiling, 108801e04c3fSmrg boolean *reset_colors, boolean *sort_items) 108901e04c3fSmrg{ 109001e04c3fSmrg char *ret = str; 109101e04c3fSmrg unsigned tmp; 109201e04c3fSmrg 109301e04c3fSmrg while (*str == '.') { 109401e04c3fSmrg ++str; 109501e04c3fSmrg switch (*str) { 109601e04c3fSmrg case 'x': 109701e04c3fSmrg ++str; 109801e04c3fSmrg *x = strtoul(str, &ret, 10); 109901e04c3fSmrg str = ret; 110001e04c3fSmrg break; 110101e04c3fSmrg 110201e04c3fSmrg case 'y': 110301e04c3fSmrg ++str; 110401e04c3fSmrg *y = strtoul(str, &ret, 10); 110501e04c3fSmrg str = ret; 110601e04c3fSmrg break; 110701e04c3fSmrg 110801e04c3fSmrg case 'w': 110901e04c3fSmrg ++str; 111001e04c3fSmrg tmp = strtoul(str, &ret, 10); 111101e04c3fSmrg *width = tmp > 80 ? tmp : 80; /* 80 is chosen arbitrarily */ 111201e04c3fSmrg str = ret; 111301e04c3fSmrg break; 111401e04c3fSmrg 111501e04c3fSmrg /* 111601e04c3fSmrg * Prevent setting height to less than 50. If the height is set to less, 111701e04c3fSmrg * the text of the Y axis labels on the graph will start overlapping. 111801e04c3fSmrg */ 111901e04c3fSmrg case 'h': 112001e04c3fSmrg ++str; 112101e04c3fSmrg tmp = strtoul(str, &ret, 10); 112201e04c3fSmrg *height = tmp > 50 ? tmp : 50; 112301e04c3fSmrg str = ret; 112401e04c3fSmrg break; 112501e04c3fSmrg 112601e04c3fSmrg case 'c': 112701e04c3fSmrg ++str; 112801e04c3fSmrg tmp = strtoul(str, &ret, 10); 112901e04c3fSmrg *ceiling = tmp > 10 ? tmp : 10; 113001e04c3fSmrg str = ret; 113101e04c3fSmrg break; 113201e04c3fSmrg 113301e04c3fSmrg case 'd': 113401e04c3fSmrg ++str; 113501e04c3fSmrg ret = str; 113601e04c3fSmrg *dyn_ceiling = true; 113701e04c3fSmrg break; 113801e04c3fSmrg 113901e04c3fSmrg case 'r': 114001e04c3fSmrg ++str; 114101e04c3fSmrg ret = str; 114201e04c3fSmrg *reset_colors = true; 114301e04c3fSmrg break; 114401e04c3fSmrg 114501e04c3fSmrg case 's': 114601e04c3fSmrg ++str; 114701e04c3fSmrg ret = str; 114801e04c3fSmrg *sort_items = true; 114901e04c3fSmrg break; 115001e04c3fSmrg 115101e04c3fSmrg default: 115201e04c3fSmrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *str); 115301e04c3fSmrg fflush(stderr); 115401e04c3fSmrg } 115501e04c3fSmrg 115601e04c3fSmrg } 115701e04c3fSmrg 115801e04c3fSmrg return ret; 115901e04c3fSmrg} 116001e04c3fSmrg 1161af69d88dSmrgstatic boolean 1162af69d88dSmrghas_occlusion_query(struct pipe_screen *screen) 1163af69d88dSmrg{ 1164af69d88dSmrg return screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY) != 0; 1165af69d88dSmrg} 1166af69d88dSmrg 1167af69d88dSmrgstatic boolean 1168af69d88dSmrghas_streamout(struct pipe_screen *screen) 1169af69d88dSmrg{ 1170af69d88dSmrg return screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0; 1171af69d88dSmrg} 1172af69d88dSmrg 1173af69d88dSmrgstatic boolean 1174af69d88dSmrghas_pipeline_stats_query(struct pipe_screen *screen) 1175af69d88dSmrg{ 1176af69d88dSmrg return screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS) != 0; 1177af69d88dSmrg} 1178af69d88dSmrg 1179af69d88dSmrgstatic void 118001e04c3fSmrghud_parse_env_var(struct hud_context *hud, struct pipe_screen *screen, 118101e04c3fSmrg const char *env) 1182af69d88dSmrg{ 1183af69d88dSmrg unsigned num, i; 118401e04c3fSmrg char name_a[256], s[256]; 118501e04c3fSmrg char *name; 1186af69d88dSmrg struct hud_pane *pane = NULL; 118701e04c3fSmrg unsigned x = 10, y = 10, y_simple = 10; 1188af69d88dSmrg unsigned width = 251, height = 100; 1189af69d88dSmrg unsigned period = 500 * 1000; /* default period (1/2 second) */ 119001e04c3fSmrg uint64_t ceiling = UINT64_MAX; 119101e04c3fSmrg unsigned column_width = 251; 119201e04c3fSmrg boolean dyn_ceiling = false; 119301e04c3fSmrg boolean reset_colors = false; 119401e04c3fSmrg boolean sort_items = false; 1195af69d88dSmrg const char *period_env; 1196af69d88dSmrg 11977ec681f3Smrg if (strncmp(env, "simple,", 7) == 0) { 119801e04c3fSmrg hud->simple = true; 119901e04c3fSmrg env += 7; 120001e04c3fSmrg } 120101e04c3fSmrg 1202af69d88dSmrg /* 1203af69d88dSmrg * The GALLIUM_HUD_PERIOD env var sets the graph update rate. 1204af69d88dSmrg * The env var is in seconds (a float). 1205af69d88dSmrg * Zero means update after every frame. 1206af69d88dSmrg */ 1207af69d88dSmrg period_env = getenv("GALLIUM_HUD_PERIOD"); 1208af69d88dSmrg if (period_env) { 1209af69d88dSmrg float p = (float) atof(period_env); 1210af69d88dSmrg if (p >= 0.0f) { 1211af69d88dSmrg period = (unsigned) (p * 1000 * 1000); 1212af69d88dSmrg } 1213af69d88dSmrg } 1214af69d88dSmrg 121501e04c3fSmrg while ((num = parse_string(env, name_a)) != 0) { 121601e04c3fSmrg bool added = true; 121701e04c3fSmrg 1218af69d88dSmrg env += num; 1219af69d88dSmrg 122001e04c3fSmrg /* check for explicit location, size and etc. settings */ 122101e04c3fSmrg name = read_pane_settings(name_a, &x, &y, &width, &height, &ceiling, 122201e04c3fSmrg &dyn_ceiling, &reset_colors, &sort_items); 122301e04c3fSmrg 122401e04c3fSmrg /* 122501e04c3fSmrg * Keep track of overall column width to avoid pane overlapping in case 122601e04c3fSmrg * later we create a new column while the bottom pane in the current 122701e04c3fSmrg * column is less wide than the rest of the panes in it. 122801e04c3fSmrg */ 122901e04c3fSmrg column_width = width > column_width ? width : column_width; 123001e04c3fSmrg 1231af69d88dSmrg if (!pane) { 123201e04c3fSmrg pane = hud_pane_create(hud, x, y, x + width, y + height, y_simple, 123301e04c3fSmrg period, 10, ceiling, dyn_ceiling, sort_items); 1234af69d88dSmrg if (!pane) 1235af69d88dSmrg return; 1236af69d88dSmrg } 1237af69d88dSmrg 123801e04c3fSmrg if (reset_colors) { 123901e04c3fSmrg pane->next_color = 0; 124001e04c3fSmrg reset_colors = false; 124101e04c3fSmrg } 124201e04c3fSmrg 1243af69d88dSmrg /* Add a graph. */ 124401e04c3fSmrg#if defined(HAVE_GALLIUM_EXTRA_HUD) || defined(HAVE_LIBSENSORS) 124501e04c3fSmrg char arg_name[64]; 124601e04c3fSmrg#endif 1247af69d88dSmrg /* IF YOU CHANGE THIS, UPDATE print_help! */ 1248af69d88dSmrg if (strcmp(name, "fps") == 0) { 1249af69d88dSmrg hud_fps_graph_install(pane); 1250af69d88dSmrg } 125101e04c3fSmrg else if (strcmp(name, "frametime") == 0) { 125201e04c3fSmrg hud_frametime_graph_install(pane); 125301e04c3fSmrg } 1254af69d88dSmrg else if (strcmp(name, "cpu") == 0) { 1255af69d88dSmrg hud_cpu_graph_install(pane, ALL_CPUS); 1256af69d88dSmrg } 1257af69d88dSmrg else if (sscanf(name, "cpu%u%s", &i, s) == 1) { 1258af69d88dSmrg hud_cpu_graph_install(pane, i); 1259af69d88dSmrg } 126001e04c3fSmrg else if (strcmp(name, "API-thread-busy") == 0) { 126101e04c3fSmrg hud_thread_busy_install(pane, name, false); 126201e04c3fSmrg } 126301e04c3fSmrg else if (strcmp(name, "API-thread-offloaded-slots") == 0) { 126401e04c3fSmrg hud_thread_counter_install(pane, name, HUD_COUNTER_OFFLOADED); 126501e04c3fSmrg } 126601e04c3fSmrg else if (strcmp(name, "API-thread-direct-slots") == 0) { 126701e04c3fSmrg hud_thread_counter_install(pane, name, HUD_COUNTER_DIRECT); 126801e04c3fSmrg } 126901e04c3fSmrg else if (strcmp(name, "API-thread-num-syncs") == 0) { 127001e04c3fSmrg hud_thread_counter_install(pane, name, HUD_COUNTER_SYNCS); 127101e04c3fSmrg } 127201e04c3fSmrg else if (strcmp(name, "main-thread-busy") == 0) { 127301e04c3fSmrg hud_thread_busy_install(pane, name, true); 127401e04c3fSmrg } 127501e04c3fSmrg#ifdef HAVE_GALLIUM_EXTRA_HUD 127601e04c3fSmrg else if (sscanf(name, "nic-rx-%s", arg_name) == 1) { 127701e04c3fSmrg hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_RX); 127801e04c3fSmrg } 127901e04c3fSmrg else if (sscanf(name, "nic-tx-%s", arg_name) == 1) { 128001e04c3fSmrg hud_nic_graph_install(pane, arg_name, NIC_DIRECTION_TX); 128101e04c3fSmrg } 128201e04c3fSmrg else if (sscanf(name, "nic-rssi-%s", arg_name) == 1) { 128301e04c3fSmrg hud_nic_graph_install(pane, arg_name, NIC_RSSI_DBM); 128401e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_DBM; 128501e04c3fSmrg } 128601e04c3fSmrg else if (sscanf(name, "diskstat-rd-%s", arg_name) == 1) { 128701e04c3fSmrg hud_diskstat_graph_install(pane, arg_name, DISKSTAT_RD); 128801e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES; 128901e04c3fSmrg } 129001e04c3fSmrg else if (sscanf(name, "diskstat-wr-%s", arg_name) == 1) { 129101e04c3fSmrg hud_diskstat_graph_install(pane, arg_name, DISKSTAT_WR); 129201e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_BYTES; 129301e04c3fSmrg } 129401e04c3fSmrg else if (sscanf(name, "cpufreq-min-cpu%u", &i) == 1) { 129501e04c3fSmrg hud_cpufreq_graph_install(pane, i, CPUFREQ_MINIMUM); 129601e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; 129701e04c3fSmrg } 129801e04c3fSmrg else if (sscanf(name, "cpufreq-cur-cpu%u", &i) == 1) { 129901e04c3fSmrg hud_cpufreq_graph_install(pane, i, CPUFREQ_CURRENT); 130001e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; 130101e04c3fSmrg } 130201e04c3fSmrg else if (sscanf(name, "cpufreq-max-cpu%u", &i) == 1) { 130301e04c3fSmrg hud_cpufreq_graph_install(pane, i, CPUFREQ_MAXIMUM); 130401e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_HZ; 130501e04c3fSmrg } 130601e04c3fSmrg#endif 130701e04c3fSmrg#ifdef HAVE_LIBSENSORS 130801e04c3fSmrg else if (sscanf(name, "sensors_temp_cu-%s", arg_name) == 1) { 130901e04c3fSmrg hud_sensors_temp_graph_install(pane, arg_name, 131001e04c3fSmrg SENSORS_TEMP_CURRENT); 131101e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE; 131201e04c3fSmrg } 131301e04c3fSmrg else if (sscanf(name, "sensors_temp_cr-%s", arg_name) == 1) { 131401e04c3fSmrg hud_sensors_temp_graph_install(pane, arg_name, 131501e04c3fSmrg SENSORS_TEMP_CRITICAL); 131601e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_TEMPERATURE; 131701e04c3fSmrg } 131801e04c3fSmrg else if (sscanf(name, "sensors_volt_cu-%s", arg_name) == 1) { 131901e04c3fSmrg hud_sensors_temp_graph_install(pane, arg_name, 132001e04c3fSmrg SENSORS_VOLTAGE_CURRENT); 132101e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_VOLTS; 132201e04c3fSmrg } 132301e04c3fSmrg else if (sscanf(name, "sensors_curr_cu-%s", arg_name) == 1) { 132401e04c3fSmrg hud_sensors_temp_graph_install(pane, arg_name, 132501e04c3fSmrg SENSORS_CURRENT_CURRENT); 132601e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_AMPS; 132701e04c3fSmrg } 132801e04c3fSmrg else if (sscanf(name, "sensors_pow_cu-%s", arg_name) == 1) { 132901e04c3fSmrg hud_sensors_temp_graph_install(pane, arg_name, 133001e04c3fSmrg SENSORS_POWER_CURRENT); 133101e04c3fSmrg pane->type = PIPE_DRIVER_QUERY_TYPE_WATTS; 133201e04c3fSmrg } 133301e04c3fSmrg#endif 1334af69d88dSmrg else if (strcmp(name, "samples-passed") == 0 && 133501e04c3fSmrg has_occlusion_query(screen)) { 133601e04c3fSmrg hud_pipe_query_install(&hud->batch_query, pane, 133701e04c3fSmrg "samples-passed", 133801e04c3fSmrg PIPE_QUERY_OCCLUSION_COUNTER, 0, 0, 133901e04c3fSmrg PIPE_DRIVER_QUERY_TYPE_UINT64, 134001e04c3fSmrg PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE, 134101e04c3fSmrg 0); 1342af69d88dSmrg } 1343af69d88dSmrg else if (strcmp(name, "primitives-generated") == 0 && 134401e04c3fSmrg has_streamout(screen)) { 134501e04c3fSmrg hud_pipe_query_install(&hud->batch_query, pane, 134601e04c3fSmrg "primitives-generated", 134701e04c3fSmrg PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0, 134801e04c3fSmrg PIPE_DRIVER_QUERY_TYPE_UINT64, 134901e04c3fSmrg PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE, 135001e04c3fSmrg 0); 1351af69d88dSmrg } 1352af69d88dSmrg else { 1353af69d88dSmrg boolean processed = FALSE; 1354af69d88dSmrg 1355af69d88dSmrg /* pipeline statistics queries */ 135601e04c3fSmrg if (has_pipeline_stats_query(screen)) { 1357af69d88dSmrg static const char *pipeline_statistics_names[] = 1358af69d88dSmrg { 1359af69d88dSmrg "ia-vertices", 1360af69d88dSmrg "ia-primitives", 1361af69d88dSmrg "vs-invocations", 1362af69d88dSmrg "gs-invocations", 1363af69d88dSmrg "gs-primitives", 1364af69d88dSmrg "clipper-invocations", 1365af69d88dSmrg "clipper-primitives-generated", 1366af69d88dSmrg "ps-invocations", 1367af69d88dSmrg "hs-invocations", 1368af69d88dSmrg "ds-invocations", 1369af69d88dSmrg "cs-invocations" 1370af69d88dSmrg }; 137101e04c3fSmrg for (i = 0; i < ARRAY_SIZE(pipeline_statistics_names); ++i) 1372af69d88dSmrg if (strcmp(name, pipeline_statistics_names[i]) == 0) 1373af69d88dSmrg break; 137401e04c3fSmrg if (i < ARRAY_SIZE(pipeline_statistics_names)) { 137501e04c3fSmrg hud_pipe_query_install(&hud->batch_query, pane, name, 1376af69d88dSmrg PIPE_QUERY_PIPELINE_STATISTICS, i, 137701e04c3fSmrg 0, PIPE_DRIVER_QUERY_TYPE_UINT64, 137801e04c3fSmrg PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE, 137901e04c3fSmrg 0); 1380af69d88dSmrg processed = TRUE; 1381af69d88dSmrg } 1382af69d88dSmrg } 1383af69d88dSmrg 1384af69d88dSmrg /* driver queries */ 1385af69d88dSmrg if (!processed) { 138601e04c3fSmrg if (!hud_driver_query_install(&hud->batch_query, pane, 138701e04c3fSmrg screen, name)) { 1388af69d88dSmrg fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name); 138901e04c3fSmrg fflush(stderr); 139001e04c3fSmrg added = false; 1391af69d88dSmrg } 1392af69d88dSmrg } 1393af69d88dSmrg } 1394af69d88dSmrg 1395af69d88dSmrg if (*env == ':') { 1396af69d88dSmrg env++; 1397af69d88dSmrg 1398af69d88dSmrg if (!pane) { 1399af69d88dSmrg fprintf(stderr, "gallium_hud: syntax error: unexpected ':', " 1400af69d88dSmrg "expected a name\n"); 140101e04c3fSmrg fflush(stderr); 1402af69d88dSmrg break; 1403af69d88dSmrg } 1404af69d88dSmrg 1405af69d88dSmrg num = parse_string(env, s); 1406af69d88dSmrg env += num; 1407af69d88dSmrg 1408af69d88dSmrg if (num && sscanf(s, "%u", &i) == 1) { 1409af69d88dSmrg hud_pane_set_max_value(pane, i); 141001e04c3fSmrg pane->initial_max_value = i; 1411af69d88dSmrg } 1412af69d88dSmrg else { 1413af69d88dSmrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) " 141401e04c3fSmrg "after ':'\n", *env, *env); 141501e04c3fSmrg fflush(stderr); 141601e04c3fSmrg } 141701e04c3fSmrg } 141801e04c3fSmrg 141901e04c3fSmrg if (*env == '=') { 142001e04c3fSmrg env++; 142101e04c3fSmrg 142201e04c3fSmrg if (!pane) { 142301e04c3fSmrg fprintf(stderr, "gallium_hud: syntax error: unexpected '=', " 142401e04c3fSmrg "expected a name\n"); 142501e04c3fSmrg fflush(stderr); 142601e04c3fSmrg break; 142701e04c3fSmrg } 142801e04c3fSmrg 142901e04c3fSmrg num = parse_string(env, s); 143001e04c3fSmrg env += num; 143101e04c3fSmrg 143201e04c3fSmrg strip_hyphens(s); 14337ec681f3Smrg if (added && !list_is_empty(&pane->graph_list)) { 143401e04c3fSmrg struct hud_graph *graph; 143501e04c3fSmrg graph = LIST_ENTRY(struct hud_graph, pane->graph_list.prev, head); 143601e04c3fSmrg strncpy(graph->name, s, sizeof(graph->name)-1); 143701e04c3fSmrg graph->name[sizeof(graph->name)-1] = 0; 1438af69d88dSmrg } 1439af69d88dSmrg } 1440af69d88dSmrg 1441af69d88dSmrg if (*env == 0) 1442af69d88dSmrg break; 1443af69d88dSmrg 1444af69d88dSmrg /* parse a separator */ 1445af69d88dSmrg switch (*env) { 1446af69d88dSmrg case '+': 1447af69d88dSmrg env++; 1448af69d88dSmrg break; 1449af69d88dSmrg 1450af69d88dSmrg case ',': 1451af69d88dSmrg env++; 145201e04c3fSmrg if (!pane) 145301e04c3fSmrg break; 145401e04c3fSmrg 1455af69d88dSmrg y += height + hud->font.glyph_height * (pane->num_graphs + 2); 145601e04c3fSmrg y_simple += hud->font.glyph_height * (pane->num_graphs + 1); 145701e04c3fSmrg height = 100; 1458af69d88dSmrg 1459af69d88dSmrg if (pane && pane->num_graphs) { 14607ec681f3Smrg list_addtail(&pane->head, &hud->pane_list); 1461af69d88dSmrg pane = NULL; 1462af69d88dSmrg } 1463af69d88dSmrg break; 1464af69d88dSmrg 1465af69d88dSmrg case ';': 1466af69d88dSmrg env++; 1467af69d88dSmrg y = 10; 146801e04c3fSmrg y_simple = 10; 146901e04c3fSmrg x += column_width + hud->font.glyph_width * 9; 147001e04c3fSmrg height = 100; 1471af69d88dSmrg 1472af69d88dSmrg if (pane && pane->num_graphs) { 14737ec681f3Smrg list_addtail(&pane->head, &hud->pane_list); 1474af69d88dSmrg pane = NULL; 1475af69d88dSmrg } 147601e04c3fSmrg 147701e04c3fSmrg /* Starting a new column; reset column width. */ 147801e04c3fSmrg column_width = 251; 1479af69d88dSmrg break; 1480af69d88dSmrg 1481af69d88dSmrg default: 1482af69d88dSmrg fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *env); 148301e04c3fSmrg fflush(stderr); 1484af69d88dSmrg } 148501e04c3fSmrg 148601e04c3fSmrg /* Reset to defaults for the next pane in case these were modified. */ 148701e04c3fSmrg width = 251; 148801e04c3fSmrg ceiling = UINT64_MAX; 148901e04c3fSmrg dyn_ceiling = false; 149001e04c3fSmrg sort_items = false; 149101e04c3fSmrg 1492af69d88dSmrg } 1493af69d88dSmrg 1494af69d88dSmrg if (pane) { 1495af69d88dSmrg if (pane->num_graphs) { 14967ec681f3Smrg list_addtail(&pane->head, &hud->pane_list); 1497af69d88dSmrg } 1498af69d88dSmrg else { 1499af69d88dSmrg FREE(pane); 1500af69d88dSmrg } 1501af69d88dSmrg } 150201e04c3fSmrg 150301e04c3fSmrg LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { 150401e04c3fSmrg struct hud_graph *gr; 150501e04c3fSmrg 150601e04c3fSmrg LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { 150701e04c3fSmrg hud_graph_set_dump_file(gr); 150801e04c3fSmrg } 150901e04c3fSmrg } 1510af69d88dSmrg} 1511af69d88dSmrg 1512af69d88dSmrgstatic void 1513af69d88dSmrgprint_help(struct pipe_screen *screen) 1514af69d88dSmrg{ 1515af69d88dSmrg int i, num_queries, num_cpus = hud_get_num_cpus(); 1516af69d88dSmrg 1517af69d88dSmrg puts("Syntax: GALLIUM_HUD=name1[+name2][...][:value1][,nameI...][;nameJ...]"); 1518af69d88dSmrg puts(""); 1519af69d88dSmrg puts(" Names are identifiers of data sources which will be drawn as graphs"); 1520af69d88dSmrg puts(" in panes. Multiple graphs can be drawn in the same pane."); 1521af69d88dSmrg puts(" There can be multiple panes placed in rows and columns."); 1522af69d88dSmrg puts(""); 1523af69d88dSmrg puts(" '+' separates names which will share a pane."); 1524af69d88dSmrg puts(" ':[value]' specifies the initial maximum value of the Y axis"); 1525af69d88dSmrg puts(" for the given pane."); 1526af69d88dSmrg puts(" ',' creates a new pane below the last one."); 1527af69d88dSmrg puts(" ';' creates a new pane at the top of the next column."); 152801e04c3fSmrg puts(" '=' followed by a string, changes the name of the last data source"); 152901e04c3fSmrg puts(" to that string"); 1530af69d88dSmrg puts(""); 1531af69d88dSmrg puts(" Example: GALLIUM_HUD=\"cpu,fps;primitives-generated\""); 1532af69d88dSmrg puts(""); 153301e04c3fSmrg puts(" Additionally, by prepending '.[identifier][value]' modifiers to"); 153401e04c3fSmrg puts(" a name, it is possible to explicitly set the location and size"); 153501e04c3fSmrg puts(" of a pane, along with limiting overall maximum value of the"); 153601e04c3fSmrg puts(" Y axis and activating dynamic readjustment of the Y axis."); 153701e04c3fSmrg puts(" Several modifiers may be applied to the same pane simultaneously."); 153801e04c3fSmrg puts(""); 153901e04c3fSmrg puts(" 'x[value]' sets the location of the pane on the x axis relative"); 154001e04c3fSmrg puts(" to the upper-left corner of the viewport, in pixels."); 154101e04c3fSmrg puts(" 'y[value]' sets the location of the pane on the y axis relative"); 154201e04c3fSmrg puts(" to the upper-left corner of the viewport, in pixels."); 154301e04c3fSmrg puts(" 'w[value]' sets width of the graph pixels."); 154401e04c3fSmrg puts(" 'h[value]' sets height of the graph in pixels."); 154501e04c3fSmrg puts(" 'c[value]' sets the ceiling of the value of the Y axis."); 154601e04c3fSmrg puts(" If the graph needs to draw values higher than"); 154701e04c3fSmrg puts(" the ceiling allows, the value is clamped."); 154801e04c3fSmrg puts(" 'd' activates dynamic Y axis readjustment to set the value of"); 154901e04c3fSmrg puts(" the Y axis to match the highest value still visible in the graph."); 155001e04c3fSmrg puts(" 'r' resets the color counter (the next color will be green)"); 155101e04c3fSmrg puts(" 's' sort items below graphs in descending order"); 155201e04c3fSmrg puts(""); 155301e04c3fSmrg puts(" If 'c' and 'd' modifiers are used simultaneously, both are in effect:"); 155401e04c3fSmrg puts(" the Y axis does not go above the restriction imposed by 'c' while"); 155501e04c3fSmrg puts(" still adjusting the value of the Y axis down when appropriate."); 155601e04c3fSmrg puts(""); 155701e04c3fSmrg puts(" You can change behavior of the whole HUD by adding these options at"); 155801e04c3fSmrg puts(" the beginning of the environment variable:"); 155901e04c3fSmrg puts(" 'simple,' disables all the fancy stuff and only draws text."); 156001e04c3fSmrg puts(""); 156101e04c3fSmrg puts(" Example: GALLIUM_HUD=\".w256.h64.x1600.y520.d.c1000fps+cpu,.datom-count\""); 156201e04c3fSmrg puts(""); 1563af69d88dSmrg puts(" Available names:"); 1564af69d88dSmrg puts(" fps"); 156501e04c3fSmrg puts(" frametime"); 1566af69d88dSmrg puts(" cpu"); 1567af69d88dSmrg 1568af69d88dSmrg for (i = 0; i < num_cpus; i++) 1569af69d88dSmrg printf(" cpu%i\n", i); 1570af69d88dSmrg 1571af69d88dSmrg if (has_occlusion_query(screen)) 1572af69d88dSmrg puts(" samples-passed"); 1573af69d88dSmrg if (has_streamout(screen)) 1574af69d88dSmrg puts(" primitives-generated"); 1575af69d88dSmrg 1576af69d88dSmrg if (has_pipeline_stats_query(screen)) { 1577af69d88dSmrg puts(" ia-vertices"); 1578af69d88dSmrg puts(" ia-primitives"); 1579af69d88dSmrg puts(" vs-invocations"); 1580af69d88dSmrg puts(" gs-invocations"); 1581af69d88dSmrg puts(" gs-primitives"); 1582af69d88dSmrg puts(" clipper-invocations"); 1583af69d88dSmrg puts(" clipper-primitives-generated"); 1584af69d88dSmrg puts(" ps-invocations"); 1585af69d88dSmrg puts(" hs-invocations"); 1586af69d88dSmrg puts(" ds-invocations"); 1587af69d88dSmrg puts(" cs-invocations"); 1588af69d88dSmrg } 1589af69d88dSmrg 159001e04c3fSmrg#ifdef HAVE_GALLIUM_EXTRA_HUD 159101e04c3fSmrg hud_get_num_disks(1); 159201e04c3fSmrg hud_get_num_nics(1); 159301e04c3fSmrg hud_get_num_cpufreq(1); 159401e04c3fSmrg#endif 159501e04c3fSmrg#ifdef HAVE_LIBSENSORS 159601e04c3fSmrg hud_get_num_sensors(1); 159701e04c3fSmrg#endif 159801e04c3fSmrg 1599af69d88dSmrg if (screen->get_driver_query_info){ 160001e04c3fSmrg boolean skipping = false; 1601af69d88dSmrg struct pipe_driver_query_info info; 1602af69d88dSmrg num_queries = screen->get_driver_query_info(screen, 0, NULL); 1603af69d88dSmrg 1604af69d88dSmrg for (i = 0; i < num_queries; i++){ 1605af69d88dSmrg screen->get_driver_query_info(screen, i, &info); 160601e04c3fSmrg if (info.flags & PIPE_DRIVER_QUERY_FLAG_DONT_LIST) { 160701e04c3fSmrg if (!skipping) 160801e04c3fSmrg puts(" ..."); 160901e04c3fSmrg skipping = true; 161001e04c3fSmrg } else { 161101e04c3fSmrg printf(" %s\n", info.name); 161201e04c3fSmrg skipping = false; 161301e04c3fSmrg } 1614af69d88dSmrg } 1615af69d88dSmrg } 1616af69d88dSmrg 1617af69d88dSmrg puts(""); 161801e04c3fSmrg fflush(stdout); 1619af69d88dSmrg} 1620af69d88dSmrg 162101e04c3fSmrgstatic void 162201e04c3fSmrghud_unset_draw_context(struct hud_context *hud) 1623af69d88dSmrg{ 162401e04c3fSmrg struct pipe_context *pipe = hud->pipe; 1625af69d88dSmrg 162601e04c3fSmrg if (!pipe) 162701e04c3fSmrg return; 1628af69d88dSmrg 162901e04c3fSmrg pipe_sampler_view_reference(&hud->font_sampler_view, NULL); 163001e04c3fSmrg 163101e04c3fSmrg if (hud->fs_color) { 163201e04c3fSmrg pipe->delete_fs_state(pipe, hud->fs_color); 163301e04c3fSmrg hud->fs_color = NULL; 163401e04c3fSmrg } 163501e04c3fSmrg if (hud->fs_text) { 163601e04c3fSmrg pipe->delete_fs_state(pipe, hud->fs_text); 163701e04c3fSmrg hud->fs_text = NULL; 163801e04c3fSmrg } 16397ec681f3Smrg if (hud->vs_color) { 16407ec681f3Smrg pipe->delete_vs_state(pipe, hud->vs_color); 16417ec681f3Smrg hud->vs_color = NULL; 16427ec681f3Smrg } 16437ec681f3Smrg if (hud->vs_text) { 16447ec681f3Smrg pipe->delete_vs_state(pipe, hud->vs_text); 16457ec681f3Smrg hud->vs_text = NULL; 1646af69d88dSmrg } 1647af69d88dSmrg 164801e04c3fSmrg hud->cso = NULL; 164901e04c3fSmrg hud->pipe = NULL; 165001e04c3fSmrg} 1651af69d88dSmrg 165201e04c3fSmrgstatic bool 16537ec681f3Smrghud_set_draw_context(struct hud_context *hud, struct cso_context *cso, 16547ec681f3Smrg struct st_context_iface *st) 165501e04c3fSmrg{ 165601e04c3fSmrg struct pipe_context *pipe = cso_get_pipe_context(cso); 165701e04c3fSmrg 165801e04c3fSmrg assert(!hud->pipe); 1659af69d88dSmrg hud->pipe = pipe; 1660af69d88dSmrg hud->cso = cso; 16617ec681f3Smrg hud->st = st; 1662af69d88dSmrg 166301e04c3fSmrg struct pipe_sampler_view view_templ; 166401e04c3fSmrg u_sampler_view_default_template( 166501e04c3fSmrg &view_templ, hud->font.texture, hud->font.texture->format); 166601e04c3fSmrg hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture, 166701e04c3fSmrg &view_templ); 166801e04c3fSmrg if (!hud->font_sampler_view) 166901e04c3fSmrg goto fail; 1670af69d88dSmrg 16717ec681f3Smrg /* color fragment shader */ 1672af69d88dSmrg hud->fs_color = 1673af69d88dSmrg util_make_fragment_passthrough_shader(pipe, 1674af69d88dSmrg TGSI_SEMANTIC_COLOR, 1675af69d88dSmrg TGSI_INTERPOLATE_CONSTANT, 1676af69d88dSmrg TRUE); 1677af69d88dSmrg 16787ec681f3Smrg /* text fragment shader */ 1679af69d88dSmrg { 1680af69d88dSmrg /* Read a texture and do .xxxx swizzling. */ 1681af69d88dSmrg static const char *fragment_shader_text = { 1682af69d88dSmrg "FRAG\n" 1683af69d88dSmrg "DCL IN[0], GENERIC[0], LINEAR\n" 1684af69d88dSmrg "DCL SAMP[0]\n" 168501e04c3fSmrg "DCL SVIEW[0], RECT, FLOAT\n" 1686af69d88dSmrg "DCL OUT[0], COLOR[0]\n" 1687af69d88dSmrg "DCL TEMP[0]\n" 1688af69d88dSmrg 1689af69d88dSmrg "TEX TEMP[0], IN[0], SAMP[0], RECT\n" 1690af69d88dSmrg "MOV OUT[0], TEMP[0].xxxx\n" 1691af69d88dSmrg "END\n" 1692af69d88dSmrg }; 1693af69d88dSmrg 1694af69d88dSmrg struct tgsi_token tokens[1000]; 16957ec681f3Smrg struct pipe_shader_state state = {0}; 1696af69d88dSmrg 169701e04c3fSmrg if (!tgsi_text_translate(fragment_shader_text, tokens, ARRAY_SIZE(tokens))) { 1698af69d88dSmrg assert(0); 169901e04c3fSmrg goto fail; 1700af69d88dSmrg } 170101e04c3fSmrg pipe_shader_state_from_tgsi(&state, tokens); 1702af69d88dSmrg hud->fs_text = pipe->create_fs_state(pipe, &state); 1703af69d88dSmrg } 1704af69d88dSmrg 17057ec681f3Smrg /* color vertex shader */ 1706af69d88dSmrg { 1707af69d88dSmrg static const char *vertex_shader_text = { 1708af69d88dSmrg "VERT\n" 1709af69d88dSmrg "DCL IN[0..1]\n" 1710af69d88dSmrg "DCL OUT[0], POSITION\n" 1711af69d88dSmrg "DCL OUT[1], COLOR[0]\n" /* color */ 1712af69d88dSmrg "DCL OUT[2], GENERIC[0]\n" /* texcoord */ 1713af69d88dSmrg /* [0] = color, 1714af69d88dSmrg * [1] = (2/fb_width, 2/fb_height, xoffset, yoffset) 1715af69d88dSmrg * [2] = (xscale, yscale, 0, 0) */ 171601e04c3fSmrg "DCL CONST[0][0..2]\n" 1717af69d88dSmrg "DCL TEMP[0]\n" 1718af69d88dSmrg "IMM[0] FLT32 { -1, 0, 0, 1 }\n" 1719af69d88dSmrg 1720af69d88dSmrg /* v = in * (xscale, yscale) + (xoffset, yoffset) */ 172101e04c3fSmrg "MAD TEMP[0].xy, IN[0], CONST[0][2].xyyy, CONST[0][1].zwww\n" 1722af69d88dSmrg /* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */ 172301e04c3fSmrg "MAD OUT[0].xy, TEMP[0], CONST[0][1].xyyy, IMM[0].xxxx\n" 1724af69d88dSmrg "MOV OUT[0].zw, IMM[0]\n" 1725af69d88dSmrg 172601e04c3fSmrg "MOV OUT[1], CONST[0][0]\n" 1727af69d88dSmrg "MOV OUT[2], IN[1]\n" 1728af69d88dSmrg "END\n" 1729af69d88dSmrg }; 1730af69d88dSmrg 1731af69d88dSmrg struct tgsi_token tokens[1000]; 17327ec681f3Smrg struct pipe_shader_state state = {0}; 173301e04c3fSmrg if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) { 1734af69d88dSmrg assert(0); 173501e04c3fSmrg goto fail; 1736af69d88dSmrg } 173701e04c3fSmrg pipe_shader_state_from_tgsi(&state, tokens); 17387ec681f3Smrg hud->vs_color = pipe->create_vs_state(pipe, &state); 17397ec681f3Smrg } 17407ec681f3Smrg 17417ec681f3Smrg /* text vertex shader */ 17427ec681f3Smrg { 17437ec681f3Smrg /* similar to the above, without the color component 17447ec681f3Smrg * to match the varyings in fs_text */ 17457ec681f3Smrg static const char *vertex_shader_text = { 17467ec681f3Smrg "VERT\n" 17477ec681f3Smrg "DCL IN[0..1]\n" 17487ec681f3Smrg "DCL OUT[0], POSITION\n" 17497ec681f3Smrg "DCL OUT[1], GENERIC[0]\n" /* texcoord */ 17507ec681f3Smrg /* [0] = color, 17517ec681f3Smrg * [1] = (2/fb_width, 2/fb_height, xoffset, yoffset) 17527ec681f3Smrg * [2] = (xscale, yscale, 0, 0) */ 17537ec681f3Smrg "DCL CONST[0][0..2]\n" 17547ec681f3Smrg "DCL TEMP[0]\n" 17557ec681f3Smrg "IMM[0] FLT32 { -1, 0, 0, 1 }\n" 17567ec681f3Smrg 17577ec681f3Smrg /* v = in * (xscale, yscale) + (xoffset, yoffset) */ 17587ec681f3Smrg "MAD TEMP[0].xy, IN[0], CONST[0][2].xyyy, CONST[0][1].zwww\n" 17597ec681f3Smrg /* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */ 17607ec681f3Smrg "MAD OUT[0].xy, TEMP[0], CONST[0][1].xyyy, IMM[0].xxxx\n" 17617ec681f3Smrg "MOV OUT[0].zw, IMM[0]\n" 17627ec681f3Smrg 17637ec681f3Smrg "MOV OUT[1], IN[1]\n" 17647ec681f3Smrg "END\n" 17657ec681f3Smrg }; 17667ec681f3Smrg 17677ec681f3Smrg struct tgsi_token tokens[1000]; 17687ec681f3Smrg struct pipe_shader_state state = {0}; 17697ec681f3Smrg if (!tgsi_text_translate(vertex_shader_text, tokens, ARRAY_SIZE(tokens))) { 17707ec681f3Smrg assert(0); 17717ec681f3Smrg goto fail; 17727ec681f3Smrg } 17737ec681f3Smrg pipe_shader_state_from_tgsi(&state, tokens); 17747ec681f3Smrg hud->vs_text = pipe->create_vs_state(pipe, &state); 1775af69d88dSmrg } 1776af69d88dSmrg 177701e04c3fSmrg return true; 177801e04c3fSmrg 177901e04c3fSmrgfail: 178001e04c3fSmrg hud_unset_draw_context(hud); 178101e04c3fSmrg fprintf(stderr, "hud: failed to set a draw context"); 178201e04c3fSmrg return false; 178301e04c3fSmrg} 178401e04c3fSmrg 178501e04c3fSmrgstatic void 178601e04c3fSmrghud_unset_record_context(struct hud_context *hud) 178701e04c3fSmrg{ 178801e04c3fSmrg struct pipe_context *pipe = hud->record_pipe; 178901e04c3fSmrg struct hud_pane *pane, *pane_tmp; 179001e04c3fSmrg struct hud_graph *graph, *graph_tmp; 179101e04c3fSmrg 179201e04c3fSmrg if (!pipe) 179301e04c3fSmrg return; 179401e04c3fSmrg 179501e04c3fSmrg LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) { 179601e04c3fSmrg LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) { 17977ec681f3Smrg list_del(&graph->head); 179801e04c3fSmrg hud_graph_destroy(graph, pipe); 179901e04c3fSmrg } 18007ec681f3Smrg list_del(&pane->head); 180101e04c3fSmrg FREE(pane); 180201e04c3fSmrg } 180301e04c3fSmrg 180401e04c3fSmrg hud_batch_query_cleanup(&hud->batch_query, pipe); 180501e04c3fSmrg hud->record_pipe = NULL; 180601e04c3fSmrg} 180701e04c3fSmrg 180801e04c3fSmrgstatic void 180901e04c3fSmrghud_set_record_context(struct hud_context *hud, struct pipe_context *pipe) 181001e04c3fSmrg{ 181101e04c3fSmrg hud->record_pipe = pipe; 181201e04c3fSmrg} 181301e04c3fSmrg 181401e04c3fSmrg/** 181501e04c3fSmrg * Create the HUD. 181601e04c3fSmrg * 181701e04c3fSmrg * If "share" is non-NULL and GALLIUM_HUD_SHARE=x,y is set, increment the 181801e04c3fSmrg * reference counter of "share", set "cso" as the recording or drawing context 181901e04c3fSmrg * according to the environment variable, and return "share". 182001e04c3fSmrg * This allows sharing the HUD instance within a multi-context share group, 182101e04c3fSmrg * record queries in one context and draw them in another. 182201e04c3fSmrg */ 182301e04c3fSmrgstruct hud_context * 18247ec681f3Smrghud_create(struct cso_context *cso, struct st_context_iface *st, 18257ec681f3Smrg struct hud_context *share) 182601e04c3fSmrg{ 182701e04c3fSmrg const char *share_env = debug_get_option("GALLIUM_HUD_SHARE", NULL); 182801e04c3fSmrg unsigned record_ctx = 0, draw_ctx = 0; 182901e04c3fSmrg 183001e04c3fSmrg if (share_env && sscanf(share_env, "%u,%u", &record_ctx, &draw_ctx) != 2) 183101e04c3fSmrg share_env = NULL; 183201e04c3fSmrg 183301e04c3fSmrg if (share && share_env) { 183401e04c3fSmrg /* All contexts in a share group share the HUD instance. 183501e04c3fSmrg * Only one context can record queries and only one context 183601e04c3fSmrg * can draw the HUD. 183701e04c3fSmrg * 183801e04c3fSmrg * GALLIUM_HUD_SHARE=x,y determines the context indices. 183901e04c3fSmrg */ 184001e04c3fSmrg int context_id = p_atomic_inc_return(&share->refcount) - 1; 184101e04c3fSmrg 184201e04c3fSmrg if (context_id == record_ctx) { 184301e04c3fSmrg assert(!share->record_pipe); 184401e04c3fSmrg hud_set_record_context(share, cso_get_pipe_context(cso)); 184501e04c3fSmrg } 184601e04c3fSmrg 184701e04c3fSmrg if (context_id == draw_ctx) { 184801e04c3fSmrg assert(!share->pipe); 18497ec681f3Smrg hud_set_draw_context(share, cso, st); 185001e04c3fSmrg } 185101e04c3fSmrg 185201e04c3fSmrg return share; 185301e04c3fSmrg } 185401e04c3fSmrg 185501e04c3fSmrg struct pipe_screen *screen = cso_get_pipe_context(cso)->screen; 185601e04c3fSmrg struct hud_context *hud; 185701e04c3fSmrg unsigned i; 185801e04c3fSmrg const char *env = debug_get_option("GALLIUM_HUD", NULL); 185901e04c3fSmrg#ifdef PIPE_OS_UNIX 186001e04c3fSmrg unsigned signo = debug_get_num_option("GALLIUM_HUD_TOGGLE_SIGNAL", 0); 186101e04c3fSmrg static boolean sig_handled = FALSE; 18627ec681f3Smrg struct sigaction action; 18637ec681f3Smrg 18647ec681f3Smrg memset(&action, 0, sizeof(action)); 186501e04c3fSmrg#endif 186601e04c3fSmrg huds_visible = debug_get_bool_option("GALLIUM_HUD_VISIBLE", TRUE); 18677ec681f3Smrg hud_scale = debug_get_num_option("GALLIUM_HUD_SCALE", 1); 186801e04c3fSmrg 186901e04c3fSmrg if (!env || !*env) 187001e04c3fSmrg return NULL; 187101e04c3fSmrg 187201e04c3fSmrg if (strcmp(env, "help") == 0) { 187301e04c3fSmrg print_help(screen); 187401e04c3fSmrg return NULL; 187501e04c3fSmrg } 187601e04c3fSmrg 187701e04c3fSmrg hud = CALLOC_STRUCT(hud_context); 187801e04c3fSmrg if (!hud) 187901e04c3fSmrg return NULL; 188001e04c3fSmrg 188101e04c3fSmrg /* font (the context is only used for the texture upload) */ 188201e04c3fSmrg if (!util_font_create(cso_get_pipe_context(cso), 188301e04c3fSmrg UTIL_FONT_FIXED_8X13, &hud->font)) { 188401e04c3fSmrg FREE(hud); 188501e04c3fSmrg return NULL; 188601e04c3fSmrg } 188701e04c3fSmrg 188801e04c3fSmrg hud->refcount = 1; 18897ec681f3Smrg 18907ec681f3Smrg static const enum pipe_format srgb_formats[] = { 18917ec681f3Smrg PIPE_FORMAT_B8G8R8A8_SRGB, 18927ec681f3Smrg PIPE_FORMAT_B8G8R8X8_SRGB 18937ec681f3Smrg }; 18947ec681f3Smrg for (i = 0; i < ARRAY_SIZE(srgb_formats); i++) { 18957ec681f3Smrg if (!screen->is_format_supported(screen, srgb_formats[i], 18967ec681f3Smrg PIPE_TEXTURE_2D, 0, 0, 18977ec681f3Smrg PIPE_BIND_RENDER_TARGET)) 18987ec681f3Smrg break; 18997ec681f3Smrg } 19007ec681f3Smrg 19017ec681f3Smrg hud->has_srgb = (i == ARRAY_SIZE(srgb_formats)); 190201e04c3fSmrg 190301e04c3fSmrg /* blend state */ 190401e04c3fSmrg hud->no_blend.rt[0].colormask = PIPE_MASK_RGBA; 190501e04c3fSmrg 190601e04c3fSmrg hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA; 190701e04c3fSmrg hud->alpha_blend.rt[0].blend_enable = 1; 190801e04c3fSmrg hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD; 190901e04c3fSmrg hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; 191001e04c3fSmrg hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; 191101e04c3fSmrg hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD; 191201e04c3fSmrg hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; 191301e04c3fSmrg hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; 191401e04c3fSmrg 191501e04c3fSmrg /* rasterizer */ 191601e04c3fSmrg hud->rasterizer.half_pixel_center = 1; 191701e04c3fSmrg hud->rasterizer.bottom_edge_rule = 1; 191801e04c3fSmrg hud->rasterizer.depth_clip_near = 1; 191901e04c3fSmrg hud->rasterizer.depth_clip_far = 1; 192001e04c3fSmrg hud->rasterizer.line_width = 1; 192101e04c3fSmrg hud->rasterizer.line_last_pixel = 1; 192201e04c3fSmrg 192301e04c3fSmrg hud->rasterizer_aa_lines = hud->rasterizer; 192401e04c3fSmrg hud->rasterizer_aa_lines.line_smooth = 1; 192501e04c3fSmrg 1926af69d88dSmrg /* vertex elements */ 19277ec681f3Smrg hud->velems.count = 2; 1928af69d88dSmrg for (i = 0; i < 2; i++) { 19297ec681f3Smrg hud->velems.velems[i].src_offset = i * 2 * sizeof(float); 19307ec681f3Smrg hud->velems.velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT; 19317ec681f3Smrg hud->velems.velems[i].vertex_buffer_index = 0; 1932af69d88dSmrg } 1933af69d88dSmrg 1934af69d88dSmrg /* sampler state (for font drawing) */ 1935af69d88dSmrg hud->font_sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 1936af69d88dSmrg hud->font_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 1937af69d88dSmrg hud->font_sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 1938af69d88dSmrg hud->font_sampler_state.normalized_coords = 0; 1939af69d88dSmrg 1940af69d88dSmrg /* constants */ 1941af69d88dSmrg hud->constbuf.buffer_size = sizeof(hud->constants); 1942af69d88dSmrg hud->constbuf.user_buffer = &hud->constants; 1943af69d88dSmrg 19447ec681f3Smrg list_inithead(&hud->pane_list); 1945af69d88dSmrg 194601e04c3fSmrg /* setup sig handler once for all hud contexts */ 194701e04c3fSmrg#ifdef PIPE_OS_UNIX 194801e04c3fSmrg if (!sig_handled && signo != 0) { 194901e04c3fSmrg action.sa_sigaction = &signal_visible_handler; 195001e04c3fSmrg action.sa_flags = SA_SIGINFO; 195101e04c3fSmrg 195201e04c3fSmrg if (signo >= NSIG) 195301e04c3fSmrg fprintf(stderr, "gallium_hud: invalid signal %u\n", signo); 195401e04c3fSmrg else if (sigaction(signo, &action, NULL) < 0) 195501e04c3fSmrg fprintf(stderr, "gallium_hud: unable to set handler for signal %u\n", signo); 195601e04c3fSmrg fflush(stderr); 195701e04c3fSmrg 195801e04c3fSmrg sig_handled = TRUE; 195901e04c3fSmrg } 196001e04c3fSmrg#endif 196101e04c3fSmrg 196201e04c3fSmrg if (record_ctx == 0) 196301e04c3fSmrg hud_set_record_context(hud, cso_get_pipe_context(cso)); 196401e04c3fSmrg if (draw_ctx == 0) 19657ec681f3Smrg hud_set_draw_context(hud, cso, st); 196601e04c3fSmrg 196701e04c3fSmrg hud_parse_env_var(hud, screen, env); 1968af69d88dSmrg return hud; 1969af69d88dSmrg} 1970af69d88dSmrg 197101e04c3fSmrg/** 197201e04c3fSmrg * Destroy a HUD. If the HUD has several users, decrease the reference counter 197301e04c3fSmrg * and detach the context from the HUD. 197401e04c3fSmrg */ 1975af69d88dSmrgvoid 197601e04c3fSmrghud_destroy(struct hud_context *hud, struct cso_context *cso) 1977af69d88dSmrg{ 197801e04c3fSmrg if (!cso || hud->record_pipe == cso_get_pipe_context(cso)) 197901e04c3fSmrg hud_unset_record_context(hud); 1980af69d88dSmrg 198101e04c3fSmrg if (!cso || hud->cso == cso) 198201e04c3fSmrg hud_unset_draw_context(hud); 198301e04c3fSmrg 198401e04c3fSmrg if (p_atomic_dec_zero(&hud->refcount)) { 198501e04c3fSmrg pipe_resource_reference(&hud->font.texture, NULL); 198601e04c3fSmrg FREE(hud); 1987af69d88dSmrg } 198801e04c3fSmrg} 1989af69d88dSmrg 199001e04c3fSmrgvoid 199101e04c3fSmrghud_add_queue_for_monitoring(struct hud_context *hud, 199201e04c3fSmrg struct util_queue_monitoring *queue_info) 199301e04c3fSmrg{ 199401e04c3fSmrg assert(!hud->monitored_queue); 199501e04c3fSmrg hud->monitored_queue = queue_info; 1996af69d88dSmrg} 1997