diff options
author | Marek Olšák <[email protected]> | 2013-03-21 19:47:06 +0100 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2013-03-26 01:28:19 +0100 |
commit | c91cf7d7d2c8cc377945c79be87799c31ce9ae59 (patch) | |
tree | acc9345705da9347f95fd9151a878d2fee5f0596 /src/gallium/auxiliary | |
parent | 8ddcd715b7e6ca3d10ddd57ea504e55ca8c8cbd7 (diff) |
gallium: implement a heads-up display module
Reviewed-by: Brian Paul <[email protected]>
v2: lots of cosmetic changes
Diffstat (limited to 'src/gallium/auxiliary')
-rw-r--r-- | src/gallium/auxiliary/Makefile.sources | 5 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/font.c | 437 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/font.h | 59 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/hud_context.c | 993 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/hud_context.h | 45 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/hud_cpu.c | 164 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/hud_driver_query.c | 207 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/hud_fps.c | 81 | ||||
-rw-r--r-- | src/gallium/auxiliary/hud/hud_private.h | 91 |
9 files changed, 2082 insertions, 0 deletions
diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources index 898abe0247c..79def217725 100644 --- a/src/gallium/auxiliary/Makefile.sources +++ b/src/gallium/auxiliary/Makefile.sources @@ -37,6 +37,11 @@ C_SOURCES := \ draw/draw_vs.c \ draw/draw_vs_exec.c \ draw/draw_vs_variant.c \ + hud/font.c \ + hud/hud_context.c \ + hud/hud_cpu.c \ + hud/hud_fps.c \ + hud/hud_driver_query.c \ os/os_misc.c \ os/os_time.c \ pipebuffer/pb_buffer_fenced.c \ diff --git a/src/gallium/auxiliary/hud/font.c b/src/gallium/auxiliary/hud/font.c new file mode 100644 index 00000000000..5c4a4d07e5d --- /dev/null +++ b/src/gallium/auxiliary/hud/font.c @@ -0,0 +1,437 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* This is the "8_BY_13" font extracted from freeglut. */ + +/* + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <[email protected]> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hud/font.h" + +#include "pipe/p_compiler.h" +#include "pipe/p_screen.h" +#include "pipe/p_state.h" +#include "pipe/p_context.h" +#include "util/u_inlines.h" + +typedef unsigned char GLubyte; /* 1-byte unsigned */ +typedef struct tagSFG_Font SFG_Font; + +struct tagSFG_Font +{ + char* Name; /* The source font name */ + int Quantity; /* Number of chars in font */ + int Height; /* Height of the characters */ + const GLubyte** Characters; /* The characters mapping */ + + float xorig, yorig; /* Relative origin of the character */ +}; + +static const GLubyte Fixed8x13_Character_000[] = { 8, 0, 0, 0,170, 0,130, 0,130, 0,130, 0,170, 0, 0}; +static const GLubyte Fixed8x13_Character_001[] = { 8, 0, 0, 0, 0, 16, 56,124,254,124, 56, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_002[] = { 8, 0,170, 85,170, 85,170, 85,170, 85,170, 85,170, 85,170}; +static const GLubyte Fixed8x13_Character_003[] = { 8, 0, 0, 0, 4, 4, 4, 4,174,160,224,160,160, 0, 0}; +static const GLubyte Fixed8x13_Character_004[] = { 8, 0, 0, 0, 8, 8, 12, 8,142,128,192,128,224, 0, 0}; +static const GLubyte Fixed8x13_Character_005[] = { 8, 0, 0, 0, 10, 10, 12, 10,108,128,128,128, 96, 0, 0}; +static const GLubyte Fixed8x13_Character_006[] = { 8, 0, 0, 0, 8, 8, 12, 8,238,128,128,128,128, 0, 0}; +static const GLubyte Fixed8x13_Character_007[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 24, 36, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_008[] = { 8, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_009[] = { 8, 0, 0, 0, 14, 8, 8, 8,168,160,160,160,192, 0, 0}; +static const GLubyte Fixed8x13_Character_010[] = { 8, 0, 0, 0, 4, 4, 4, 4, 46, 80, 80,136,136, 0, 0}; +static const GLubyte Fixed8x13_Character_011[] = { 8, 0, 0, 0, 0, 0, 0, 0,240, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_012[] = { 8, 0, 16, 16, 16, 16, 16, 16,240, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_013[] = { 8, 0, 16, 16, 16, 16, 16, 16, 31, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_014[] = { 8, 0, 0, 0, 0, 0, 0, 0, 31, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_015[] = { 8, 0, 16, 16, 16, 16, 16, 16,255, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_016[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255}; +static const GLubyte Fixed8x13_Character_017[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_018[] = { 8, 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_019[] = { 8, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_020[] = { 8, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_021[] = { 8, 0, 16, 16, 16, 16, 16, 16, 31, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_022[] = { 8, 0, 16, 16, 16, 16, 16, 16,240, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_023[] = { 8, 0, 0, 0, 0, 0, 0, 0,255, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_024[] = { 8, 0, 16, 16, 16, 16, 16, 16,255, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_025[] = { 8, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_026[] = { 8, 0, 0, 0,254, 0, 14, 48,192, 48, 14, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_027[] = { 8, 0, 0, 0,254, 0,224, 24, 6, 24,224, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_028[] = { 8, 0, 0, 0, 68, 68, 68, 68, 68,254, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_029[] = { 8, 0, 0, 0, 32, 32,126, 16, 8,126, 4, 4, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_030[] = { 8, 0, 0, 0,220, 98, 32, 32, 32,112, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_031[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_032[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_033[] = { 8, 0, 0, 0, 16, 0, 16, 16, 16, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_034[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, 36, 0, 0}; +static const GLubyte Fixed8x13_Character_035[] = { 8, 0, 0, 0, 0, 36, 36,126, 36,126, 36, 36, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_036[] = { 8, 0, 0, 0, 16,120, 20, 20, 56, 80, 80, 60, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_037[] = { 8, 0, 0, 0, 68, 42, 36, 16, 8, 8, 36, 82, 34, 0, 0}; +static const GLubyte Fixed8x13_Character_038[] = { 8, 0, 0, 0, 58, 68, 74, 48, 72, 72, 48, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_039[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 48, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_040[] = { 8, 0, 0, 0, 4, 8, 8, 16, 16, 16, 8, 8, 4, 0, 0}; +static const GLubyte Fixed8x13_Character_041[] = { 8, 0, 0, 0, 32, 16, 16, 8, 8, 8, 16, 16, 32, 0, 0}; +static const GLubyte Fixed8x13_Character_042[] = { 8, 0, 0, 0, 0, 0, 36, 24,126, 24, 36, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_043[] = { 8, 0, 0, 0, 0, 0, 16, 16,124, 16, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_044[] = { 8, 0, 0, 64, 48, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_045[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_046[] = { 8, 0, 0, 16, 56, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_047[] = { 8, 0, 0, 0,128,128, 64, 32, 16, 8, 4, 2, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_048[] = { 8, 0, 0, 0, 24, 36, 66, 66, 66, 66, 66, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_049[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 80, 48, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_050[] = { 8, 0, 0, 0,126, 64, 32, 24, 4, 2, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_051[] = { 8, 0, 0, 0, 60, 66, 2, 2, 28, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_052[] = { 8, 0, 0, 0, 4, 4,126, 68, 68, 36, 20, 12, 4, 0, 0}; +static const GLubyte Fixed8x13_Character_053[] = { 8, 0, 0, 0, 60, 66, 2, 2, 98, 92, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_054[] = { 8, 0, 0, 0, 60, 66, 66, 98, 92, 64, 64, 32, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_055[] = { 8, 0, 0, 0, 32, 32, 16, 16, 8, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_056[] = { 8, 0, 0, 0, 60, 66, 66, 66, 60, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_057[] = { 8, 0, 0, 0, 56, 4, 2, 2, 58, 70, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_058[] = { 8, 0, 0, 16, 56, 16, 0, 0, 16, 56, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_059[] = { 8, 0, 0, 64, 48, 56, 0, 0, 16, 56, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_060[] = { 8, 0, 0, 0, 2, 4, 8, 16, 32, 16, 8, 4, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_061[] = { 8, 0, 0, 0, 0, 0,126, 0, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_062[] = { 8, 0, 0, 0, 64, 32, 16, 8, 4, 8, 16, 32, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_063[] = { 8, 0, 0, 0, 8, 0, 8, 8, 4, 2, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_064[] = { 8, 0, 0, 0, 60, 64, 74, 86, 82, 78, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_065[] = { 8, 0, 0, 0, 66, 66, 66,126, 66, 66, 66, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_066[] = { 8, 0, 0, 0,252, 66, 66, 66,124, 66, 66, 66,252, 0, 0}; +static const GLubyte Fixed8x13_Character_067[] = { 8, 0, 0, 0, 60, 66, 64, 64, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_068[] = { 8, 0, 0, 0,252, 66, 66, 66, 66, 66, 66, 66,252, 0, 0}; +static const GLubyte Fixed8x13_Character_069[] = { 8, 0, 0, 0,126, 64, 64, 64,120, 64, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_070[] = { 8, 0, 0, 0, 64, 64, 64, 64,120, 64, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_071[] = { 8, 0, 0, 0, 58, 70, 66, 78, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_072[] = { 8, 0, 0, 0, 66, 66, 66, 66,126, 66, 66, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_073[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 16,124, 0, 0}; +static const GLubyte Fixed8x13_Character_074[] = { 8, 0, 0, 0, 56, 68, 4, 4, 4, 4, 4, 4, 31, 0, 0}; +static const GLubyte Fixed8x13_Character_075[] = { 8, 0, 0, 0, 66, 68, 72, 80, 96, 80, 72, 68, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_076[] = { 8, 0, 0, 0,126, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_077[] = { 8, 0, 0, 0,130,130,130,146,146,170,198,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_078[] = { 8, 0, 0, 0, 66, 66, 66, 70, 74, 82, 98, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_079[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_080[] = { 8, 0, 0, 0, 64, 64, 64, 64,124, 66, 66, 66,124, 0, 0}; +static const GLubyte Fixed8x13_Character_081[] = { 8, 0, 0, 2, 60, 74, 82, 66, 66, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_082[] = { 8, 0, 0, 0, 66, 68, 72, 80,124, 66, 66, 66,124, 0, 0}; +static const GLubyte Fixed8x13_Character_083[] = { 8, 0, 0, 0, 60, 66, 2, 2, 60, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_084[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16,254, 0, 0}; +static const GLubyte Fixed8x13_Character_085[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_086[] = { 8, 0, 0, 0, 16, 40, 40, 40, 68, 68, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_087[] = { 8, 0, 0, 0, 68,170,146,146,146,130,130,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_088[] = { 8, 0, 0, 0,130,130, 68, 40, 16, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_089[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_090[] = { 8, 0, 0, 0,126, 64, 64, 32, 16, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_091[] = { 8, 0, 0, 0, 60, 32, 32, 32, 32, 32, 32, 32, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_092[] = { 8, 0, 0, 0, 2, 2, 4, 8, 16, 32, 64,128,128, 0, 0}; +static const GLubyte Fixed8x13_Character_093[] = { 8, 0, 0, 0,120, 8, 8, 8, 8, 8, 8, 8,120, 0, 0}; +static const GLubyte Fixed8x13_Character_094[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 40, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_095[] = { 8, 0, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_096[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 24, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_097[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_098[] = { 8, 0, 0, 0, 92, 98, 66, 66, 98, 92, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_099[] = { 8, 0, 0, 0, 60, 66, 64, 64, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_100[] = { 8, 0, 0, 0, 58, 70, 66, 66, 70, 58, 2, 2, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_101[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_102[] = { 8, 0, 0, 0, 32, 32, 32, 32,124, 32, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_103[] = { 8, 0, 60, 66, 60, 64, 56, 68, 68, 58, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_104[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_105[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_106[] = { 8, 0, 56, 68, 68, 4, 4, 4, 4, 12, 0, 4, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_107[] = { 8, 0, 0, 0, 66, 68, 72,112, 72, 68, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_108[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 16, 48, 0, 0}; +static const GLubyte Fixed8x13_Character_109[] = { 8, 0, 0, 0,130,146,146,146,146,236, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_110[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_111[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_112[] = { 8, 0, 64, 64, 64, 92, 98, 66, 98, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_113[] = { 8, 0, 2, 2, 2, 58, 70, 66, 70, 58, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_114[] = { 8, 0, 0, 0, 32, 32, 32, 32, 34, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_115[] = { 8, 0, 0, 0, 60, 66, 12, 48, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_116[] = { 8, 0, 0, 0, 28, 34, 32, 32, 32,124, 32, 32, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_117[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_118[] = { 8, 0, 0, 0, 16, 40, 40, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_119[] = { 8, 0, 0, 0, 68,170,146,146,130,130, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_120[] = { 8, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_121[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_122[] = { 8, 0, 0, 0,126, 32, 16, 8, 4,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_123[] = { 8, 0, 0, 0, 14, 16, 16, 8, 48, 8, 16, 16, 14, 0, 0}; +static const GLubyte Fixed8x13_Character_124[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_125[] = { 8, 0, 0, 0,112, 8, 8, 16, 12, 16, 8, 8,112, 0, 0}; +static const GLubyte Fixed8x13_Character_126[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 84, 36, 0, 0}; +static const GLubyte Fixed8x13_Character_127[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_128[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_129[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_130[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_131[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_132[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_133[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_134[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_135[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_136[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_137[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_138[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_139[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_140[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_141[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_142[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_143[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_144[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_145[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_146[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_147[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_148[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_149[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_150[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_151[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_152[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_153[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_154[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_155[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_156[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_157[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_158[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_159[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_160[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_161[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 0, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_162[] = { 8, 0, 0, 0, 0, 16, 56, 84, 80, 80, 84, 56, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_163[] = { 8, 0, 0, 0,220, 98, 32, 32, 32,112, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_164[] = { 8, 0, 0, 0, 0, 66, 60, 36, 36, 60, 66, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_165[] = { 8, 0, 0, 0, 16, 16,124, 16,124, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_166[] = { 8, 0, 0, 0, 16, 16, 16, 16, 0, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_167[] = { 8, 0, 0, 0, 24, 36, 4, 24, 36, 36, 24, 32, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_168[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, 0, 0}; +static const GLubyte Fixed8x13_Character_169[] = { 8, 0, 0, 0, 0, 56, 68,146,170,162,170,146, 68, 56, 0}; +static const GLubyte Fixed8x13_Character_170[] = { 8, 0, 0, 0, 0, 0,124, 0, 60, 68, 60, 4, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_171[] = { 8, 0, 0, 0, 0, 18, 36, 72,144, 72, 36, 18, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_172[] = { 8, 0, 0, 0, 0, 2, 2, 2,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_173[] = { 8, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_174[] = { 8, 0, 0, 0, 0, 56, 68,170,178,170,170,146, 68, 56, 0}; +static const GLubyte Fixed8x13_Character_175[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 0}; +static const GLubyte Fixed8x13_Character_176[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 24, 36, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_177[] = { 8, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_178[] = { 8, 0, 0, 0, 0, 0, 0, 0,120, 64, 48, 8, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_179[] = { 8, 0, 0, 0, 0, 0, 0, 0, 48, 72, 8, 16, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_180[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_181[] = { 8, 0, 0, 64, 90,102, 66, 66, 66, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_182[] = { 8, 0, 0, 0, 20, 20, 20, 20, 52,116,116,116, 62, 0, 0}; +static const GLubyte Fixed8x13_Character_183[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_184[] = { 8, 0, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_185[] = { 8, 0, 0, 0, 0, 0, 0, 0,112, 32, 32, 32, 96, 32, 0}; +static const GLubyte Fixed8x13_Character_186[] = { 8, 0, 0, 0, 0, 0, 0,120, 0, 48, 72, 72, 48, 0, 0}; +static const GLubyte Fixed8x13_Character_187[] = { 8, 0, 0, 0, 0,144, 72, 36, 18, 36, 72,144, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_188[] = { 8, 0, 0, 0, 6, 26, 18, 10,230, 66, 64, 64,192, 64, 0}; +static const GLubyte Fixed8x13_Character_189[] = { 8, 0, 0, 0, 30, 16, 12, 2,242, 76, 64, 64,192, 64, 0}; +static const GLubyte Fixed8x13_Character_190[] = { 8, 0, 0, 0, 6, 26, 18, 10,102,146, 16, 32,144, 96, 0}; +static const GLubyte Fixed8x13_Character_191[] = { 8, 0, 0, 0, 60, 66, 66, 64, 32, 16, 16, 0, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_192[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_193[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_194[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_195[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_196[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_197[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 24, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_198[] = { 8, 0, 0, 0,158,144,144,240,156,144,144,144,110, 0, 0}; +static const GLubyte Fixed8x13_Character_199[] = { 8, 0, 16, 8, 60, 66, 64, 64, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_200[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_201[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_202[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_203[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_204[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_205[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_206[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_207[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_208[] = { 8, 0, 0, 0,120, 68, 66, 66,226, 66, 66, 68,120, 0, 0}; +static const GLubyte Fixed8x13_Character_209[] = { 8, 0, 0, 0,130,134,138,146,162,194,130, 0,152,100, 0}; +static const GLubyte Fixed8x13_Character_210[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_211[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_212[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_213[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0,152,100, 0}; +static const GLubyte Fixed8x13_Character_214[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_215[] = { 8, 0, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_216[] = { 8, 0, 0, 64, 60, 98, 82, 82, 82, 74, 74, 70, 60, 2, 0}; +static const GLubyte Fixed8x13_Character_217[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_218[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_219[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_220[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_221[] = { 8, 0, 0, 0, 16, 16, 16, 16, 40, 68, 68, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_222[] = { 8, 0, 0, 0, 64, 64, 64,124, 66, 66, 66,124, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_223[] = { 8, 0, 0, 0, 92, 66, 66, 76, 80, 72, 68, 68, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_224[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_225[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 8, 4, 0}; +static const GLubyte Fixed8x13_Character_226[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_227[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_228[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_229[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 24, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_230[] = { 8, 0, 0, 0,108,146,144,124, 18,108, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_231[] = { 8, 0, 16, 8, 60, 66, 64, 64, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_232[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_233[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_234[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_235[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_236[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_237[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 32, 16, 0}; +static const GLubyte Fixed8x13_Character_238[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_239[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_240[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 4, 40, 24, 36, 0}; +static const GLubyte Fixed8x13_Character_241[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_242[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_243[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_244[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_245[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_246[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_247[] = { 8, 0, 0, 0, 0, 16, 16, 0,124, 0, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_248[] = { 8, 0, 0, 64, 60, 98, 82, 74, 70, 60, 2, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_249[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_250[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_251[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_252[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_253[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_254[] = { 8, 0, 64, 64, 92, 98, 66, 66, 98, 92, 64, 64, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_255[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 36, 36, 0}; + +/* The font characters mapping: */ +static const GLubyte* Fixed8x13_Character_Map[] = {Fixed8x13_Character_000,Fixed8x13_Character_001,Fixed8x13_Character_002,Fixed8x13_Character_003,Fixed8x13_Character_004,Fixed8x13_Character_005,Fixed8x13_Character_006,Fixed8x13_Character_007,Fixed8x13_Character_008,Fixed8x13_Character_009,Fixed8x13_Character_010,Fixed8x13_Character_011,Fixed8x13_Character_012,Fixed8x13_Character_013,Fixed8x13_Character_014,Fixed8x13_Character_015, + Fixed8x13_Character_016,Fixed8x13_Character_017,Fixed8x13_Character_018,Fixed8x13_Character_019,Fixed8x13_Character_020,Fixed8x13_Character_021,Fixed8x13_Character_022,Fixed8x13_Character_023,Fixed8x13_Character_024,Fixed8x13_Character_025,Fixed8x13_Character_026,Fixed8x13_Character_027,Fixed8x13_Character_028,Fixed8x13_Character_029,Fixed8x13_Character_030,Fixed8x13_Character_031, + Fixed8x13_Character_032,Fixed8x13_Character_033,Fixed8x13_Character_034,Fixed8x13_Character_035,Fixed8x13_Character_036,Fixed8x13_Character_037,Fixed8x13_Character_038,Fixed8x13_Character_039,Fixed8x13_Character_040,Fixed8x13_Character_041,Fixed8x13_Character_042,Fixed8x13_Character_043,Fixed8x13_Character_044,Fixed8x13_Character_045,Fixed8x13_Character_046,Fixed8x13_Character_047, + Fixed8x13_Character_048,Fixed8x13_Character_049,Fixed8x13_Character_050,Fixed8x13_Character_051,Fixed8x13_Character_052,Fixed8x13_Character_053,Fixed8x13_Character_054,Fixed8x13_Character_055,Fixed8x13_Character_056,Fixed8x13_Character_057,Fixed8x13_Character_058,Fixed8x13_Character_059,Fixed8x13_Character_060,Fixed8x13_Character_061,Fixed8x13_Character_062,Fixed8x13_Character_063, + Fixed8x13_Character_064,Fixed8x13_Character_065,Fixed8x13_Character_066,Fixed8x13_Character_067,Fixed8x13_Character_068,Fixed8x13_Character_069,Fixed8x13_Character_070,Fixed8x13_Character_071,Fixed8x13_Character_072,Fixed8x13_Character_073,Fixed8x13_Character_074,Fixed8x13_Character_075,Fixed8x13_Character_076,Fixed8x13_Character_077,Fixed8x13_Character_078,Fixed8x13_Character_079, + Fixed8x13_Character_080,Fixed8x13_Character_081,Fixed8x13_Character_082,Fixed8x13_Character_083,Fixed8x13_Character_084,Fixed8x13_Character_085,Fixed8x13_Character_086,Fixed8x13_Character_087,Fixed8x13_Character_088,Fixed8x13_Character_089,Fixed8x13_Character_090,Fixed8x13_Character_091,Fixed8x13_Character_092,Fixed8x13_Character_093,Fixed8x13_Character_094,Fixed8x13_Character_095, + Fixed8x13_Character_096,Fixed8x13_Character_097,Fixed8x13_Character_098,Fixed8x13_Character_099,Fixed8x13_Character_100,Fixed8x13_Character_101,Fixed8x13_Character_102,Fixed8x13_Character_103,Fixed8x13_Character_104,Fixed8x13_Character_105,Fixed8x13_Character_106,Fixed8x13_Character_107,Fixed8x13_Character_108,Fixed8x13_Character_109,Fixed8x13_Character_110,Fixed8x13_Character_111, + Fixed8x13_Character_112,Fixed8x13_Character_113,Fixed8x13_Character_114,Fixed8x13_Character_115,Fixed8x13_Character_116,Fixed8x13_Character_117,Fixed8x13_Character_118,Fixed8x13_Character_119,Fixed8x13_Character_120,Fixed8x13_Character_121,Fixed8x13_Character_122,Fixed8x13_Character_123,Fixed8x13_Character_124,Fixed8x13_Character_125,Fixed8x13_Character_126,Fixed8x13_Character_032, + Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032, + Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032, + Fixed8x13_Character_160,Fixed8x13_Character_161,Fixed8x13_Character_162,Fixed8x13_Character_163,Fixed8x13_Character_164,Fixed8x13_Character_165,Fixed8x13_Character_166,Fixed8x13_Character_167,Fixed8x13_Character_168,Fixed8x13_Character_169,Fixed8x13_Character_170,Fixed8x13_Character_171,Fixed8x13_Character_172,Fixed8x13_Character_173,Fixed8x13_Character_174,Fixed8x13_Character_175, + Fixed8x13_Character_176,Fixed8x13_Character_177,Fixed8x13_Character_178,Fixed8x13_Character_179,Fixed8x13_Character_180,Fixed8x13_Character_181,Fixed8x13_Character_182,Fixed8x13_Character_183,Fixed8x13_Character_184,Fixed8x13_Character_185,Fixed8x13_Character_186,Fixed8x13_Character_187,Fixed8x13_Character_188,Fixed8x13_Character_189,Fixed8x13_Character_190,Fixed8x13_Character_191, + Fixed8x13_Character_192,Fixed8x13_Character_193,Fixed8x13_Character_194,Fixed8x13_Character_195,Fixed8x13_Character_196,Fixed8x13_Character_197,Fixed8x13_Character_198,Fixed8x13_Character_199,Fixed8x13_Character_200,Fixed8x13_Character_201,Fixed8x13_Character_202,Fixed8x13_Character_203,Fixed8x13_Character_204,Fixed8x13_Character_205,Fixed8x13_Character_206,Fixed8x13_Character_207, + Fixed8x13_Character_208,Fixed8x13_Character_209,Fixed8x13_Character_210,Fixed8x13_Character_211,Fixed8x13_Character_212,Fixed8x13_Character_213,Fixed8x13_Character_214,Fixed8x13_Character_215,Fixed8x13_Character_216,Fixed8x13_Character_217,Fixed8x13_Character_218,Fixed8x13_Character_219,Fixed8x13_Character_220,Fixed8x13_Character_221,Fixed8x13_Character_222,Fixed8x13_Character_223, + Fixed8x13_Character_224,Fixed8x13_Character_225,Fixed8x13_Character_226,Fixed8x13_Character_227,Fixed8x13_Character_228,Fixed8x13_Character_229,Fixed8x13_Character_230,Fixed8x13_Character_231,Fixed8x13_Character_232,Fixed8x13_Character_233,Fixed8x13_Character_234,Fixed8x13_Character_235,Fixed8x13_Character_236,Fixed8x13_Character_237,Fixed8x13_Character_238,Fixed8x13_Character_239, + Fixed8x13_Character_240,Fixed8x13_Character_241,Fixed8x13_Character_242,Fixed8x13_Character_243,Fixed8x13_Character_244,Fixed8x13_Character_245,Fixed8x13_Character_246,Fixed8x13_Character_247,Fixed8x13_Character_248,Fixed8x13_Character_249,Fixed8x13_Character_250,Fixed8x13_Character_251,Fixed8x13_Character_252,Fixed8x13_Character_253,Fixed8x13_Character_254,Fixed8x13_Character_255,NULL}; + +/* The font structure: */ +static const SFG_Font fgFontFixed8x13 = { "-misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1", 256, 14, Fixed8x13_Character_Map, 0, 3 }; + + +static void +util_font_draw_character(void *dst_mem, unsigned dst_stride, unsigned character) +{ + unsigned char *dst = (unsigned char*)dst_mem; + const SFG_Font *font = &fgFontFixed8x13; + unsigned width = font->Characters[character][0]; + unsigned bitmap_stride = (width + 7) / 8; + unsigned j,i; + const GLubyte *bitmap = font->Characters[character]+1 + bitmap_stride * (font->Height - 1); + + for (j = 0; j < font->Height; j++) { + for (i = 0; i < width; i++) { + dst[i] = bitmap[i/8] & (128 >> (i%8)) ? 0xff : 0; + } + dst += dst_stride; + bitmap -= bitmap_stride; + } +} + +static boolean +util_font_create_fixed_8x13(struct pipe_context *pipe, + struct util_font *out_font) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_resource tex_templ, *tex; + struct pipe_transfer *transfer = NULL; + char *map; + int i; + + if (!screen->is_format_supported(screen, PIPE_FORMAT_I8_UNORM, + PIPE_TEXTURE_RECT, 0, + PIPE_BIND_SAMPLER_VIEW)) { + return FALSE; + } + + memset(&tex_templ, 0, sizeof(tex_templ)); + tex_templ.target = PIPE_TEXTURE_RECT; + tex_templ.format = PIPE_FORMAT_I8_UNORM; + tex_templ.width0 = 128; + tex_templ.height0 = 256; + tex_templ.depth0 = 1; + tex_templ.array_size = 1; + tex_templ.usage = PIPE_USAGE_STATIC; + tex_templ.bind = PIPE_BIND_SAMPLER_VIEW; + + tex = screen->resource_create(screen, &tex_templ); + if (!tex) { + return FALSE; + } + + map = pipe_transfer_map(pipe, tex, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, + tex->width0, tex->height0, &transfer); + if (!map) { + pipe_resource_reference(&tex, NULL); + return FALSE; + } + + for (i = 0; i < 256; i++) { + int x = (i % 16) * 8; + int y = (i / 16) * 14; + + util_font_draw_character(map + y * transfer->stride + x, + transfer->stride, i); + } + + pipe_transfer_unmap(pipe, transfer); + + pipe_resource_reference(&out_font->texture, NULL); + out_font->texture = tex; + out_font->glyph_width = 8; + out_font->glyph_height = 14; + return TRUE; +} + + +boolean +util_font_create(struct pipe_context *pipe, enum util_font_name name, + struct util_font *out_font) +{ + switch (name) { + case UTIL_FONT_FIXED_8X13: + return util_font_create_fixed_8x13(pipe, out_font); + } + return FALSE; +} diff --git a/src/gallium/auxiliary/hud/font.h b/src/gallium/auxiliary/hud/font.h new file mode 100644 index 00000000000..cf1c8798403 --- /dev/null +++ b/src/gallium/auxiliary/hud/font.h @@ -0,0 +1,59 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef FONT_H +#define FONT_H + +#include "pipe/p_compiler.h" + +struct pipe_resource; +struct pipe_context; + +enum util_font_name { + UTIL_FONT_FIXED_8X13 +}; + +/* The font is stored in a RECT texture. There are 256 glyphs + * drawn in a 16x16 matrix. The texture coordinates of a glyph + * within the matrix should be calculated as follows: + * + * x1 = (glyph % 16) * glyph_width; + * y1 = (glyph / 16) * glyph_height; + * x2 = x1 + glyph_width; + * y2 = y1 + glyph_height; + */ +struct util_font { + struct pipe_resource *texture; + unsigned glyph_width; + unsigned glyph_height; +}; + +boolean +util_font_create(struct pipe_context *pipe, enum util_font_name name, + struct util_font *out_font); + +#endif diff --git a/src/gallium/auxiliary/hud/hud_context.c b/src/gallium/auxiliary/hud/hud_context.c new file mode 100644 index 00000000000..60355cabc77 --- /dev/null +++ b/src/gallium/auxiliary/hud/hud_context.c @@ -0,0 +1,993 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* This head-up display module can draw transparent graphs on top of what + * the app is rendering, visualizing various data like framerate, cpu load, + * performance counters, etc. It can be hook up into any state tracker. + * + * The HUD is controlled with the GALLIUM_HUD environment variable. + * Set GALLIUM_HUD=help for more info. + */ + +#include "hud/hud_context.h" +#include "hud/hud_private.h" +#include "hud/font.h" + +#include "cso_cache/cso_context.h" +#include "util/u_draw_quad.h" +#include "util/u_inlines.h" +#include "util/u_memory.h" +#include "util/u_math.h" +#include "util/u_simple_shaders.h" +#include "util/u_string.h" +#include "util/u_upload_mgr.h" +#include "tgsi/tgsi_text.h" +#include "tgsi/tgsi_dump.h" + + +struct hud_context { + struct pipe_context *pipe; + struct cso_context *cso; + struct u_upload_mgr *uploader; + + struct list_head pane_list; + + /* states */ + struct pipe_blend_state alpha_blend; + struct pipe_depth_stencil_alpha_state dsa; + void *fs_color, *fs_texture; + struct pipe_rasterizer_state rasterizer; + void *vs; + struct pipe_vertex_element velems[2]; + + /* font */ + struct util_font font; + struct pipe_sampler_view *font_sampler_view; + struct pipe_sampler_state font_sampler_state; + + /* VS constant buffer */ + struct { + float color[4]; + float two_div_fb_width; + float two_div_fb_height; + float translate[2]; + float scale[2]; + float padding[2]; + } constants; + struct pipe_constant_buffer constbuf; + + unsigned fb_width, fb_height; + + /* vertices for text and background drawing are accumulated here and then + * drawn all at once */ + struct vertex_queue { + float *vertices; + struct pipe_vertex_buffer vbuf; + unsigned max_num_vertices; + unsigned num_vertices; + } text, bg, whitelines; +}; + + +static void +hud_draw_colored_prims(struct hud_context *hud, unsigned prim, + float *buffer, unsigned num_vertices, + float r, float g, float b, float a, + int xoffset, int yoffset, float yscale) +{ + struct cso_context *cso = hud->cso; + struct pipe_vertex_buffer vbuffer = {0}; + + hud->constants.color[0] = r; + hud->constants.color[1] = g; + hud->constants.color[2] = b; + hud->constants.color[3] = a; + hud->constants.translate[0] = xoffset; + hud->constants.translate[1] = yoffset; + hud->constants.scale[0] = 1; + hud->constants.scale[1] = yscale; + cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); + + vbuffer.user_buffer = buffer; + vbuffer.stride = 2 * sizeof(float); + + cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), + 1, &vbuffer); + cso_set_fragment_shader_handle(hud->cso, hud->fs_color); + cso_draw_arrays(cso, prim, 0, num_vertices); +} + +static void +hud_draw_colored_quad(struct hud_context *hud, unsigned prim, + unsigned x1, unsigned y1, unsigned x2, unsigned y2, + float r, float g, float b, float a) +{ + float buffer[] = { + x1, y1, + x1, y2, + x2, y2, + x2, y1, + }; + + hud_draw_colored_prims(hud, prim, buffer, 4, r, g, b, a, 0, 0, 1); +} + +static void +hud_draw_background_quad(struct hud_context *hud, + unsigned x1, unsigned y1, unsigned x2, unsigned y2) +{ + float *vertices = hud->bg.vertices + hud->bg.num_vertices*2; + unsigned num = 0; + + assert(hud->bg.num_vertices + 4 <= hud->bg.max_num_vertices); + + vertices[num++] = x1; + vertices[num++] = y1; + + vertices[num++] = x1; + vertices[num++] = y2; + + vertices[num++] = x2; + vertices[num++] = y2; + + vertices[num++] = x2; + vertices[num++] = y1; + + hud->bg.num_vertices += num/2; +} + +static void +hud_draw_string(struct hud_context *hud, unsigned x, unsigned y, + const char *str, ...) +{ + char buf[256]; + char *s = buf; + float *vertices = hud->text.vertices + hud->text.num_vertices*4; + unsigned num = 0; + + va_list ap; + va_start(ap, str); + util_vsnprintf(buf, sizeof(buf), str, ap); + va_end(ap); + + if (!*s) + return; + + hud_draw_background_quad(hud, + x, y, + x + strlen(buf)*hud->font.glyph_width, + y + hud->font.glyph_height); + + while (*s) { + unsigned x1 = x; + unsigned y1 = y; + unsigned x2 = x + hud->font.glyph_width; + unsigned y2 = y + hud->font.glyph_height; + unsigned tx1 = (*s % 16) * hud->font.glyph_width; + unsigned ty1 = (*s / 16) * hud->font.glyph_height; + unsigned tx2 = tx1 + hud->font.glyph_width; + unsigned ty2 = ty1 + hud->font.glyph_height; + + if (*s == ' ') { + x += hud->font.glyph_width; + s++; + continue; + } + + assert(hud->text.num_vertices + num/4 + 4 <= hud->text.max_num_vertices); + + vertices[num++] = x1; + vertices[num++] = y1; + vertices[num++] = tx1; + vertices[num++] = ty1; + + vertices[num++] = x1; + vertices[num++] = y2; + vertices[num++] = tx1; + vertices[num++] = ty2; + + vertices[num++] = x2; + vertices[num++] = y2; + vertices[num++] = tx2; + vertices[num++] = ty2; + + vertices[num++] = x2; + vertices[num++] = y1; + vertices[num++] = tx2; + vertices[num++] = ty1; + + x += hud->font.glyph_width; + s++; + } + + hud->text.num_vertices += num/4; +} + +static void +number_to_human_readable(uint64_t num, boolean is_in_bytes, char *out) +{ + static const char *byte_units[] = + {"", " KB", " MB", " GB", " TB", " PB", " EB"}; + static const char *metric_units[] = + {"", " k", " M", " G", " T", " P", " E"}; + const char **units = is_in_bytes ? byte_units : metric_units; + double divisor = is_in_bytes ? 1024 : 1000; + int unit = 0; + double d = num; + + while (d > divisor) { + d /= divisor; + unit++; + } + + if (d >= 100 || d == (int)d) + sprintf(out, "%.0f%s", d, units[unit]); + else if (d >= 10 || d*10 == (int)(d*10)) + sprintf(out, "%.1f%s", d, units[unit]); + else + sprintf(out, "%.2f%s", d, units[unit]); +} + +static void +hud_draw_graph_line_strip(struct hud_context *hud, const struct hud_graph *gr, + unsigned xoffset, unsigned yoffset, float yscale) +{ + if (gr->num_vertices <= 1) + return; + + assert(gr->index <= gr->num_vertices); + + hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP, + gr->vertices, gr->index, + gr->color[0], gr->color[1], gr->color[2], 1, + xoffset + (gr->pane->max_num_vertices - gr->index - 1) * 2 - 1, + yoffset, yscale); + + if (gr->num_vertices <= gr->index) + return; + + hud_draw_colored_prims(hud, PIPE_PRIM_LINE_STRIP, + gr->vertices + gr->index*2, + gr->num_vertices - gr->index, + gr->color[0], gr->color[1], gr->color[2], 1, + xoffset - gr->index*2 - 1, yoffset, yscale); +} + +static void +hud_pane_accumulate_vertices(struct hud_context *hud, + const struct hud_pane *pane) +{ + struct hud_graph *gr; + float *line_verts = hud->whitelines.vertices + hud->whitelines.num_vertices*2; + unsigned i, num = 0; + char str[32]; + + /* draw background */ + hud_draw_background_quad(hud, + pane->x1, pane->y1, + pane->x2, pane->y2); + + /* draw numbers on the right-hand side */ + for (i = 0; i < 6; i++) { + unsigned x = pane->x2 + 2; + unsigned y = pane->inner_y1 + pane->inner_height * (5 - i) / 5 - + hud->font.glyph_height / 2; + + number_to_human_readable(pane->max_value * i / 5, + pane->uses_byte_units, str); + hud_draw_string(hud, x, y, str); + } + + /* draw info below the pane */ + i = 0; + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + unsigned x = pane->x1 + 2; + unsigned y = pane->y2 + 2 + i*hud->font.glyph_height; + + number_to_human_readable(gr->current_value, + pane->uses_byte_units, str); + hud_draw_string(hud, x, y, " %s: %s", gr->name, str); + i++; + } + + /* draw border */ + assert(hud->whitelines.num_vertices + num/2 + 8 <= hud->whitelines.max_num_vertices); + line_verts[num++] = pane->x1; + line_verts[num++] = pane->y1; + line_verts[num++] = pane->x2; + line_verts[num++] = pane->y1; + + line_verts[num++] = pane->x2; + line_verts[num++] = pane->y1; + line_verts[num++] = pane->x2; + line_verts[num++] = pane->y2; + + line_verts[num++] = pane->x1; + line_verts[num++] = pane->y2; + line_verts[num++] = pane->x2; + line_verts[num++] = pane->y2; + + line_verts[num++] = pane->x1; + line_verts[num++] = pane->y1; + line_verts[num++] = pane->x1; + line_verts[num++] = pane->y2; + + /* draw horizontal lines inside the graph */ + for (i = 0; i <= 5; i++) { + float y = round((pane->max_value * i / 5.0) * pane->yscale + pane->inner_y2); + + assert(hud->whitelines.num_vertices + num/2 + 2 <= hud->whitelines.max_num_vertices); + line_verts[num++] = pane->x1; + line_verts[num++] = y; + line_verts[num++] = pane->x2; + line_verts[num++] = y; + } + + hud->whitelines.num_vertices += num/2; +} + +static void +hud_pane_draw_colored_objects(struct hud_context *hud, + const struct hud_pane *pane) +{ + struct hud_graph *gr; + unsigned i; + + /* draw colored quads below the pane */ + i = 0; + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + unsigned x = pane->x1 + 2; + unsigned y = pane->y2 + 2 + i*hud->font.glyph_height; + + hud_draw_colored_quad(hud, PIPE_PRIM_QUADS, x + 1, y + 1, x + 12, y + 13, + gr->color[0], gr->color[1], gr->color[2], 1); + i++; + } + + /* draw the line strips */ + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + hud_draw_graph_line_strip(hud, gr, pane->inner_x1, pane->inner_y2, pane->yscale); + } +} + +static void +hud_alloc_vertices(struct hud_context *hud, struct vertex_queue *v, + unsigned num_vertices, unsigned stride) +{ + v->num_vertices = 0; + v->max_num_vertices = num_vertices; + v->vbuf.stride = stride; + u_upload_alloc(hud->uploader, 0, v->vbuf.stride * v->max_num_vertices, + &v->vbuf.buffer_offset, &v->vbuf.buffer, + (void**)&v->vertices); +} + +/** + * Draw the HUD to the texture \p tex. + * The texture is usually the back buffer being displayed. + */ +void +hud_draw(struct hud_context *hud, struct pipe_resource *tex) +{ + struct cso_context *cso = hud->cso; + struct pipe_context *pipe = hud->pipe; + struct pipe_framebuffer_state fb; + struct pipe_surface surf_templ, *surf; + struct pipe_viewport_state viewport; + const struct pipe_sampler_state *sampler_states[] = + { &hud->font_sampler_state }; + struct hud_pane *pane; + struct hud_graph *gr; + + hud->fb_width = tex->width0; + hud->fb_height = tex->height0; + hud->constants.two_div_fb_width = 2.0 / hud->fb_width; + hud->constants.two_div_fb_height = 2.0 / hud->fb_height; + + cso_save_framebuffer(cso); + cso_save_sample_mask(cso); + cso_save_blend(cso); + cso_save_depth_stencil_alpha(cso); + cso_save_fragment_shader(cso); + cso_save_sampler_views(cso, PIPE_SHADER_FRAGMENT); + cso_save_samplers(cso, PIPE_SHADER_FRAGMENT); + cso_save_rasterizer(cso); + cso_save_viewport(cso); + cso_save_stream_outputs(cso); + cso_save_geometry_shader(cso); + cso_save_vertex_shader(cso); + cso_save_vertex_elements(cso); + cso_save_aux_vertex_buffer_slot(cso); + cso_save_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); + cso_save_render_condition(cso); + + /* set states */ + memset(&surf_templ, 0, sizeof(surf_templ)); + surf_templ.format = tex->format; + surf = pipe->create_surface(pipe, tex, &surf_templ); + + memset(&fb, 0, sizeof(fb)); + fb.nr_cbufs = 1; + fb.cbufs[0] = surf; + fb.zsbuf = NULL; + fb.width = hud->fb_width; + fb.height = hud->fb_height; + + viewport.scale[0] = 0.5f * hud->fb_width; + viewport.scale[1] = 0.5f * hud->fb_height; + viewport.scale[2] = 1.0f; + viewport.scale[3] = 1.0f; + viewport.translate[0] = 0.5f * hud->fb_width; + viewport.translate[1] = 0.5f * hud->fb_height; + viewport.translate[2] = 0.0f; + viewport.translate[3] = 0.0f; + + cso_set_framebuffer(cso, &fb); + cso_set_sample_mask(cso, ~0); + cso_set_blend(cso, &hud->alpha_blend); + cso_set_depth_stencil_alpha(cso, &hud->dsa); + cso_set_rasterizer(cso, &hud->rasterizer); + cso_set_viewport(cso, &viewport); + cso_set_stream_outputs(cso, 0, NULL, 0); + cso_set_geometry_shader_handle(cso, NULL); + cso_set_vertex_shader_handle(cso, hud->vs); + cso_set_vertex_elements(cso, 2, hud->velems); + cso_set_render_condition(cso, NULL, 0); + cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1, + &hud->font_sampler_view); + cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, sampler_states); + cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); + + /* prepare vertex buffers */ + hud_alloc_vertices(hud, &hud->bg, 4 * 64, 2 * sizeof(float)); + hud_alloc_vertices(hud, &hud->whitelines, 4 * 256, 2 * sizeof(float)); + hud_alloc_vertices(hud, &hud->text, 4 * 512, 4 * sizeof(float)); + + /* prepare all graphs */ + LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { + LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) { + gr->query_new_value(gr); + } + + hud_pane_accumulate_vertices(hud, pane); + } + + /* draw accumulated vertices for background quads */ + cso_set_fragment_shader_handle(hud->cso, hud->fs_color); + + if (hud->bg.num_vertices) { + hud->constants.color[0] = 0; + hud->constants.color[1] = 0; + hud->constants.color[2] = 0; + hud->constants.color[3] = 0.666; + hud->constants.translate[0] = 0; + hud->constants.translate[1] = 0; + hud->constants.scale[0] = 1; + hud->constants.scale[1] = 1; + + cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); + cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1, + &hud->bg.vbuf); + cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices); + } + pipe_resource_reference(&hud->bg.vbuf.buffer, NULL); + + /* draw accumulated vertices for white lines */ + hud->constants.color[0] = 1; + hud->constants.color[1] = 1; + hud->constants.color[2] = 1; + hud->constants.color[3] = 1; + hud->constants.translate[0] = 0; + hud->constants.translate[1] = 0; + hud->constants.scale[0] = 1; + hud->constants.scale[1] = 1; + cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf); + + if (hud->whitelines.num_vertices) { + cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1, + &hud->whitelines.vbuf); + cso_set_fragment_shader_handle(hud->cso, hud->fs_color); + cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices); + } + pipe_resource_reference(&hud->whitelines.vbuf.buffer, NULL); + + /* draw accumulated vertices for text */ + if (hud->text.num_vertices) { + cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1, + &hud->text.vbuf); + cso_set_fragment_shader_handle(hud->cso, hud->fs_texture); + cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices); + } + pipe_resource_reference(&hud->text.vbuf.buffer, NULL); + + /* draw the rest */ + LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) { + if (pane) + hud_pane_draw_colored_objects(hud, pane); + } + + /* restore states */ + cso_restore_framebuffer(cso); + cso_restore_sample_mask(cso); + cso_restore_blend(cso); + cso_restore_depth_stencil_alpha(cso); + cso_restore_fragment_shader(cso); + cso_restore_sampler_views(cso, PIPE_SHADER_FRAGMENT); + cso_restore_samplers(cso, PIPE_SHADER_FRAGMENT); + cso_restore_rasterizer(cso); + cso_restore_viewport(cso); + cso_restore_stream_outputs(cso); + cso_restore_geometry_shader(cso); + cso_restore_vertex_shader(cso); + cso_restore_vertex_elements(cso); + cso_restore_aux_vertex_buffer_slot(cso); + cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_VERTEX); + cso_restore_render_condition(cso); + + pipe_surface_reference(&surf, NULL); +} + +/** + * Set the maximum value for the Y axis of the graph. + * This scales the graph accordingly. + */ +void +hud_pane_set_max_value(struct hud_pane *pane, uint64_t value) +{ + pane->max_value = value; + pane->yscale = -(int)pane->inner_height / (double)pane->max_value; +} + +static struct hud_pane * +hud_pane_create(unsigned x1, unsigned y1, unsigned x2, unsigned y2, + unsigned period, uint64_t max_value) +{ + struct hud_pane *pane = CALLOC_STRUCT(hud_pane); + + if (!pane) + return NULL; + + pane->x1 = x1; + pane->y1 = y1; + pane->x2 = x2; + pane->y2 = y2; + pane->inner_x1 = x1 + 1; + pane->inner_x2 = x2 - 1; + pane->inner_y1 = y1 + 1; + pane->inner_y2 = y2 - 1; + pane->inner_width = pane->inner_x2 - pane->inner_x1; + pane->inner_height = pane->inner_y2 - pane->inner_y1; + pane->period = period; + pane->max_num_vertices = (x2 - x1 + 2) / 2; + hud_pane_set_max_value(pane, max_value); + LIST_INITHEAD(&pane->graph_list); + return pane; +} + +/** + * Add a graph to an existing pane. + * One pane can contain multiple graphs over each other. + */ +void +hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr) +{ + static const float colors[][3] = { + {0, 1, 0}, + {1, 0, 0}, + {0, 1, 1}, + {1, 0, 1}, + {1, 1, 0}, + {0.5, 0.5, 1}, + {0.5, 0.5, 0.5}, + }; + char *name = gr->name; + + /* replace '-' with a space */ + while (*name) { + if (*name == '-') + *name = ' '; + name++; + } + + assert(pane->num_graphs < Elements(colors)); + gr->vertices = malloc(pane->max_num_vertices * sizeof(float) * 2); + gr->color[0] = colors[pane->num_graphs][0]; + gr->color[1] = colors[pane->num_graphs][1]; + gr->color[2] = colors[pane->num_graphs][2]; + gr->pane = pane; + LIST_ADDTAIL(&gr->head, &pane->graph_list); + pane->num_graphs++; +} + +void +hud_graph_add_value(struct hud_graph *gr, uint64_t value) +{ + if (gr->index == gr->pane->max_num_vertices) { + gr->vertices[0] = 0; + gr->vertices[1] = gr->vertices[(gr->index-1)*2+1]; + gr->index = 1; + } + gr->vertices[(gr->index)*2+0] = gr->index*2; + gr->vertices[(gr->index)*2+1] = value; + gr->index++; + + if (gr->num_vertices < gr->pane->max_num_vertices) { + gr->num_vertices++; + } + + gr->current_value = value; + if (value > gr->pane->max_value) { + hud_pane_set_max_value(gr->pane, value); + } +} + +static void +hud_graph_destroy(struct hud_graph *graph) +{ + FREE(graph->vertices); + if (graph->free_query_data) + graph->free_query_data(graph->query_data); + FREE(graph); +} + +/** + * Read a string from the environment variable. + * The separators "+", ",", ":", and ";" terminate the string. + * Return the number of read characters. + */ +static int +parse_string(const char *s, char *out) +{ + int i; + + for (i = 0; *s && *s != '+' && *s != ',' && *s != ':' && *s != ';'; + s++, out++, i++) + *out = *s; + + *out = 0; + + if (*s && !i) + fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) while " + "parsing a string\n", *s, *s); + return i; +} + +static boolean +has_occlusion_query(struct pipe_screen *screen) +{ + return screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY) != 0; +} + +static boolean +has_streamout(struct pipe_screen *screen) +{ + return screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0; +} + +static void +hud_parse_env_var(struct hud_context *hud, const char *env) +{ + unsigned num, i; + char name[256], s[256]; + struct hud_pane *pane = NULL; + unsigned x = 10, y = 10; + unsigned width = 251, height = 100; + + while ((num = parse_string(env, name)) != 0) { + env += num; + + if (!pane) { + pane = hud_pane_create(x, y, x + width, y + height, 40000, 10); + if (!pane) + return; + } + + /* add a graph */ + if (strcmp(name, "fps") == 0) { + hud_fps_graph_install(pane); + } + else if (strcmp(name, "cpu") == 0) { + hud_cpu_graph_install(pane, ALL_CPUS); + } + else if (sscanf(name, "cpu%u%s", &i, s) == 1) { + hud_cpu_graph_install(pane, i); + } + else if (strcmp(name, "pixels-rendered") == 0 && + has_occlusion_query(hud->pipe->screen)) { + hud_pipe_query_install(pane, hud->pipe, "pixels-rendered", + PIPE_QUERY_OCCLUSION_COUNTER, 0, FALSE); + } + else if (strcmp(name, "primitives-generated") == 0 && + has_streamout(hud->pipe->screen)) { + hud_pipe_query_install(pane, hud->pipe, "primitives-generated", + PIPE_QUERY_PRIMITIVES_GENERATED, 0, FALSE); + } + else { + if (!hud_driver_query_install(pane, hud->pipe, name)){ + fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name); + } + } + + if (*env == ':') { + env++; + + if (!pane) { + fprintf(stderr, "gallium_hud: syntax error: unexpected ':', " + "expected a name\n"); + break; + } + + num = parse_string(env, s); + env += num; + + if (num && sscanf(s, "%u", &i) == 1) { + hud_pane_set_max_value(pane, i); + } + else { + fprintf(stderr, "gallium_hud: syntax error: unexpected '%c' (%i) " + "after ':'\n", *env, *env); + } + } + + if (*env == 0) + break; + + /* parse a separator */ + switch (*env) { + case '+': + env++; + break; + + case ',': + env++; + y += height + hud->font.glyph_height * (pane->num_graphs + 2); + + if (pane && pane->num_graphs) { + LIST_ADDTAIL(&pane->head, &hud->pane_list); + pane = NULL; + } + break; + + case ';': + env++; + y = 10; + x += width + hud->font.glyph_width * 7; + + if (pane && pane->num_graphs) { + LIST_ADDTAIL(&pane->head, &hud->pane_list); + pane = NULL; + } + break; + + default: + fprintf(stderr, "gallium_hud: syntax error: unexpected '%c'\n", *env); + } + } + + if (pane) { + if (pane->num_graphs) { + LIST_ADDTAIL(&pane->head, &hud->pane_list); + } + else { + FREE(pane); + } + } +} + +static void +print_help(struct pipe_screen *screen) +{ + int i, num_queries, num_cpus = hud_get_num_cpus(); + + puts("Syntax: GALLIUM_HUD=name1[+name2][...][:value1][,nameI...][;nameJ...]"); + puts(""); + puts(" Names are identifiers of data sources which will be drawn as graphs"); + puts(" in panes. Multiple graphs can be drawn in the same pane."); + puts(" There can be multiple panes placed in rows and columns."); + puts(""); + puts(" '+' separates names which will share a pane."); + puts(" ':[value]' specifies the initial maximum value of the Y axis"); + puts(" for the given pane."); + puts(" ',' creates a new pane below the last one."); + puts(" ';' creates a new pane at the top of the next column."); + puts(""); + puts(" Example: GALLIUM_HUD=\"cpu,fps;primitives-generated\""); + puts(""); + puts(" Available names:"); + puts(" fps"); + puts(" cpu"); + + for (i = 0; i < num_cpus; i++) + printf(" cpu%i\n", i); + + if (has_occlusion_query(screen)) + puts(" pixels-rendered"); + if (has_streamout(screen)) + puts(" primitives-generated"); + + if (screen->get_driver_query_info){ + struct pipe_driver_query_info info; + num_queries = screen->get_driver_query_info(screen, 0, NULL); + + for (i = 0; i < num_queries; i++){ + screen->get_driver_query_info(screen, i, &info); + printf(" %s\n", info.name); + } + } + + puts(""); +} + +struct hud_context * +hud_create(struct pipe_context *pipe, struct cso_context *cso) +{ + struct hud_context *hud; + struct pipe_sampler_view view_templ; + unsigned i; + const char *env = debug_get_option("GALLIUM_HUD", NULL); + + if (!env || !*env) + return NULL; + + if (strcmp(env, "help") == 0) { + print_help(pipe->screen); + return NULL; + } + + hud = CALLOC_STRUCT(hud_context); + if (!hud) + return NULL; + + hud->pipe = pipe; + hud->cso = cso; + hud->uploader = u_upload_create(pipe, 256 * 1024, 16, + PIPE_BIND_VERTEX_BUFFER); + + /* font */ + if (!util_font_create(pipe, UTIL_FONT_FIXED_8X13, &hud->font)) { + u_upload_destroy(hud->uploader); + FREE(hud); + return NULL; + } + + /* blend state */ + hud->alpha_blend.rt[0].colormask = PIPE_MASK_RGBA; + hud->alpha_blend.rt[0].blend_enable = 1; + hud->alpha_blend.rt[0].rgb_func = PIPE_BLEND_ADD; + hud->alpha_blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + hud->alpha_blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + hud->alpha_blend.rt[0].alpha_func = PIPE_BLEND_ADD; + hud->alpha_blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; + hud->alpha_blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + + /* fragment shader */ + hud->fs_color = + util_make_fragment_passthrough_shader(pipe, + TGSI_SEMANTIC_COLOR, + TGSI_INTERPOLATE_CONSTANT); + + hud->fs_texture = + util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_RECT, + TGSI_INTERPOLATE_PERSPECTIVE); + + /* rasterizer */ + hud->rasterizer.gl_rasterization_rules = 1; + hud->rasterizer.depth_clip = 1; + hud->rasterizer.line_width = 1; + hud->rasterizer.line_last_pixel = 1; + + /* vertex shader */ + { + static const char *vertex_shader_text = { + "VERT\n" + "DCL IN[0..1]\n" + "DCL OUT[0], POSITION\n" + "DCL OUT[1], COLOR[0]\n" /* color */ + "DCL OUT[2], GENERIC[0]\n" /* texcoord */ + /* [0] = color, + * [1] = (2/fb_width, 2/fb_height, xoffset, yoffset) + * [2] = (xscale, yscale, 0, 0) */ + "DCL CONST[0..2]\n" + "DCL TEMP[0]\n" + "IMM[0] FLT32 { -1, 0, 0, 1 }\n" + + /* v = in * (xscale, yscale) + (xoffset, yoffset) */ + "MAD TEMP[0].xy, IN[0], CONST[2].xyyy, CONST[1].zwww\n" + /* pos = v * (2 / fb_width, 2 / fb_height) - (1, 1) */ + "MAD OUT[0].xy, TEMP[0], CONST[1].xyyy, IMM[0].xxxx\n" + "MOV OUT[0].zw, IMM[0]\n" + + "MOV OUT[1], CONST[0]\n" + "MOV OUT[2], IN[1]\n" + "END\n" + }; + + struct tgsi_token tokens[1000]; + struct pipe_shader_state state = {tokens}; + + if (!tgsi_text_translate(vertex_shader_text, tokens, Elements(tokens))) { + assert(0); + pipe_resource_reference(&hud->font.texture, NULL); + u_upload_destroy(hud->uploader); + FREE(hud); + return NULL; + } + + hud->vs = pipe->create_vs_state(pipe, &state); + } + + /* vertex elements */ + for (i = 0; i < 2; i++) { + hud->velems[i].src_offset = i * 2 * sizeof(float); + hud->velems[i].src_format = PIPE_FORMAT_R32G32_FLOAT; + hud->velems[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso); + } + + /* sampler view */ + memset(&view_templ, 0, sizeof(view_templ)); + view_templ.format = hud->font.texture->format; + view_templ.swizzle_r = PIPE_SWIZZLE_RED; + view_templ.swizzle_g = PIPE_SWIZZLE_GREEN; + view_templ.swizzle_b = PIPE_SWIZZLE_BLUE; + view_templ.swizzle_a = PIPE_SWIZZLE_ALPHA; + hud->font_sampler_view = pipe->create_sampler_view(pipe, hud->font.texture, + &view_templ); + + /* constants */ + hud->constbuf.buffer_size = sizeof(hud->constants); + hud->constbuf.user_buffer = &hud->constants; + + LIST_INITHEAD(&hud->pane_list); + + hud_parse_env_var(hud, env); + return hud; +} + +void +hud_destroy(struct hud_context *hud) +{ + struct pipe_context *pipe = hud->pipe; + struct hud_pane *pane, *pane_tmp; + struct hud_graph *graph, *graph_tmp; + + LIST_FOR_EACH_ENTRY_SAFE(pane, pane_tmp, &hud->pane_list, head) { + LIST_FOR_EACH_ENTRY_SAFE(graph, graph_tmp, &pane->graph_list, head) { + LIST_DEL(&graph->head); + hud_graph_destroy(graph); + } + LIST_DEL(&pane->head); + FREE(pane); + } + + pipe->delete_fs_state(pipe, hud->fs_color); + pipe->delete_fs_state(pipe, hud->fs_texture); + pipe->delete_vs_state(pipe, hud->vs); + pipe_sampler_view_reference(&hud->font_sampler_view, NULL); + pipe_resource_reference(&hud->font.texture, NULL); + u_upload_destroy(hud->uploader); + FREE(hud); +} diff --git a/src/gallium/auxiliary/hud/hud_context.h b/src/gallium/auxiliary/hud/hud_context.h new file mode 100644 index 00000000000..abf2ad58642 --- /dev/null +++ b/src/gallium/auxiliary/hud/hud_context.h @@ -0,0 +1,45 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef HUD_CONTEXT_H +#define HUD_CONTEXT_H + +struct hud_context; +struct cso_context; +struct pipe_context; +struct pipe_resource; + +struct hud_context * +hud_create(struct pipe_context *pipe, struct cso_context *cso); + +void +hud_destroy(struct hud_context *hud); + +void +hud_draw(struct hud_context *hud, struct pipe_resource *tex); + +#endif diff --git a/src/gallium/auxiliary/hud/hud_cpu.c b/src/gallium/auxiliary/hud/hud_cpu.c new file mode 100644 index 00000000000..dfd9f686920 --- /dev/null +++ b/src/gallium/auxiliary/hud/hud_cpu.c @@ -0,0 +1,164 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* This file contains code for reading CPU load for displaying on the HUD. + */ + +#include "hud/hud_private.h" +#include "os/os_time.h" +#include "util/u_memory.h" +#include <stdio.h> + +static boolean +get_cpu_stats(unsigned cpu_index, uint64_t *busy_time, uint64_t *total_time) +{ + char cpuname[32]; + char line[1024]; + FILE *f; + + if (cpu_index == ALL_CPUS) + strcpy(cpuname, "cpu"); + else + sprintf(cpuname, "cpu%u", cpu_index); + + f = fopen("/proc/stat", "r"); + if (!f) + return FALSE; + + while (!feof(f) && fgets(line, sizeof(line), f)) { + if (strstr(line, cpuname) == line) { + uint64_t v[12]; + int i, num; + + num = sscanf(line, + "%s %llu %llu %llu %llu %llu %llu %llu %llu %llu " + "%llu %llu %llu", + cpuname, &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], + &v[6], &v[7], &v[8], &v[9], &v[10], &v[11]); + if (num < 5) { + fclose(f); + return FALSE; + } + + /* user + nice + system */ + *busy_time = v[0] + v[1] + v[2]; + *total_time = *busy_time; + + /* ... + idle + iowait + irq + softirq + ... */ + for (i = 3; i < num-1; i++) { + *total_time += v[i]; + } + fclose(f); + return TRUE; + } + } + fclose(f); + return FALSE; +} + +struct cpu_info { + unsigned cpu_index; + uint64_t last_cpu_busy, last_cpu_total, last_time; +}; + +static void +query_cpu_load(struct hud_graph *gr) +{ + struct cpu_info *info = gr->query_data; + uint64_t now = os_time_get(); + + if (info->last_time) { + if (info->last_time + gr->pane->period <= now) { + uint64_t cpu_busy, cpu_total, cpu_load; + + get_cpu_stats(info->cpu_index, &cpu_busy, &cpu_total); + + cpu_load = (cpu_busy - info->last_cpu_busy) * 100 / + (double)(cpu_total - info->last_cpu_total); + hud_graph_add_value(gr, cpu_load); + + info->last_cpu_busy = cpu_busy; + info->last_cpu_total = cpu_total; + info->last_time = now; + } + } + else { + /* initialize */ + info->last_time = now; + get_cpu_stats(info->cpu_index, &info->last_cpu_busy, + &info->last_cpu_total); + } +} + +void +hud_cpu_graph_install(struct hud_pane *pane, unsigned cpu_index) +{ + struct hud_graph *gr; + struct cpu_info *info; + uint64_t busy, total; + + /* see if the cpu exists */ + if (cpu_index != ALL_CPUS && !get_cpu_stats(cpu_index, &busy, &total)) { + return; + } + + gr = CALLOC_STRUCT(hud_graph); + if (!gr) + return; + + if (cpu_index == ALL_CPUS) + strcpy(gr->name, "cpu"); + else + sprintf(gr->name, "cpu%u", cpu_index); + + gr->query_data = CALLOC_STRUCT(cpu_info); + if (!gr->query_data) { + FREE(gr); + return; + } + + gr->query_new_value = query_cpu_load; + gr->free_query_data = free; + + info = gr->query_data; + info->cpu_index = cpu_index; + + hud_pane_add_graph(pane, gr); + hud_pane_set_max_value(pane, 100); +} + +int +hud_get_num_cpus(void) +{ + uint64_t busy, total; + int i = 0; + + while (get_cpu_stats(i, &busy, &total)) + i++; + + return i; +} diff --git a/src/gallium/auxiliary/hud/hud_driver_query.c b/src/gallium/auxiliary/hud/hud_driver_query.c new file mode 100644 index 00000000000..798da50e57c --- /dev/null +++ b/src/gallium/auxiliary/hud/hud_driver_query.c @@ -0,0 +1,207 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* This file contains code for reading values from pipe queries + * for displaying on the HUD. To prevent stalls when reading queries, we + * keep a list of busy queries in a ring. We read only those queries which + * are idle. + */ + +#include "hud/hud_private.h" +#include "pipe/p_screen.h" +#include "os/os_time.h" +#include "util/u_memory.h" +#include <stdio.h> + +#define NUM_QUERIES 8 + +struct query_info { + struct pipe_context *pipe; + unsigned query_type; + + /* Ring of queries. If a query is busy, we use another slot. */ + struct pipe_query *query[NUM_QUERIES]; + unsigned head, tail; + unsigned num_queries; + + uint64_t last_time; + uint64_t results_cumulative; + unsigned num_results; +}; + +static void +query_new_value(struct hud_graph *gr) +{ + struct query_info *info = gr->query_data; + struct pipe_context *pipe = info->pipe; + uint64_t now = os_time_get(); + + if (info->last_time) { + pipe->end_query(pipe, info->query[info->head]); + + /* read query results */ + while (1) { + struct pipe_query *query = info->query[info->tail]; + union pipe_query_result result; + result.u64 = 0; + + if (pipe->get_query_result(pipe, query, FALSE, &result)) { + info->results_cumulative += result.u64; + info->num_results++; + + if (info->tail == info->head) + break; + + info->tail = (info->tail+1) % NUM_QUERIES; + } + else { + /* the oldest query is busy */ + if ((info->head+1) % NUM_QUERIES == info->tail) { + /* all queries are busy, throw away the last query and create + * a new one */ + fprintf(stderr, + "gallium_hud: all queries are busy after %i frames, " + "can't add another query\n", + NUM_QUERIES); + pipe->destroy_query(pipe, info->query[info->head]); + info->query[info->head] = + pipe->create_query(pipe, info->query_type); + } + else { + /* the last query is busy, we need to add a new one we can use + * for this frame */ + info->head = (info->head+1) % NUM_QUERIES; + if (!info->query[info->head]) { + info->query[info->head] = + pipe->create_query(pipe, info->query_type); + } + } + break; + } + } + + if (info->num_results && info->last_time + gr->pane->period <= now) { + /* compute the average value across all frames */ + hud_graph_add_value(gr, info->results_cumulative / info->num_results); + + info->last_time = now; + info->results_cumulative = 0; + info->num_results = 0; + } + + pipe->begin_query(pipe, info->query[info->head]); + } + else { + /* initialize */ + info->last_time = now; + info->query[info->head] = pipe->create_query(pipe, info->query_type); + pipe->begin_query(pipe, info->query[info->head]); + } +} + +static void +free_query_info(void *ptr) +{ + struct query_info *info = ptr; + + if (info->last_time) { + struct pipe_context *pipe = info->pipe; + int i; + + pipe->end_query(pipe, info->query[info->head]); + + for (i = 0; i < Elements(info->query); i++) { + if (info->query[i]) { + pipe->destroy_query(pipe, info->query[i]); + } + } + } + FREE(info); +} + +void +hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe, + const char *name, unsigned query_type, + uint64_t max_value, boolean uses_byte_units) +{ + struct hud_graph *gr; + struct query_info *info; + + gr = CALLOC_STRUCT(hud_graph); + if (!gr) + return; + + strcpy(gr->name, name); + gr->query_data = CALLOC_STRUCT(query_info); + if (!gr->query_data) { + FREE(gr); + return; + } + + gr->query_new_value = query_new_value; + gr->free_query_data = free_query_info; + + info = gr->query_data; + info->pipe = pipe; + info->query_type = query_type; + + hud_pane_add_graph(pane, gr); + if (pane->max_value < max_value) + hud_pane_set_max_value(pane, max_value); + if (uses_byte_units) + pane->uses_byte_units = TRUE; +} + +boolean +hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe, + const char *name) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_driver_query_info query; + unsigned num_queries, i; + boolean found = FALSE; + + if (!screen->get_driver_query_info) + return FALSE; + + num_queries = screen->get_driver_query_info(screen, 0, NULL); + + for (i = 0; i < num_queries; i++) { + if (screen->get_driver_query_info(screen, i, &query) && + strcmp(query.name, name) == 0) { + found = TRUE; + break; + } + } + + if (!found) + return FALSE; + + hud_pipe_query_install(pane, pipe, query.name, query.query_type, + query.max_value, query.uses_byte_units); + return TRUE; +} diff --git a/src/gallium/auxiliary/hud/hud_fps.c b/src/gallium/auxiliary/hud/hud_fps.c new file mode 100644 index 00000000000..71cdfd04ee7 --- /dev/null +++ b/src/gallium/auxiliary/hud/hud_fps.c @@ -0,0 +1,81 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* This file contains code for calculating framerate for displaying on the HUD. + */ + +#include "hud/hud_private.h" +#include "os/os_time.h" +#include "util/u_memory.h" + +struct fps_info { + int frames; + uint64_t last_time; +}; + +static void +query_fps(struct hud_graph *gr) +{ + struct fps_info *info = gr->query_data; + uint64_t now = os_time_get(); + + info->frames++; + + if (info->last_time) { + if (info->last_time + gr->pane->period <= now) { + double fps = info->frames * 1000000 / (double)(now - info->last_time); + info->frames = 0; + info->last_time = now; + + hud_graph_add_value(gr, fps); + } + } + else { + info->last_time = now; + } +} + +void +hud_fps_graph_install(struct hud_pane *pane) +{ + struct hud_graph *gr = CALLOC_STRUCT(hud_graph); + + if (!gr) + return; + + strcpy(gr->name, "fps"); + gr->query_data = CALLOC_STRUCT(fps_info); + if (!gr->query_data) { + FREE(gr); + return; + } + + gr->query_new_value = query_fps; + gr->free_query_data = free; + + hud_pane_add_graph(pane, gr); +} diff --git a/src/gallium/auxiliary/hud/hud_private.h b/src/gallium/auxiliary/hud/hud_private.h new file mode 100644 index 00000000000..4c97791c635 --- /dev/null +++ b/src/gallium/auxiliary/hud/hud_private.h @@ -0,0 +1,91 @@ +/************************************************************************** + * + * Copyright 2013 Marek Olšák <[email protected]> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef HUD_PRIVATE_H +#define HUD_PRIVATE_H + +#include "pipe/p_context.h" +#include "util/u_double_list.h" + +struct hud_graph { + /* initialized by common code */ + struct list_head head; + struct hud_pane *pane; + float color[3]; + float *vertices; /* ring buffer of vertices */ + + /* name and query */ + char name[128]; + void *query_data; + void (*query_new_value)(struct hud_graph *gr); + void (*free_query_data)(void *ptr); + + /* mutable variables */ + unsigned num_vertices; + unsigned index; /* vertex index being updated */ + uint64_t current_value; +}; + +struct hud_pane { + struct list_head head; + unsigned x1, y1, x2, y2; + unsigned inner_x1; + unsigned inner_y1; + unsigned inner_x2; + unsigned inner_y2; + unsigned inner_width; + unsigned inner_height; + float yscale; + unsigned max_num_vertices; + uint64_t max_value; + boolean uses_byte_units; + uint64_t period; /* in microseconds */ + + struct list_head graph_list; + unsigned num_graphs; +}; + + +/* core */ +void hud_pane_add_graph(struct hud_pane *pane, struct hud_graph *gr); +void hud_pane_set_max_value(struct hud_pane *pane, uint64_t value); +void hud_graph_add_value(struct hud_graph *gr, uint64_t value); + +/* graphs/queries */ +#define ALL_CPUS ~0 /* optionally set as cpu_index */ + +int hud_get_num_cpus(void); + +void hud_fps_graph_install(struct hud_pane *pane); +void hud_cpu_graph_install(struct hud_pane *pane, unsigned cpu_index); +void hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe, + const char *name, unsigned query_type, + uint64_t max_value, boolean uses_byte_units); +boolean hud_driver_query_install(struct hud_pane *pane, + struct pipe_context *pipe, const char *name); + +#endif |