1/*
2 * Copyright © 2020 Google, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include <getopt.h>
25#include <stdbool.h>
26
27static bool bin_debug = false;
28#define BIN_DEBUG bin_debug
29
30#include "freedreno_gmem.c"
31
32/* NOTE, non-interesting gmem keys (ie. things that are small enough to fit
33 * in a single bin) are commented out, but retained for posterity.
34 */
35/* clang-format off */
36static const struct gmem_key keys[] = {
37   { .minx=0, .miny=0, .width=1536, .height=2048, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {1,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
38   /* manhattan: */
39   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
40   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
41// { .minx=0, .miny=0, .width=64, .height=64, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
42// { .minx=0, .miny=0, .width=32, .height=32, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
43// { .minx=0, .miny=0, .width=16, .height=16, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
44// { .minx=0, .miny=0, .width=8, .height=8, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
45// { .minx=0, .miny=0, .width=4, .height=4, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
46// { .minx=0, .miny=0, .width=2, .height=2, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
47// { .minx=0, .miny=0, .width=1, .height=1, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
48   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=4, .cbuf_cpp = {4,4,4,4,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
49// { .minx=0, .miny=0, .width=64, .height=64, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {2,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
50   { .minx=0, .miny=0, .width=1024, .height=1024, .gmem_page_align=1, .nr_cbufs=0, .cbuf_cpp = {0,0,0,0,0,0,0,0,}, .zsbuf_cpp = {2,0,}},
51   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=0, .cbuf_cpp = {0,0,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
52   { .minx=0, .miny=0, .width=960, .height=540, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
53   { .minx=0, .miny=0, .width=480, .height=270, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
54// { .minx=0, .miny=0, .width=240, .height=135, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
55// { .minx=0, .miny=0, .width=120, .height=67, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
56
57   /* trex: */
58   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
59   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
60   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {2,0,}},
61   { .minx=0, .miny=0, .width=960, .height=540, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {2,0,0,0,0,0,0,0,}, .zsbuf_cpp = {2,0,}},
62   { .minx=0, .miny=0, .width=1024, .height=1024, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {2,0,}},
63// { .minx=0, .miny=0, .width=64, .height=64, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {2,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
64
65   /* supertuxkart: */
66   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
67   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {2,0,}},
68   { .minx=0, .miny=0, .width=810, .height=810, .gmem_page_align=1, .nr_cbufs=2, .cbuf_cpp = {4,4,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
69// { .minx=0, .miny=0, .width=405, .height=405, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {2,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
70   { .minx=0, .miny=0, .width=405, .height=405, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {8,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
71   { .minx=0, .miny=0, .width=810, .height=810, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {8,0,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
72   { .minx=0, .miny=0, .width=810, .height=810, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
73   { .minx=0, .miny=0, .width=810, .height=810, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
74   { .minx=0, .miny=0, .width=960, .height=540, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {2,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
75   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {8,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
76   { .minx=0, .miny=0, .width=960, .height=540, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {8,0,0,0,0,0,0,0,}, .zsbuf_cpp = {0,0,}},
77   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=2, .cbuf_cpp = {4,4,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
78   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {8,0,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
79   { .minx=0, .miny=0, .width=1920, .height=1080, .gmem_page_align=1, .nr_cbufs=1, .cbuf_cpp = {4,0,0,0,0,0,0,0,}, .zsbuf_cpp = {4,0,}},
80};
81/* clang-format on */
82
83struct gpu_info {
84   const char *name;
85   uint32_t gpu_id;
86   uint8_t gmem_page_align;
87   uint32_t gmemsize_bytes;
88};
89
90#define SZ_128K 0x00020000
91#define SZ_256K 0x00040000
92#define SZ_512K 0x00080000
93#define SZ_1M   0x00100000
94
95/* keep sorted by gpu name: */
96static const struct gpu_info gpu_infos[] = {
97   {"a306", 307, 4, SZ_128K},
98   {"a405", 405, 4, SZ_256K},
99   {"a530", 530, 4, SZ_1M},
100   {"a618", 618, 1, SZ_512K},
101   {"a630", 630, 1, SZ_1M},
102   {"a650", 630, 1, SZ_1M + SZ_128K},
103};
104
105static const struct option opts[] = {
106   {.name = "gpu",     .has_arg = 1, NULL, 'g'},
107   {.name = "help",    .has_arg = 0, NULL, 'h'},
108   {.name = "verbose", .has_arg = 0, NULL, 'v'},
109   {}};
110
111static void
112usage(void)
113{
114   fprintf(stderr, "Usage:\n\n"
115                   "\tgmemtool [-hv] [-g GPU]\n\n"
116                   "Options:\n"
117                   "\t-g, --gpu=GPU   - use GMEM size/alignment/etc settings "
118                   "for the specified GPU\n"
119                   "\t-h, --help      - this usage message\n"
120                   "\t-v, --verbose   - dump more verbose output\n"
121                   "\n");
122   fprintf(stderr, "Where GPU is one of:\n");
123   for (int i = 0; i < ARRAY_SIZE(gpu_infos); i++)
124      fprintf(stderr, "\t%s\n", gpu_infos[i].name);
125   exit(2);
126}
127
128int
129main(int argc, char **argv)
130{
131   const char *gpu_name = "a630";
132   int c;
133
134   while ((c = getopt_long(argc, argv, "g:hv", opts, NULL)) != -1) {
135      switch (c) {
136      case 'g':
137         gpu_name = optarg;
138         break;
139      case 'v':
140         bin_debug = true;
141         break;
142      case 'h':
143      default:
144         usage();
145      }
146   }
147
148   const struct gpu_info *gpu_info = NULL;
149
150   for (int i = 0; i < ARRAY_SIZE(gpu_infos); i++) {
151      if (strcmp(gpu_name, gpu_infos[i].name) == 0) {
152         gpu_info = &gpu_infos[i];
153         break;
154      }
155   }
156
157   if (!gpu_info) {
158      printf("unrecognized gpu name: %s\n", gpu_name);
159      usage();
160   }
161
162   struct fd_dev_id dev_id = {
163         .gpu_id = gpu_info->gpu_id,
164   };
165   /* Setup a fake screen with enough GMEM related configuration
166    * to make gmem_stateobj_init() happy:
167    */
168   struct fd_screen screen = {
169      .dev_id = &dev_id,
170      .gmemsize_bytes = gpu_info->gmemsize_bytes,
171   };
172
173   screen.info = fd_dev_info(&dev_id);
174
175   /* And finally run thru all the GMEM keys: */
176   for (int i = 0; i < ARRAY_SIZE(keys); i++) {
177      struct gmem_key key = keys[i];
178      key.gmem_page_align = gpu_info->gmem_page_align;
179      struct fd_gmem_stateobj *gmem = gmem_stateobj_init(&screen, &key);
180      dump_gmem_state(gmem);
181
182      assert((gmem->bin_w * gmem->nbins_x) >= key.width);
183      assert((gmem->bin_h * gmem->nbins_y) >= key.height);
184      assert(gmem->bin_w < screen.info->tile_max_w);
185      assert(gmem->bin_h < screen.info->tile_max_h);
186
187      ralloc_free(gmem);
188   }
189
190   return 0;
191}
192