summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolai Hähnle <nicolai.haehnle@amd.com>2017-05-08 16:16:34 +0200
committerNicolai Hähnle <nicolai.haehnle@amd.com>2018-03-14 09:04:04 +0100
commitb6bfa65b8cb3bc814952b85db1a0506a0a8d8855 (patch)
tree320fa72a341aef3bb44923d4393456f77c5fd372
parent2ed6f03d3bf2fb5671776375a0a6132bba30c9f0 (diff)
WIP amd/addrtool
-rw-r--r--src/amd/Makefile.addrtool.am46
-rw-r--r--src/amd/Makefile.am2
-rw-r--r--src/amd/addrtool/addrtool.cpp677
3 files changed, 725 insertions, 0 deletions
diff --git a/src/amd/Makefile.addrtool.am b/src/amd/Makefile.addrtool.am
new file mode 100644
index 0000000000..dfc76778ca
--- /dev/null
+++ b/src/amd/Makefile.addrtool.am
@@ -0,0 +1,46 @@
+# Copyright 2017 Advanced Micro Devices, Inc.
+#
+# 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS 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.
+
+noinst_PROGRAMS += addrtool/addrtool
+
+addrtool_addrtool_SOURCES = \
+ addrtool/addrtool.cpp
+
+addrtool_addrtool_LDADD = \
+ addrlib/libamdgpu_addrlib.la \
+ common/libamd_common.la
+
+nodist_EXTRA_addrtool_addrtool_SOURCES = dummy.cpp
+
+addrtool_addrtool_CPPFLAGS = \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/mesa \
+ -I$(top_srcdir)/src/amd/common \
+ -I$(top_srcdir)/src/gallium/auxiliary \
+ -I$(top_srcdir)/src/gallium/include \
+ -I$(top_srcdir)/include \
+ $(VALGRIND_CFLAGS) \
+ $(AMDGPU_CFLAGS) \
+ $(DEFINES)
+
+addrtool_addrtool_LDADD += \
+ $(AMDGPU_LIBS) \
+ $(LIBDRM_LIBS)
diff --git a/src/amd/Makefile.am b/src/amd/Makefile.am
index 39cf0741ad..870e1ae407 100644
--- a/src/amd/Makefile.am
+++ b/src/amd/Makefile.am
@@ -22,8 +22,10 @@
include Makefile.sources
noinst_LTLIBRARIES =
+noinst_PROGRAMS =
include Makefile.addrlib.am
+include Makefile.addrtool.am
include Makefile.common.am
EXTRA_DIST = \
diff --git a/src/amd/addrtool/addrtool.cpp b/src/amd/addrtool/addrtool.cpp
new file mode 100644
index 0000000000..79b54ddffc
--- /dev/null
+++ b/src/amd/addrtool/addrtool.cpp
@@ -0,0 +1,677 @@
+/*
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * 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
+ * on 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 AUTHOR(S) AND/OR THEIR 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.
+ */
+
+/* Surface description format
+ * ==========================
+ * W[xH[xD]][.Samples][*Layers][:Levels][,flag]...
+ *
+ * Levels can be empty, indicating a full miptree.
+ * flags can be:
+ * * 'cube'
+ * * '3d'
+ */
+
+//HACK - Must update libdrm to be C++-compatible
+#include <stdint.h>
+#include <stdbool.h>
+extern "C" {
+#include <amdgpu.h>
+}
+//END HACK
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util/bitscan.h"
+#include "util/macros.h"
+#include "util/u_math.h"
+
+#include "ac_gpu_info.h"
+#include "ac_surface.h"
+
+#include "addrlib/addrinterface.h"
+#include "addrlib/addrtypes.h"
+
+static struct radeon_info info;
+static ADDR_HANDLE addrlib;
+
+static void usage()
+{
+ printf(
+"usage: addrtool addr <surface> <coord>...\n"
+"usage: addrtool coord <surface> <addr>...\n"
+"\n"
+" <surface> is: W[xH[xD]][.Samples][*Layers][:Levels][,flag]...\n"
+" <coord> is: X[xY[xZ]][*Layer][:Level]\n"
+ );
+ exit(1);
+}
+
+static void addrlib_open()
+{
+ unsigned major_version, minor_version;
+ int fd = open("/dev/dri/renderD128", O_RDWR);
+ amdgpu_device_handle dev;
+ struct amdgpu_gpu_info amdinfo;
+ int r;
+ if (fd == -1)
+ perror("Could not open DRM node");
+
+ r = amdgpu_device_initialize(fd, &major_version, &minor_version, &dev);
+ if (r == -1)
+ perror("Could not initialize amdgpu");
+
+ if (!ac_query_gpu_info(fd, dev, &info, &amdinfo)) {
+ fprintf(stderr, "Failed to query GPU info\n");
+ exit(1);
+ }
+
+ addrlib = amdgpu_addr_create(&info, &amdinfo, NULL);
+ if (!addrlib) {
+ fprintf(stderr, "Failed to create addrlib instance\n");
+ exit(1);
+ }
+
+ amdgpu_device_deinitialize(dev);
+ close(fd);
+}
+
+static void addrlib_error(ADDR_E_RETURNCODE ret, const char *msg)
+{
+ fprintf(stderr, "addrlib error %u: %s\n", ret, msg);
+ exit(1);
+}
+
+static const char *get_tile_mode_string(AddrTileMode tm, char *buf, int len)
+{
+ static const char *strings[] = {
+#define X(e) [e] = #e,
+ X(ADDR_TM_LINEAR_GENERAL)
+ X(ADDR_TM_LINEAR_ALIGNED)
+ X(ADDR_TM_1D_TILED_THIN1)
+ X(ADDR_TM_1D_TILED_THICK)
+ X(ADDR_TM_2D_TILED_THIN1)
+ X(ADDR_TM_2D_TILED_THIN2)
+ X(ADDR_TM_2D_TILED_THIN4)
+ X(ADDR_TM_2D_TILED_THICK)
+ X(ADDR_TM_2B_TILED_THIN1)
+ X(ADDR_TM_2B_TILED_THIN2)
+ X(ADDR_TM_2B_TILED_THIN4)
+ X(ADDR_TM_2B_TILED_THICK)
+ X(ADDR_TM_3D_TILED_THIN1)
+ X(ADDR_TM_3D_TILED_THICK)
+ X(ADDR_TM_3B_TILED_THIN1)
+ X(ADDR_TM_3B_TILED_THICK)
+ X(ADDR_TM_2D_TILED_XTHICK)
+ X(ADDR_TM_3D_TILED_XTHICK)
+ X(ADDR_TM_POWER_SAVE)
+ X(ADDR_TM_PRT_TILED_THIN1)
+ X(ADDR_TM_PRT_2D_TILED_THIN1)
+ X(ADDR_TM_PRT_3D_TILED_THIN1)
+ X(ADDR_TM_PRT_TILED_THICK)
+ X(ADDR_TM_PRT_2D_TILED_THICK)
+ X(ADDR_TM_PRT_3D_TILED_THICK)
+ X(ADDR_TM_UNKNOWN)
+#undef X
+ };
+
+ if (tm < ARRAY_SIZE(strings))
+ return strings[tm];
+
+ snprintf(buf, len, "%u", tm);
+ return buf;
+}
+
+static const char *get_pipe_config_string(AddrPipeCfg v, char *buf, int len)
+{
+ switch(v) {
+#define X(e) case e: return #e;
+ X(ADDR_PIPECFG_INVALID)
+ X(ADDR_PIPECFG_P2)
+ X(ADDR_PIPECFG_P4_8x16)
+ X(ADDR_PIPECFG_P4_16x16)
+ X(ADDR_PIPECFG_P4_16x32)
+ X(ADDR_PIPECFG_P4_32x32)
+ X(ADDR_PIPECFG_P8_16x16_8x16)
+ X(ADDR_PIPECFG_P8_16x32_8x16)
+ X(ADDR_PIPECFG_P8_32x32_8x16)
+ X(ADDR_PIPECFG_P8_16x32_16x16)
+ X(ADDR_PIPECFG_P8_32x32_16x16)
+ X(ADDR_PIPECFG_P8_32x32_16x32)
+ X(ADDR_PIPECFG_P8_32x64_32x32)
+ X(ADDR_PIPECFG_P16_32x32_8x16)
+ X(ADDR_PIPECFG_P16_32x32_16x16)
+ X(ADDR_PIPECFG_MAX)
+#undef X
+ default:
+ snprintf(buf, len, "%u", v);
+ return buf;
+ }
+}
+
+static const char *get_tile_type_string(AddrTileType v, char *buf, int len)
+{
+ static const char *strings[] = {
+#define X(e) [e] = #e,
+ X(ADDR_DISPLAYABLE)
+ X(ADDR_NON_DISPLAYABLE)
+ X(ADDR_DEPTH_SAMPLE_ORDER)
+ X(ADDR_ROTATED)
+ X(ADDR_THICK)
+#undef X
+ };
+
+ if (v < ARRAY_SIZE(strings))
+ return strings[v];
+
+ snprintf(buf, len, "%u", v);
+ return buf;
+}
+
+static void dump_surface_info_output(const ADDR_COMPUTE_SURFACE_INFO_OUTPUT *csio)
+{
+ char buf1[32];
+
+ printf("ADDR_COMPUTE_SURFACE_INFO_OUTPUT: {\n");
+ printf(" pitch: %u, height: %u, depth: %u, surfSize: %llu, tileMode: %s,\n",
+ csio->pitch, csio->height, csio->depth, csio->surfSize,
+ get_tile_mode_string(csio->tileMode, buf1, sizeof(buf1)));
+ printf(" baseAlign: %u, pitchAlign: %u, heightAlign: %u, depthAlign: %u,\n",
+ csio->baseAlign, csio->pitchAlign, csio->heightAlign, csio->depthAlign);
+ printf(" bpp: %u, pixelPitch: %u, pixelHeight: %u, pixelBits: %u, sliceSize: %llu,\n",
+ csio->bpp, csio->pixelPitch, csio->pixelHeight, csio->pixelBits, csio->sliceSize);
+ printf(" pitchTileMax: %u, heightTileMax: %u, sliceTileMax: %u, numSamples: %u\n",
+ csio->pitchTileMax, csio->heightTileMax, csio->sliceTileMax, csio->numSamples);
+ if (csio->pTileInfo) {
+ const ADDR_TILEINFO *ti = csio->pTileInfo;
+ printf(" pTileInfo: { banks: %u, bankWidth: %u, bankHeight: %u, macroAspectRatio: %u,\n",
+ ti->banks, ti->bankWidth, ti->bankHeight, ti->macroAspectRatio);
+ printf(" tileSplitBytes: %u, pipeConfig: %s },\n",
+ ti->tileSplitBytes, get_pipe_config_string(ti->pipeConfig, buf1, sizeof(buf1)));
+ }
+ printf(" tileType: %s, tileIndex: %d, macroModeIndex: %d, last2DLevel: %u, tcCompatible: %u\n",
+ get_tile_type_string(csio->tileType, buf1, sizeof(buf1)),
+ csio->tileIndex, csio->macroModeIndex, csio->last2DLevel, csio->tcCompatible);
+ printf(" dccUnsupport: %u, prtTileIndex: %u, equationIndex: %u,\n",
+ csio->blockWidth, csio->blockHeight, csio->blockSlices);
+ printf(" pStereoInfo: %p, stencilTileIdx: %d }\n",
+ csio->pStereoInfo, csio->stencilTileIdx);
+}
+
+static void demo()
+{
+ ADDR_COMPUTE_SURFACE_INFO_INPUT csii;
+ ADDR_COMPUTE_SURFACE_INFO_OUTPUT csio;
+ ADDR_TILEINFO tio = {0};
+ ADDR_E_RETURNCODE ret;
+
+ memset(&csii, 0, sizeof(csii));
+ csii.size = sizeof(csii);
+
+ csii.tileMode = ADDR_TM_UNKNOWN;
+ csii.bpp = 32;
+ csii.numSamples = 1;
+ csii.width = 64;
+ csii.height = 64;
+ csii.numSlices = 18;
+ csii.numMipLevels = 7;
+ csii.flags.depth = 1;
+ csii.flags.stencil = 1;
+ csii.flags.compressZ = 1;
+ csii.flags.cube = 1;
+ csii.flags.pow2Pad = 1;
+
+ csio.size = sizeof(csio);
+ csio.pTileInfo = &tio;
+
+ ret = AddrComputeSurfaceInfo(addrlib, &csii, &csio);
+ if (ret != ADDR_OK)
+ addrlib_error(ret, "AddrComputeSurfaceInfo");
+
+ dump_surface_info_output(&csio);
+}
+
+static void parse_error(const char *cur, const char *full, const char *msg)
+{
+ printf("Error: %s\n", msg);
+ printf("in: %s\n", full);
+ printf("%*s^\n", 4 + (int)(cur - full), "");
+}
+
+enum parse_int_flags {
+ parse_int_optional = (1 << 0),
+};
+
+static bool parse_uint(const char **pcur, const char *full, unsigned flags, unsigned *result)
+{
+ const char *cur = *pcur;
+
+ if (!(*cur >= '0' && *cur <= '9')) {
+ if (flags & parse_int_optional)
+ return true;
+
+ parse_error(cur, full, "unsigned integer expected");
+ return false;
+ }
+
+ char *endp;
+ *result = strtol(cur, &endp, 10);
+ *pcur = endp;
+
+ return true;
+}
+
+static bool parse_keyword(const char **pcur, const char *keyword)
+{
+ int len = strlen(keyword);
+ if (strncmp(*pcur, keyword, len) != 0)
+ return false;
+
+ *pcur += len;
+ return true;
+}
+
+static bool parse_surf_config(const char *def, struct ac_surf_config *config)
+{
+ const char *cur = def;
+
+ config->info.width = config->info.height = config->info.depth = config->info.array_size = 1;
+ config->info.levels = 1;
+
+ if (!parse_uint(&cur, def, 0, &config->info.width))
+ return false;
+
+ if (*cur == 'x') {
+ cur++;
+ if (!parse_uint(&cur, def, 0, &config->info.height))
+ return false;
+
+ if (*cur == 'x') {
+ cur++;
+ if (!parse_uint(&cur, def, 0, &config->info.depth))
+ return false;
+
+ config->is_3d = 1;
+ }
+ }
+
+ if (*cur == '.') {
+ unsigned samples;
+ cur++;
+ if (!parse_uint(&cur, def, 0, &samples))
+ return false;
+
+ config->info.samples = samples;
+ }
+
+ if (*cur == '*') {
+ unsigned array_size;
+ cur++;
+ if (!parse_uint(&cur, def, 0, &array_size))
+ return false;
+
+ config->info.array_size = array_size;
+ }
+
+ if (*cur == ':') {
+ unsigned levels = MAX3(util_last_bit(config->info.width),
+ util_last_bit(config->info.height),
+ util_last_bit(config->info.depth));
+ cur++;
+ if (!parse_uint(&cur, def, parse_int_optional, &levels))
+ return false;
+
+ config->info.levels = levels;
+ }
+
+ while (*cur == ',') {
+ if (parse_keyword(&cur, "cube")) {
+ config->is_cube = 1;
+ } else if (parse_keyword(&cur, "3d")) {
+ config->is_3d = 1;
+ } else {
+ parse_error(cur, def, "unknown flag");
+ return false;
+ }
+
+ if (*cur && *cur != ',') {
+ parse_error(cur, def, "unexpected noise after flag");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+struct coordinate {
+ unsigned x, y, z;
+ unsigned sample;
+ unsigned layer;
+ unsigned level;
+};
+
+static bool parse_coordinate(const char *def, struct coordinate *coord)
+{
+ const char *cur = def;
+
+ if (!parse_uint(&cur, def, 0, &coord->x))
+ return false;
+
+ if (*cur == 'x') {
+ cur++;
+ if (!parse_uint(&cur, def, 0, &coord->y))
+ return false;
+
+ if (*cur == 'x') {
+ cur++;
+ if (!parse_uint(&cur, def, 0, &coord->z))
+ return false;
+ }
+ }
+
+ if (*cur == '.') {
+ cur++;
+ if (!parse_uint(&cur, def, 0, &coord->sample))
+ return false;
+ }
+
+ if (*cur == '*') {
+ cur++;
+ if (!parse_uint(&cur, def, 0, &coord->layer))
+ return false;
+ }
+
+ if (*cur == ':') {
+ cur++;
+ if (!parse_uint(&cur, def, parse_int_optional, &coord->level))
+ return false;
+ }
+
+ return true;
+}
+
+static void print_surf_config(const struct ac_surf_config *config, FILE *f)
+{
+ fprintf(f, "%ux%ux%u.%u*%u:%u",
+ config->info.width, config->info.height, config->info.depth,
+ config->info.samples, config->info.array_size, config->info.levels);
+ if (config->is_3d)
+ fprintf(f, ",3d");
+ if (config->is_cube)
+ fprintf(f, ",cube");
+}
+
+static void print_coordinate(const struct coordinate *coord, FILE *f)
+{
+ fprintf(f, "%ux%ux%u.%u*%u:%u",
+ coord->x, coord->y, coord->z, coord->sample, coord->layer,
+ coord->level);
+}
+
+template<typename T>
+static void gfx6_setup_compute_addr_coord(const struct ac_surf_config *config,
+ const struct radeon_surf *surf,
+ unsigned level,
+ T *in,
+ ADDR_TILEINFO *ti)
+{
+ ADDR_E_RETURNCODE r;
+ ADDR_EXTRACT_BANKPIPE_SWIZZLE_INPUT ebpsi = {};
+ ADDR_EXTRACT_BANKPIPE_SWIZZLE_OUTPUT ebpso = {};
+ const struct legacy_surf_level *lvlinfo = &surf->u.legacy.level[level];
+
+ ebpsi.size = sizeof(ebpsi);
+ ebpso.size = sizeof(ebpso);
+
+ /* Fill in surface data */
+ in->bpp = surf->bpe * 8;
+ in->pitch = lvlinfo->nblk_x;
+ in->height = lvlinfo->nblk_y;
+ in->numSlices = config->is_3d ? u_minify(config->info.depth, level) : config->info.array_size;
+ in->numSamples = config->info.samples;
+
+ switch (lvlinfo->mode) {
+ case RADEON_SURF_MODE_LINEAR_ALIGNED:
+ in->tileMode = ADDR_TM_LINEAR_ALIGNED;
+ break;
+ case RADEON_SURF_MODE_1D:
+ in->tileMode = ADDR_TM_1D_TILED_THIN1;
+ break;
+ case RADEON_SURF_MODE_2D:
+ in->tileMode = ADDR_TM_2D_TILED_THIN1;
+ break;
+ default:
+ assert(0);
+ }
+
+ in->isDepth = !!(surf->flags & RADEON_SURF_Z_OR_SBUFFER);
+ in->tileBase = 0; /* ??? */
+ in->compBits = 0; /* ??? */
+
+ /* Set the micro tile type. */
+ if (surf->flags & RADEON_SURF_SCANOUT)
+ in->tileType = ADDR_DISPLAYABLE;
+ else if (surf->flags & (RADEON_SURF_Z_OR_SBUFFER | RADEON_SURF_FMASK))
+ in->tileType = ADDR_DEPTH_SAMPLE_ORDER;
+ else
+ in->tileType = ADDR_NON_DISPLAYABLE;
+
+ ti->banks = surf->u.legacy.num_banks;
+ ti->bankWidth = surf->u.legacy.bankw;
+ ti->bankHeight = surf->u.legacy.bankh;
+ ti->macroAspectRatio = surf->u.legacy.mtilea;
+ ti->tileSplitBytes = surf->u.legacy.tile_split;
+ ti->pipeConfig = AddrPipeCfg(surf->u.legacy.pipe_config + 1); /* +1 compared to GB_TILE_MODE */
+ in->pTileInfo = ti;
+ in->tileIndex = surf->u.legacy.tiling_index[level];
+
+ ebpsi.base256b = 0; /* ??? slice swizzle ??? */
+ ebpsi.pTileInfo = ti;
+ ebpsi.tileIndex = surf->u.legacy.tiling_index[level];
+ ebpsi.macroModeIndex = surf->u.legacy.macro_tile_index;
+
+ r = AddrExtractBankPipeSwizzle(addrlib, &ebpsi, &ebpso);
+ if (r != ADDR_OK) {
+ printf("AddrExtractBankPipeSwizzle failed: %d\n", r);
+ exit(1);
+ }
+
+ in->bankSwizzle = ebpso.bankSwizzle;
+ in->pipeSwizzle = ebpso.pipeSwizzle;
+}
+
+static uint64_t gfx6_compute_addr(const struct ac_surf_config *config,
+ const struct radeon_surf *surf,
+ const struct coordinate *coord)
+{
+ ADDR_TILEINFO ti = {};
+ ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT in = {};
+ ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT out = {};
+ ADDR_E_RETURNCODE r;
+ int level = coord->level;
+
+ in.size = sizeof(in);
+ out.size = sizeof(out);
+
+ gfx6_setup_compute_addr_coord(config, surf, level, &in, &ti);
+
+ /* Fill in coordinate */
+ in.x = coord->x;
+ in.y = coord->y;
+ in.slice = config->is_3d ? coord->z : coord->layer;
+ in.sample = coord->sample;
+
+ r = AddrComputeSurfaceAddrFromCoord(addrlib, &in, &out);
+ if (r != ADDR_OK) {
+ printf("AddrComputeSurfaceAddrFromCoord failed: %d\n", r);
+ exit(1);
+ }
+
+ return out.addr + surf->u.legacy.level[level].offset;
+}
+
+static void gfx6_compute_coord(const struct ac_surf_config *config,
+ const struct radeon_surf *surf,
+ uint64_t addr,
+ struct coordinate *coord)
+{
+ ADDR_TILEINFO ti = {};
+ ADDR_COMPUTE_SURFACE_COORDFROMADDR_INPUT in = {};
+ ADDR_COMPUTE_SURFACE_COORDFROMADDR_OUTPUT out = {};
+ ADDR_E_RETURNCODE r;
+ int level = 0;
+
+ while (level + 1 < config->info.levels &&
+ addr >= surf->u.legacy.level[level + 1].offset)
+ level++;
+
+ in.size = sizeof(in);
+ out.size = sizeof(out);
+
+ gfx6_setup_compute_addr_coord(config, surf, level, &in, &ti);
+
+ /* Fill in address */
+ in.addr = addr - surf->u.legacy.level[level].offset;
+
+ r = AddrComputeSurfaceCoordFromAddr(addrlib, &in, &out);
+ if (r != ADDR_OK) {
+ printf("AddrComputeSurfaceCoordFromAddr failed: %d\n", r);
+ exit(1);
+ }
+
+ coord->x = out.x;
+ coord->y = out.y;
+ coord->z = config->is_3d ? out.slice : 0;
+ coord->layer = config->is_3d ? 0 : out.slice;
+ coord->sample = out.sample;
+ coord->level = level;
+}
+
+static void cmd_addr_coord(int argc, char **argv, int argi, bool from_addr)
+{
+ struct ac_surf_config config = {};
+ int r;
+
+ if (argi >= argc) {
+ printf("Missing arguments: <surface> %s\n", from_addr ? "<addr>" : "<coord>");
+ exit(1);
+ }
+ if (!parse_surf_config(argv[argi++], &config))
+ exit(1);
+
+ printf("Surface: ");
+ print_surf_config(&config, stdout);
+ printf("\n");
+
+ if (argi >= argc) {
+ printf("Missing argument: %s\n", from_addr ? "<addr>" : "<coord>");
+ exit(1);
+ }
+
+ struct radeon_surf surf = {};
+
+ surf.blk_w = 1;
+ surf.blk_h = 1;
+ surf.bpe = 4;
+
+ r = ac_compute_surface(addrlib, &info, &config, RADEON_SURF_MODE_2D, &surf);
+ if (r) {
+ printf("Error computing surface: %d\n", r);
+ exit(1);
+ }
+
+ /* TODO: gfx9 support... */
+ assert(info.chip_class <= VI);
+
+ while (argi < argc) {
+ if (from_addr) {
+ char *endp;
+ uint64_t addr = strtoull(argv[argi++], &endp, 0);
+ if (*endp) {
+ printf("Expected addr: %s\n", argv[argi - 1]);
+ exit(1);
+ }
+
+ printf("Addr: %" PRIu64 " -- 0x%" PRIx64 "\n", addr, addr);
+
+ struct coordinate coord;
+ gfx6_compute_coord(&config, &surf, addr, &coord);
+ printf("Coordinate: ");
+ print_coordinate(&coord, stdout);
+ printf("\n");
+ } else {
+ struct coordinate coord = {};
+ if (!parse_coordinate(argv[argi++], &coord))
+ exit(1);
+
+ printf("Coordinate: ");
+ print_coordinate(&coord, stdout);
+ printf("\n");
+
+ uint64_t addr = gfx6_compute_addr(&config, &surf, &coord);
+ printf("Address: %" PRIu64 " -- 0x%" PRIx64 "\n", addr, addr);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int i = 1;
+
+ addrlib_open();
+
+ printf("Demo\n");
+ demo();
+
+ while (i < argc) {
+ if (argv[i][0] != '-')
+ break;
+
+ if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ usage();
+ } else {
+ printf("Unknown argument: %s\n", argv[i]);
+ exit(1);
+ }
+ }
+
+ if (i >= argc) {
+ printf("Need to provide a command!\n");
+ exit(1);
+ }
+
+ const char *cmd = argv[i++];
+
+ if (!strcmp(cmd, "addr")) {
+ cmd_addr_coord(argc, argv, i, false);
+ } else if (!strcmp(cmd, "coord")) {
+ cmd_addr_coord(argc, argv, i, true);
+ } else {
+ printf("Unknown command: %s\n", argv[i]);
+ exit(1);
+ }
+}