/*
 * Copyright © 2024 Igalia S.L.
 * SPDX-License-Identifier: MIT
 */

#include "util/u_math.h"

#include "fd6_hw.h"

#include "freedreno_perfcntr.h"

#define REG6(_x) REG_A6XX_##_x
#define REG7(_x) REG_A7XX_##_x

#define FD7_COUNTER(_sel, _offset) COUNTER_BASE(_sel, _offset+0, _offset+1)
#define FD7_COUNTABLE(_sel) COUNTABLE_BASE(#_sel, A7XX_##_sel, UINT64, AVERAGE)

static const struct fd_perfcntr_counter cp_counters[] = {
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(0)), REG7(RBBM_PERFCTR_CP(0))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(1)), REG7(RBBM_PERFCTR_CP(1))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(2)), REG7(RBBM_PERFCTR_CP(2))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(3)), REG7(RBBM_PERFCTR_CP(3))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(4)), REG7(RBBM_PERFCTR_CP(4))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(5)), REG7(RBBM_PERFCTR_CP(5))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(6)), REG7(RBBM_PERFCTR_CP(6))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(7)), REG7(RBBM_PERFCTR_CP(7))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(8)), REG7(RBBM_PERFCTR_CP(8))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(9)), REG7(RBBM_PERFCTR_CP(9))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(10)), REG7(RBBM_PERFCTR_CP(10))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(11)), REG7(RBBM_PERFCTR_CP(11))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(12)), REG7(RBBM_PERFCTR_CP(12))),
      FD7_COUNTER(REG6(CP_PERFCTR_CP_SEL(13)), REG7(RBBM_PERFCTR_CP(13))),
};

static const struct fd_perfcntr_countable cp_countables[] = {
      FD7_COUNTABLE(PERF_CP_ALWAYS_COUNT),
      FD7_COUNTABLE(PERF_CP_BUSY_GFX_CORE_IDLE),
      FD7_COUNTABLE(PERF_CP_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_CP_NUM_PREEMPTIONS),
      FD7_COUNTABLE(PERF_CP_PREEMPTION_REACTION_DELAY),
      FD7_COUNTABLE(PERF_CP_PREEMPTION_SWITCH_OUT_TIME),
      FD7_COUNTABLE(PERF_CP_PREEMPTION_SWITCH_IN_TIME),
      FD7_COUNTABLE(PERF_CP_DEAD_DRAWS_IN_BIN_RENDER),
      FD7_COUNTABLE(PERF_CP_PREDICATED_DRAWS_KILLED),
      FD7_COUNTABLE(PERF_CP_MODE_SWITCH),
      FD7_COUNTABLE(PERF_CP_ZPASS_DONE),
      FD7_COUNTABLE(PERF_CP_CONTEXT_DONE),
      FD7_COUNTABLE(PERF_CP_CACHE_FLUSH),
      FD7_COUNTABLE(PERF_CP_LONG_PREEMPTIONS),
      FD7_COUNTABLE(PERF_CP_SQE_I_CACHE_STARVE),
      FD7_COUNTABLE(PERF_CP_SQE_IDLE),
      FD7_COUNTABLE(PERF_CP_SQE_PM4_STARVE_RB_IB),
      FD7_COUNTABLE(PERF_CP_SQE_PM4_STARVE_SDS),
      FD7_COUNTABLE(PERF_CP_SQE_MRB_STARVE),
      FD7_COUNTABLE(PERF_CP_SQE_RRB_STARVE),
      FD7_COUNTABLE(PERF_CP_SQE_VSD_STARVE),
      FD7_COUNTABLE(PERF_CP_VSD_DECODE_STARVE),
      FD7_COUNTABLE(PERF_CP_SQE_PIPE_OUT_STALL),
      FD7_COUNTABLE(PERF_CP_SQE_SYNC_STALL),
      FD7_COUNTABLE(PERF_CP_SQE_PM4_WFI_STALL),
      FD7_COUNTABLE(PERF_CP_SQE_SYS_WFI_STALL),
      FD7_COUNTABLE(PERF_CP_SQE_T4_EXEC),
      FD7_COUNTABLE(PERF_CP_SQE_LOAD_STATE_EXEC),
      FD7_COUNTABLE(PERF_CP_SQE_SAVE_SDS_STATE),
      FD7_COUNTABLE(PERF_CP_SQE_DRAW_EXEC),
      FD7_COUNTABLE(PERF_CP_SQE_CTXT_REG_BUNCH_EXEC),
      FD7_COUNTABLE(PERF_CP_SQE_EXEC_PROFILED),
      FD7_COUNTABLE(PERF_CP_MEMORY_POOL_EMPTY),
      FD7_COUNTABLE(PERF_CP_MEMORY_POOL_SYNC_STALL),
      FD7_COUNTABLE(PERF_CP_MEMORY_POOL_ABOVE_THRESH),
      FD7_COUNTABLE(PERF_CP_AHB_WR_STALL_PRE_DRAWS),
      FD7_COUNTABLE(PERF_CP_AHB_STALL_SQE_GMU),
      FD7_COUNTABLE(PERF_CP_AHB_STALL_SQE_WR_OTHER),
      FD7_COUNTABLE(PERF_CP_AHB_STALL_SQE_RD_OTHER),
      FD7_COUNTABLE(PERF_CP_CLUSTER0_EMPTY),
      FD7_COUNTABLE(PERF_CP_CLUSTER1_EMPTY),
      FD7_COUNTABLE(PERF_CP_CLUSTER2_EMPTY),
      FD7_COUNTABLE(PERF_CP_CLUSTER3_EMPTY),
      FD7_COUNTABLE(PERF_CP_CLUSTER4_EMPTY),
      FD7_COUNTABLE(PERF_CP_CLUSTER5_EMPTY),
      FD7_COUNTABLE(PERF_CP_PM4_DATA),
      FD7_COUNTABLE(PERF_CP_PM4_HEADERS),
      FD7_COUNTABLE(PERF_CP_VBIF_READ_BEATS),
      FD7_COUNTABLE(PERF_CP_VBIF_WRITE_BEATS),
      FD7_COUNTABLE(PERF_CP_SQE_INSTR_COUNTER),
      FD7_COUNTABLE(PERF_CP_RESERVED_50),
      FD7_COUNTABLE(PERF_CP_RESERVED_51),
      FD7_COUNTABLE(PERF_CP_RESERVED_52),
      FD7_COUNTABLE(PERF_CP_RESERVED_53),
      FD7_COUNTABLE(PERF_CP_RESERVED_54),
      FD7_COUNTABLE(PERF_CP_RESERVED_55),
      FD7_COUNTABLE(PERF_CP_RESERVED_56),
      FD7_COUNTABLE(PERF_CP_RESERVED_57),
      FD7_COUNTABLE(PERF_CP_RESERVED_58),
      FD7_COUNTABLE(PERF_CP_RESERVED_59),
      FD7_COUNTABLE(PERF_CP_CLUSTER0_FULL),
      FD7_COUNTABLE(PERF_CP_CLUSTER1_FULL),
      FD7_COUNTABLE(PERF_CP_CLUSTER2_FULL),
      FD7_COUNTABLE(PERF_CP_CLUSTER3_FULL),
      FD7_COUNTABLE(PERF_CP_CLUSTER4_FULL),
      FD7_COUNTABLE(PERF_CP_CLUSTER5_FULL),
      FD7_COUNTABLE(PERF_CP_CLUSTER6_FULL),
      FD7_COUNTABLE(PERF_CP_CLUSTER6_EMPTY),
      FD7_COUNTABLE(PERF_CP_ICACHE_MISSES),
      FD7_COUNTABLE(PERF_CP_ICACHE_HITS),
      FD7_COUNTABLE(PERF_CP_ICACHE_STALL),
      FD7_COUNTABLE(PERF_CP_DCACHE_MISSES),
      FD7_COUNTABLE(PERF_CP_DCACHE_HITS),
      FD7_COUNTABLE(PERF_CP_DCACHE_STALLS),
      FD7_COUNTABLE(PERF_CP_AQE_SQE_STALL),
      FD7_COUNTABLE(PERF_CP_SQE_AQE_STARVE),
      FD7_COUNTABLE(PERF_CP_PREEMPT_LATENCY),
      FD7_COUNTABLE(PERF_CP_SQE_MD8_STALL_CYCLES),
      FD7_COUNTABLE(PERF_CP_SQE_MESH_EXEC_CYCLES),
      FD7_COUNTABLE(PERF_CP_AQE_NUM_AS_CHUNKS),
      FD7_COUNTABLE(PERF_CP_AQE_NUM_MS_CHUNKS),
};

static const struct fd_perfcntr_counter rbbm_counters[] = {
      FD7_COUNTER(REG6(RBBM_PERFCTR_RBBM_SEL(0)), REG7(RBBM_PERFCTR_RBBM(0))),
      FD7_COUNTER(REG6(RBBM_PERFCTR_RBBM_SEL(1)), REG7(RBBM_PERFCTR_RBBM(1))),
      FD7_COUNTER(REG6(RBBM_PERFCTR_RBBM_SEL(2)), REG7(RBBM_PERFCTR_RBBM(2))),
      FD7_COUNTER(REG6(RBBM_PERFCTR_RBBM_SEL(3)), REG7(RBBM_PERFCTR_RBBM(3))),
};

static const struct fd_perfcntr_countable rbbm_countables[] = {
      FD7_COUNTABLE(PERF_RBBM_ALWAYS_COUNT),
      FD7_COUNTABLE(PERF_RBBM_ALWAYS_ON),
      FD7_COUNTABLE(PERF_RBBM_TSE_BUSY),
      FD7_COUNTABLE(PERF_RBBM_RAS_BUSY),
      FD7_COUNTABLE(PERF_RBBM_PC_DCALL_BUSY),
      FD7_COUNTABLE(PERF_RBBM_PC_VSD_BUSY),
      FD7_COUNTABLE(PERF_RBBM_STATUS_MASKED),
      FD7_COUNTABLE(PERF_RBBM_COM_BUSY),
      FD7_COUNTABLE(PERF_RBBM_DCOM_BUSY),
      FD7_COUNTABLE(PERF_RBBM_VBIF_BUSY),
      FD7_COUNTABLE(PERF_RBBM_VSC_BUSY),
      FD7_COUNTABLE(PERF_RBBM_TESS_BUSY),
      FD7_COUNTABLE(PERF_RBBM_UCHE_BUSY),
      FD7_COUNTABLE(PERF_RBBM_HLSQ_BUSY),
};

static const struct fd_perfcntr_counter pc_counters[] = {
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(0)), REG7(RBBM_PERFCTR_PC(0))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(1)), REG7(RBBM_PERFCTR_PC(1))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(2)), REG7(RBBM_PERFCTR_PC(2))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(3)), REG7(RBBM_PERFCTR_PC(3))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(4)), REG7(RBBM_PERFCTR_PC(4))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(5)), REG7(RBBM_PERFCTR_PC(5))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(6)), REG7(RBBM_PERFCTR_PC(6))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(7)), REG7(RBBM_PERFCTR_PC(7))),
};

static const struct fd_perfcntr_countable pc_countables[] = {
      FD7_COUNTABLE(PERF_PC_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_PC_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_VFD),
      FD7_COUNTABLE(PERF_PC_RESERVED),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_VPC),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_TESS),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_VFD_ONLY),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_VPC_ONLY),
      FD7_COUNTABLE(PERF_PC_PASS1_TF_STALL_CYCLES),
      FD7_COUNTABLE(PERF_PC_STARVE_CYCLES_FOR_INDEX),
      FD7_COUNTABLE(PERF_PC_STARVE_CYCLES_FOR_TESS_FACTOR),
      FD7_COUNTABLE(PERF_PC_STARVE_CYCLES_FOR_VIZ_STREAM),
      FD7_COUNTABLE(PERF_PC_STARVE_CYCLES_DI),
      FD7_COUNTABLE(PERF_PC_VIS_STREAMS_LOADED),
      FD7_COUNTABLE(PERF_PC_INSTANCES),
      FD7_COUNTABLE(PERF_PC_VPC_PRIMITIVES),
      FD7_COUNTABLE(PERF_PC_DEAD_PRIM),
      FD7_COUNTABLE(PERF_PC_LIVE_PRIM),
      FD7_COUNTABLE(PERF_PC_VERTEX_HITS),
      FD7_COUNTABLE(PERF_PC_IA_VERTICES),
      FD7_COUNTABLE(PERF_PC_IA_PRIMITIVES),
      FD7_COUNTABLE(PERF_PC_RESERVED_22),
      FD7_COUNTABLE(PERF_PC_HS_INVOCATIONS),
      FD7_COUNTABLE(PERF_PC_DS_INVOCATIONS),
      FD7_COUNTABLE(PERF_PC_VS_INVOCATIONS),
      FD7_COUNTABLE(PERF_PC_GS_INVOCATIONS),
      FD7_COUNTABLE(PERF_PC_DS_PRIMITIVES),
      FD7_COUNTABLE(PERF_PC_3D_DRAWCALLS),
      FD7_COUNTABLE(PERF_PC_2D_DRAWCALLS),
      FD7_COUNTABLE(PERF_PC_NON_DRAWCALL_GLOBAL_EVENTS),
      FD7_COUNTABLE(PERF_PC_TESS_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_PC_TESS_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_PC_TESS_STALL_CYCLES_PC),
      FD7_COUNTABLE(PERF_PC_TESS_STARVE_CYCLES_PC),
      FD7_COUNTABLE(PERF_PC_TESS_SINGLE_PRIM_CYCLES),
      FD7_COUNTABLE(PERF_PC_TESS_PC_UV_TRANS),
      FD7_COUNTABLE(PERF_PC_TESS_PC_UV_PATCHES),
      FD7_COUNTABLE(PERF_PC_TESS_FACTOR_TRANS),
      FD7_COUNTABLE(PERF_PC_TAG_CHECKED_VERTICES),
      FD7_COUNTABLE(PERF_PC_MESH_VS_WAVES),
      FD7_COUNTABLE(PERF_PC_MESH_DRAWS),
      FD7_COUNTABLE(PERF_PC_MESH_DEAD_DRAWS),
      FD7_COUNTABLE(PERF_PC_MESH_MVIS_EN_DRAWS),
      FD7_COUNTABLE(PERF_PC_MESH_DEAD_PRIM),
      FD7_COUNTABLE(PERF_PC_MESH_LIVE_PRIM),
      FD7_COUNTABLE(PERF_PC_MESH_PA_EN_PRIM),
      FD7_COUNTABLE(PERF_PC_STARVE_CYCLES_FOR_MVIS_STREAM),
      FD7_COUNTABLE(PERF_PC_STARVE_CYCLES_PREDRAW),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_COMPUTE_GFX),
      FD7_COUNTABLE(PERF_PC_STALL_CYCLES_GFX_COMPUTE),
      FD7_COUNTABLE(PERF_PC_TESS_PC_MULTI_PATCH_TRANS),
};

static const struct fd_perfcntr_counter vfd_counters[] = {
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(0)), REG7(RBBM_PERFCTR_VFD(0))),
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(1)), REG7(RBBM_PERFCTR_VFD(1))),
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(2)), REG7(RBBM_PERFCTR_VFD(2))),
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(3)), REG7(RBBM_PERFCTR_VFD(3))),
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(4)), REG7(RBBM_PERFCTR_VFD(4))),
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(5)), REG7(RBBM_PERFCTR_VFD(5))),
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(6)), REG7(RBBM_PERFCTR_VFD(6))),
      FD7_COUNTER(REG6(VFD_PERFCTR_VFD_SEL(7)), REG7(RBBM_PERFCTR_VFD(7))),
};

static const struct fd_perfcntr_countable vfd_countables[] = {
      FD7_COUNTABLE(PERF_VFD_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_VFD_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_VFD_STALL_CYCLES_VPC_ALLOC),
      FD7_COUNTABLE(PERF_VFD_STALL_CYCLES_SP_INFO),
      FD7_COUNTABLE(PERF_VFD_STALL_CYCLES_SP_ATTR),
      FD7_COUNTABLE(PERF_VFD_STARVE_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_VFD_RBUFFER_FULL),
      FD7_COUNTABLE(PERF_VFD_ATTR_INFO_FIFO_FULL),
      FD7_COUNTABLE(PERF_VFD_DECODED_ATTRIBUTE_BYTES),
      FD7_COUNTABLE(PERF_VFD_NUM_ATTRIBUTES),
      FD7_COUNTABLE(PERF_VFD_UPPER_SHADER_FIBERS),
      FD7_COUNTABLE(PERF_VFD_LOWER_SHADER_FIBERS),
      FD7_COUNTABLE(PERF_VFD_MODE_0_FIBERS),
      FD7_COUNTABLE(PERF_VFD_MODE_1_FIBERS),
      FD7_COUNTABLE(PERF_VFD_MODE_2_FIBERS),
      FD7_COUNTABLE(PERF_VFD_MODE_3_FIBERS),
      FD7_COUNTABLE(PERF_VFD_MODE_4_FIBERS),
      FD7_COUNTABLE(PERF_VFD_TOTAL_VERTICES),
      FD7_COUNTABLE(PERF_VFDP_STALL_CYCLES_VFD),
      FD7_COUNTABLE(PERF_VFDP_STALL_CYCLES_VFD_INDEX),
      FD7_COUNTABLE(PERF_VFDP_STALL_CYCLES_VFD_PROG),
      FD7_COUNTABLE(PERF_VFDP_STARVE_CYCLES_PC),
      FD7_COUNTABLE(PERF_VFDP_VS_STAGE_WAVES),
      FD7_COUNTABLE(PERF_VFD_STALL_CYCLES_PRG_END_FE),
      FD7_COUNTABLE(PERF_VFD_STALL_CYCLES_CBSYNC),
};

static const struct fd_perfcntr_counter hlsq_counters[] = {
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(0)), REG7(RBBM_PERFCTR_HLSQ(0))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(1)), REG7(RBBM_PERFCTR_HLSQ(1))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(2)), REG7(RBBM_PERFCTR_HLSQ(2))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(3)), REG7(RBBM_PERFCTR_HLSQ(3))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(4)), REG7(RBBM_PERFCTR_HLSQ(4))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(5)), REG7(RBBM_PERFCTR_HLSQ(5))),
};

static const struct fd_perfcntr_countable hlsq_countables[] = {
      FD7_COUNTABLE(PERF_HLSQ_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_HLSQ_STALL_CYCLES_SP_STATE),
      FD7_COUNTABLE(PERF_HLSQ_STALL_CYCLES_SP_FS_STAGE),
      FD7_COUNTABLE(PERF_HLSQ_UCHE_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_UCHE_LATENCY_COUNT),
      FD7_COUNTABLE(PERF_HLSQ_RESERVED_6),
      FD7_COUNTABLE(PERF_HLSQ_RESERVED_7),
      FD7_COUNTABLE(PERF_HLSQ_RESERVED_8),
      FD7_COUNTABLE(PERF_HLSQ_RESERVED_9),
      FD7_COUNTABLE(PERF_HLSQ_COMPUTE_DRAWCALLS),
      FD7_COUNTABLE(PERF_HLSQ_FS_DATA_WAIT_PROGRAMMING),
      FD7_COUNTABLE(PERF_HLSQ_DUAL_FS_PROG_ACTIVE),
      FD7_COUNTABLE(PERF_HLSQ_DUAL_VS_PROG_ACTIVE),
      FD7_COUNTABLE(PERF_HLSQ_FS_BATCH_COUNT_ZERO),
      FD7_COUNTABLE(PERF_HLSQ_VS_BATCH_COUNT_ZERO),
      FD7_COUNTABLE(PERF_HLSQ_WAVE_PENDING_NO_QUAD),
      FD7_COUNTABLE(PERF_HLSQ_WAVE_PENDING_NO_PRIM_BASE),
      FD7_COUNTABLE(PERF_HLSQ_STALL_CYCLES_VPC),
      FD7_COUNTABLE(PERF_HLSQ_RESERVED_19),
      FD7_COUNTABLE(PERF_HLSQ_DRAW_MODE_SWITCH_VSFS_SYNC),
      FD7_COUNTABLE(PERF_HLSQ_VSBR_STALL_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_FS_STALL_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_LPAC_STALL_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_BV_STALL_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_VSBR_DEREF_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_FS_DEREF_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_LPAC_DEREF_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_BV_DEREF_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_VSBR_S2W_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_FS_S2W_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_LPAC_S2W_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_BV_S2W_CYCLES),
      FD7_COUNTABLE(PERF_HLSQ_VSBR_WAIT_FS_S2W),
      FD7_COUNTABLE(PERF_HLSQ_FS_WAIT_VS_S2W),
      FD7_COUNTABLE(PERF_HLSQ_LPAC_WAIT_VS_S2W),
      FD7_COUNTABLE(PERF_HLSQ_BV_WAIT_FS_S2W),
      FD7_COUNTABLE(PERF_HLSQ_VS_WAIT_CONST_RESOURCE),
      FD7_COUNTABLE(PERF_HLSQ_FS_WAIT_SAME_VS_S2W),
      FD7_COUNTABLE(PERF_HLSQ_FS_STARVING_SP),
      FD7_COUNTABLE(PERF_HLSQ_VS_DATA_WAIT_PROGRAMMING),
      FD7_COUNTABLE(PERF_HLSQ_BV_DATA_WAIT_PROGRAMMING),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXTS_VS),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXT_CYCLES_VS),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXTS_FS),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXT_CYCLES_FS),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXTS_BV),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXT_CYCLES_BV),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXTS_LPAC),
      FD7_COUNTABLE(PERF_HLSQ_STPROC_WAVE_CONTEXT_CYCLES_LPAC),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_WARMUP_INC_VS),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_WARMUP_INC_FS),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_WARMUP_INC_BV),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_WARMUP_INC_LPAC),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_MISS_INC_VS),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_MISS_INC_FS),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_MISS_INC_BV),
      FD7_COUNTABLE(PERF_HLSQ_SPTROC_STCHE_MISS_INC_LPAC),
};

static const struct fd_perfcntr_counter vpc_counters[] = {
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(0)), REG7(RBBM_PERFCTR_VPC(0))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(1)), REG7(RBBM_PERFCTR_VPC(1))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(2)), REG7(RBBM_PERFCTR_VPC(2))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(3)), REG7(RBBM_PERFCTR_VPC(3))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(4)), REG7(RBBM_PERFCTR_VPC(4))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(5)), REG7(RBBM_PERFCTR_VPC(5))),
};

static const struct fd_perfcntr_countable vpc_countables[] = {
      FD7_COUNTABLE(PERF_VPC_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_VPC_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_VFD_WACK),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_HLSQ_PRIM_ALLOC),
      FD7_COUNTABLE(PERF_VPC_RESERVED_5),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_SP_LM),
      FD7_COUNTABLE(PERF_VPC_STARVE_CYCLES_SP),
      FD7_COUNTABLE(PERF_VPC_STARVE_CYCLES_LRZ),
      FD7_COUNTABLE(PERF_VPC_PC_PRIMITIVES),
      FD7_COUNTABLE(PERF_VPC_SP_COMPONENTS),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_VPCRAM_POS),
      FD7_COUNTABLE(PERF_VPC_LRZ_ASSIGN_PRIMITIVES),
      FD7_COUNTABLE(PERF_VPC_RB_VISIBLE_PRIMITIVES),
      FD7_COUNTABLE(PERF_VPC_LM_TRANSACTION),
      FD7_COUNTABLE(PERF_VPC_STREAMOUT_TRANSACTION),
      FD7_COUNTABLE(PERF_VPC_VS_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_VPC_PS_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_VPC_VS_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_VPC_PS_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_VPC_STARVE_CYCLES_RB),
      FD7_COUNTABLE(PERF_VPC_NUM_VPCRAM_READ_POS),
      FD7_COUNTABLE(PERF_VPC_WIT_FULL_CYCLES),
      FD7_COUNTABLE(PERF_VPC_VPCRAM_FULL_CYCLES),
      FD7_COUNTABLE(PERF_VPC_LM_FULL_WAIT_FOR_INTP_END),
      FD7_COUNTABLE(PERF_VPC_NUM_VPCRAM_WRITE),
      FD7_COUNTABLE(PERF_VPC_NUM_VPCRAM_READ_SO),
      FD7_COUNTABLE(PERF_VPC_NUM_ATTR_REQ_LM),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLE_TSE),
      FD7_COUNTABLE(PERF_VPC_TSE_PRIMITIVES),
      FD7_COUNTABLE(PERF_VPC_GS_PRIMITIVES),
      FD7_COUNTABLE(PERF_VPC_TSE_TRANSACTIONS),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_CCU),
      FD7_COUNTABLE(PERF_VPC_NUM_WM_HIT),
      FD7_COUNTABLE(PERF_VPC_STALL_DQ_WACK),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_CCHE),
      FD7_COUNTABLE(PERF_VPC_STARVE_CYCLES_CCHE),
      FD7_COUNTABLE(PERF_VPC_NUM_PA_REQ),
      FD7_COUNTABLE(PERF_VPC_NUM_LM_REQ_HIT),
      FD7_COUNTABLE(PERF_VPC_CCHE_REQBUF_FULL),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_LM_ACK),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_PRG_END_FE),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_PRG_END_PCVS),
      FD7_COUNTABLE(PERF_VPC_STALL_CYCLES_PRG_END_VPCPS),
};

static const struct fd_perfcntr_counter tse_counters[] = {
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(0)), REG7(RBBM_PERFCTR_TSE(0))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(1)), REG7(RBBM_PERFCTR_TSE(1))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(2)), REG7(RBBM_PERFCTR_TSE(2))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(3)), REG7(RBBM_PERFCTR_TSE(3))),
};

static const struct fd_perfcntr_countable tse_countables[] = {
      FD7_COUNTABLE(PERF_TSE_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_TSE_CLIPPING_CYCLES),
      FD7_COUNTABLE(PERF_TSE_STALL_CYCLES_RAS),
      FD7_COUNTABLE(PERF_TSE_STALL_CYCLES_LRZ_BARYPLANE),
      FD7_COUNTABLE(PERF_TSE_STALL_CYCLES_LRZ_ZPLANE),
      FD7_COUNTABLE(PERF_TSE_STARVE_CYCLES_PC),
      FD7_COUNTABLE(PERF_TSE_INPUT_PRIM),
      FD7_COUNTABLE(PERF_TSE_INPUT_NULL_PRIM),
      FD7_COUNTABLE(PERF_TSE_TRIVAL_REJ_PRIM),
      FD7_COUNTABLE(PERF_TSE_CLIPPED_PRIM),
      FD7_COUNTABLE(PERF_TSE_ZERO_AREA_PRIM),
      FD7_COUNTABLE(PERF_TSE_FACENESS_CULLED_PRIM),
      FD7_COUNTABLE(PERF_TSE_ZERO_PIXEL_PRIM),
      FD7_COUNTABLE(PERF_TSE_OUTPUT_NULL_PRIM),
      FD7_COUNTABLE(PERF_TSE_OUTPUT_VISIBLE_PRIM),
      FD7_COUNTABLE(PERF_TSE_CINVOCATION),
      FD7_COUNTABLE(PERF_TSE_CPRIMITIVES),
      FD7_COUNTABLE(PERF_TSE_2D_INPUT_PRIM),
      FD7_COUNTABLE(PERF_TSE_2D_ALIVE_CYCLES),
      FD7_COUNTABLE(PERF_TSE_CLIP_PLANES),
};

static const struct fd_perfcntr_counter ras_counters[] = {
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(0)), REG7(RBBM_PERFCTR_RAS(0))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(1)), REG7(RBBM_PERFCTR_RAS(1))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(2)), REG7(RBBM_PERFCTR_RAS(2))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(3)), REG7(RBBM_PERFCTR_RAS(3))),
};

static const struct fd_perfcntr_countable ras_countables[] = {
      FD7_COUNTABLE(PERF_RAS_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_RAS_SUPERTILE_ACTIVE_CYCLES),
      FD7_COUNTABLE(PERF_RAS_STALL_CYCLES_LRZ),
      FD7_COUNTABLE(PERF_RAS_STARVE_CYCLES_TSE),
      FD7_COUNTABLE(PERF_RAS_SUPER_TILES),
      FD7_COUNTABLE(PERF_RAS_8X4_TILES),
      FD7_COUNTABLE(PERF_RAS_MASKGEN_ACTIVE),
      FD7_COUNTABLE(PERF_RAS_FULLY_COVERED_SUPER_TILES),
      FD7_COUNTABLE(PERF_RAS_FULLY_COVERED_8X4_TILES),
      FD7_COUNTABLE(PERF_RAS_PRIM_KILLED_INVISILBE),
      FD7_COUNTABLE(PERF_RAS_SUPERTILE_GEN_ACTIVE_CYCLES),
      FD7_COUNTABLE(PERF_RAS_LRZ_INTF_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_RAS_BLOCKS),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_0_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_1_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_2_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_3_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_4_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_5_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_6_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_7_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_8_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_9_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_10_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_11_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_12_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_13_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_14_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_SAMPLE_MASK_GEN_LANE_15_WORKING_CC_l2),
      FD7_COUNTABLE(PERF_RAS_FALSE_PARTIAL_STILE),
};

static const struct fd_perfcntr_counter uche_counters[] = {
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(0)), REG7(RBBM_PERFCTR_UCHE(0))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(1)), REG7(RBBM_PERFCTR_UCHE(1))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(2)), REG7(RBBM_PERFCTR_UCHE(2))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(3)), REG7(RBBM_PERFCTR_UCHE(3))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(4)), REG7(RBBM_PERFCTR_UCHE(4))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(5)), REG7(RBBM_PERFCTR_UCHE(5))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(6)), REG7(RBBM_PERFCTR_UCHE(6))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(7)), REG7(RBBM_PERFCTR_UCHE(7))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(8)), REG7(RBBM_PERFCTR_UCHE(8))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(9)), REG7(RBBM_PERFCTR_UCHE(9))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(10)), REG7(RBBM_PERFCTR_UCHE(10))),
      FD7_COUNTER(REG6(UCHE_PERFCTR_UCHE_SEL(11)), REG7(RBBM_PERFCTR_UCHE(11))),
};

static const struct fd_perfcntr_countable uche_countables[] = {
      FD7_COUNTABLE(PERF_UCHE_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_UCHE_STALL_CYCLES_ARBITER),
      FD7_COUNTABLE(PERF_UCHE_VBIF_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_UCHE_VBIF_LATENCY_SAMPLES),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_TP),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_VFD),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_HLSQ),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_LRZ),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_SP),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_TP),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_VFD),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_HLSQ),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_LRZ),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_SP),
      FD7_COUNTABLE(PERF_UCHE_WRITE_REQUESTS_LRZ),
      FD7_COUNTABLE(PERF_UCHE_WRITE_REQUESTS_SP),
      FD7_COUNTABLE(PERF_UCHE_WRITE_REQUESTS_VPC),
      FD7_COUNTABLE(PERF_UCHE_WRITE_REQUESTS_VSC),
      FD7_COUNTABLE(PERF_UCHE_EVICTS),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ0),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ1),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ2),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ3),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ4),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ5),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ6),
      FD7_COUNTABLE(PERF_UCHE_BANK_REQ7),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_CH0),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_CH1),
      FD7_COUNTABLE(PERF_UCHE_GMEM_READ_BEATS),
      FD7_COUNTABLE(PERF_UCHE_TPH_REF_FULL),
      FD7_COUNTABLE(PERF_UCHE_TPH_VICTIM_FULL),
      FD7_COUNTABLE(PERF_UCHE_TPH_EXT_FULL),
      FD7_COUNTABLE(PERF_UCHE_VBIF_STALL_WRITE_DATA),
      FD7_COUNTABLE(PERF_UCHE_DCMP_LATENCY_SAMPLES),
      FD7_COUNTABLE(PERF_UCHE_DCMP_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_UCHE_VBIF_READ_BEATS_PC),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_PC),
      FD7_COUNTABLE(PERF_UCHE_RAM_READ_REQ),
      FD7_COUNTABLE(PERF_UCHE_RAM_WRITE_REQ),
      FD7_COUNTABLE(PERF_UCHE_STARVED_CYCLES_VBIF_DECMP),
      FD7_COUNTABLE(PERF_UCHE_STALL_CYCLES_DECMP),
      FD7_COUNTABLE(PERF_UCHE_ARBITER_STALL_CYCLES_VBIF),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_TP_UBWC),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_TP_NONUBWC),
      FD7_COUNTABLE(PERF_UCHE_READ_REQUESTS_TP_GMEM),
      FD7_COUNTABLE(PERF_UCHE_LONG_LINE_ALL_EVICTS_KAILUA),
      FD7_COUNTABLE(PERF_UCHE_LONG_LINE_PARTIAL_EVICTS_KAILUA),
      FD7_COUNTABLE(PERF_UCHE_TPH_CONFLICT_CL_CCHE),
      FD7_COUNTABLE(PERF_UCHE_TPH_CONFLICT_CL_OTHER_KAILUA),
      FD7_COUNTABLE(PERF_UCHE_DBANK_CONFLICT_CL_CCHE),
      FD7_COUNTABLE(PERF_UCHE_DBANK_CONFLICT_CL_OTHER_CLIENTS),
      FD7_COUNTABLE(PERF_UCHE_VBIF_WRITE_BEATS_CH0),
      FD7_COUNTABLE(PERF_UCHE_VBIF_WRITE_BEATS_CH1),
      FD7_COUNTABLE(PERF_UCHE_CCHE_TPH_QUEUE_FULL),
      FD7_COUNTABLE(PERF_UCHE_CCHE_DPH_QUEUE_FULL),
      FD7_COUNTABLE(PERF_UCHE_GMEM_WRITE_BEATS),
      FD7_COUNTABLE(PERF_UCHE_UBWC_READ_BEATS),
      FD7_COUNTABLE(PERF_UCHE_UBWC_WRITE_BEATS),
};

static const struct fd_perfcntr_counter tp_counters[] = {
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(0)), REG7(RBBM_PERFCTR_TP(0))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(1)), REG7(RBBM_PERFCTR_TP(1))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(2)), REG7(RBBM_PERFCTR_TP(2))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(3)), REG7(RBBM_PERFCTR_TP(3))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(4)), REG7(RBBM_PERFCTR_TP(4))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(5)), REG7(RBBM_PERFCTR_TP(5))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(6)), REG7(RBBM_PERFCTR_TP(6))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(7)), REG7(RBBM_PERFCTR_TP(7))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(8)), REG7(RBBM_PERFCTR_TP(8))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(9)), REG7(RBBM_PERFCTR_TP(9))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(10)), REG7(RBBM_PERFCTR_TP(10))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(11)), REG7(RBBM_PERFCTR_TP(11))),
};

static const struct fd_perfcntr_countable tp_countables[] = {
      FD7_COUNTABLE(PERF_TP_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_TP_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_TP_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_TP_LATENCY_TRANS),
      FD7_COUNTABLE(PERF_TP_FLAG_FIFO_DELAY_SAMPLES),
      FD7_COUNTABLE(PERF_TP_FLAG_FIFO_DELAY_CYCLES),
      FD7_COUNTABLE(PERF_TP_L1_CACHELINE_REQUESTS),
      FD7_COUNTABLE(PERF_TP_L1_CACHELINE_MISSES),
      FD7_COUNTABLE(PERF_TP_SP_TP_TRANS),
      FD7_COUNTABLE(PERF_TP_TP_SP_TRANS),
      FD7_COUNTABLE(PERF_TP_OUTPUT_PIXELS),
      FD7_COUNTABLE(PERF_TP_FILTER_WORKLOAD_16BIT),
      FD7_COUNTABLE(PERF_TP_FILTER_WORKLOAD_32BIT),
      FD7_COUNTABLE(PERF_TP_QUADS_RECEIVED),
      FD7_COUNTABLE(PERF_TP_QUADS_OFFSET),
      FD7_COUNTABLE(PERF_TP_QUADS_SHADOW),
      FD7_COUNTABLE(PERF_TP_QUADS_ARRAY),
      FD7_COUNTABLE(PERF_TP_QUADS_GRADIENT),
      FD7_COUNTABLE(PERF_TP_QUADS_1D),
      FD7_COUNTABLE(PERF_TP_QUADS_2D),
      FD7_COUNTABLE(PERF_TP_QUADS_BUFFER),
      FD7_COUNTABLE(PERF_TP_QUADS_3D),
      FD7_COUNTABLE(PERF_TP_QUADS_CUBE),
      FD7_COUNTABLE(PERF_TP_DIVERGENT_QUADS_RECEIVED),
      FD7_COUNTABLE(PERF_TP_PRT_NON_RESIDENT_EVENTS),
      FD7_COUNTABLE(PERF_TP_OUTPUT_PIXELS_POINT),
      FD7_COUNTABLE(PERF_TP_OUTPUT_PIXELS_BILINEAR),
      FD7_COUNTABLE(PERF_TP_OUTPUT_PIXELS_MIP),
      FD7_COUNTABLE(PERF_TP_OUTPUT_PIXELS_ANISO),
      FD7_COUNTABLE(PERF_TP_OUTPUT_PIXELS_ZERO_LOD),
      FD7_COUNTABLE(PERF_TP_FLAG_CACHE_REQUESTS),
      FD7_COUNTABLE(PERF_TP_FLAG_CACHE_MISSES),
      FD7_COUNTABLE(PERF_TP_L1_5_L2_REQUESTS),
      FD7_COUNTABLE(PERF_TP_2D_OUTPUT_PIXELS),
      FD7_COUNTABLE(PERF_TP_2D_OUTPUT_PIXELS_POINT),
      FD7_COUNTABLE(PERF_TP_2D_OUTPUT_PIXELS_BILINEAR),
      FD7_COUNTABLE(PERF_TP_2D_FILTER_WORKLOAD_16BIT),
      FD7_COUNTABLE(PERF_TP_2D_FILTER_WORKLOAD_32BIT),
      FD7_COUNTABLE(PERF_TP_TPA2TPC_TRANS),
      FD7_COUNTABLE(PERF_TP_L1_MISSES_ASTC_1TILE),
      FD7_COUNTABLE(PERF_TP_L1_MISSES_ASTC_2TILE),
      FD7_COUNTABLE(PERF_TP_L1_MISSES_ASTC_4TILE),
      FD7_COUNTABLE(PERF_TP_L1_5_COMPRESS_REQS),
      FD7_COUNTABLE(PERF_TP_L1_5_L2_COMPRESS_MISS),
      FD7_COUNTABLE(PERF_TP_L1_BANK_CONFLICT),
      FD7_COUNTABLE(PERF_TP_L1_5_MISS_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_TP_L1_5_MISS_LATENCY_TRANS),
      FD7_COUNTABLE(PERF_TP_QUADS_CONSTANT_MULTIPLIED),
      FD7_COUNTABLE(PERF_TP_FRONTEND_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_TP_L1_TAG_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_TP_L1_DATA_WRITE_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_TP_PRE_L1_DECOM_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_TP_BACKEND_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_TP_L1_5_CACHE_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_TP_STARVE_CYCLES_SP),
      FD7_COUNTABLE(PERF_TP_STARVE_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_TP_STALL_CYCLES_UFC),
      FD7_COUNTABLE(PERF_TP_FORMAT_DECOMP),
      FD7_COUNTABLE(PERF_TP_FILTER_POINT_FP16),
      FD7_COUNTABLE(PERF_TP_FILTER_POINT_FP32),
      FD7_COUNTABLE(PERF_TP_LATENCY_FIFO_FULL),
      FD7_COUNTABLE(PERF_TP_RESERVED_61),
      FD7_COUNTABLE(PERF_TP_RESERVED_62),
      FD7_COUNTABLE(PERF_TP_RESERVED_63),
      FD7_COUNTABLE(PERF_TP_RESERVED_64),
      FD7_COUNTABLE(PERF_TP_RESERVED_65),
      FD7_COUNTABLE(PERF_TP_RESERVED_66),
      FD7_COUNTABLE(PERF_TP_RESERVED_67),
      FD7_COUNTABLE(PERF_TP_RESERVED_68),
      FD7_COUNTABLE(PERF_TP_RESERVED_69),
      FD7_COUNTABLE(PERF_TP_RESERVED_70),
      FD7_COUNTABLE(PERF_TP_RESERVED_71),
      FD7_COUNTABLE(PERF_TP_RESERVED_72),
      FD7_COUNTABLE(PERF_TP_RESERVED_73),
      FD7_COUNTABLE(PERF_TP_RESERVED_74),
      FD7_COUNTABLE(PERF_TP_RESERVED_75),
      FD7_COUNTABLE(PERF_TP_RESERVED_76),
      FD7_COUNTABLE(PERF_TP_RESERVED_77),
      FD7_COUNTABLE(PERF_TP_RESERVED_78),
      FD7_COUNTABLE(PERF_TP_RESERVED_79),
      FD7_COUNTABLE(PERF_TP_RESERVED_80),
      FD7_COUNTABLE(PERF_TP_RESERVED_81),
      FD7_COUNTABLE(PERF_TP_RESERVED_82),
      FD7_COUNTABLE(PERF_TP_RESERVED_83),
      FD7_COUNTABLE(PERF_TP_RESERVED_84),
      FD7_COUNTABLE(PERF_TP_RESERVED_85),
      FD7_COUNTABLE(PERF_TP_RESERVED_86),
      FD7_COUNTABLE(PERF_TP_RESERVED_87),
      FD7_COUNTABLE(PERF_TP_RESERVED_88),
      FD7_COUNTABLE(PERF_TP_RESERVED_89),
      FD7_COUNTABLE(PERF_TP_RESERVED_90),
      FD7_COUNTABLE(PERF_TP_RESERVED_91),
      FD7_COUNTABLE(PERF_TP_RESERVED_92),
      FD7_COUNTABLE(PERF_TP_RESERVED_93),
      FD7_COUNTABLE(PERF_TP_RESERVED_94),
      FD7_COUNTABLE(PERF_TP_RESERVED_95),
      FD7_COUNTABLE(PERF_TP_RESERVED_96),
      FD7_COUNTABLE(PERF_TP_RESERVED_97),
      FD7_COUNTABLE(PERF_TP_RESERVED_98),
      FD7_COUNTABLE(PERF_TP_RESERVED_99),
      FD7_COUNTABLE(PERF_TP_RESERVED_100),
      FD7_COUNTABLE(PERF_TP_RESERVED_101),
      FD7_COUNTABLE(PERF_TP_RESERVED_102),
      FD7_COUNTABLE(PERF_TP_RESERVED_103),
      FD7_COUNTABLE(PERF_TP_RESERVED_104),
      FD7_COUNTABLE(PERF_TP_RESERVED_105),
      FD7_COUNTABLE(PERF_TP_RESERVED_106),
      FD7_COUNTABLE(PERF_TP_RESERVED_107),
      FD7_COUNTABLE(PERF_TP_RESERVED_108),
      FD7_COUNTABLE(PERF_TP_RESERVED_109),
      FD7_COUNTABLE(PERF_TP_RESERVED_110),
      FD7_COUNTABLE(PERF_TP_RESERVED_111),
      FD7_COUNTABLE(PERF_TP_RESERVED_112),
      FD7_COUNTABLE(PERF_TP_RESERVED_113),
      FD7_COUNTABLE(PERF_TP_RESERVED_114),
      FD7_COUNTABLE(PERF_TP_RESERVED_115),
      FD7_COUNTABLE(PERF_TP_RESERVED_116),
      FD7_COUNTABLE(PERF_TP_RESERVED_117),
      FD7_COUNTABLE(PERF_TP_RESERVED_118),
      FD7_COUNTABLE(PERF_TP_RESERVED_119),
      FD7_COUNTABLE(PERF_TP_RESERVED_120),
      FD7_COUNTABLE(PERF_TP_RESERVED_121),
      FD7_COUNTABLE(PERF_TP_RESERVED_122),
      FD7_COUNTABLE(PERF_TP_RESERVED_123),
      FD7_COUNTABLE(PERF_TP_RESERVED_124),
      FD7_COUNTABLE(PERF_TP_RESERVED_125),
      FD7_COUNTABLE(PERF_TP_RESERVED_126),
      FD7_COUNTABLE(PERF_TP_RESERVED_127),
      FD7_COUNTABLE(PERF_TP_FORMAT_DECOMP_BILINEAR),
      FD7_COUNTABLE(PERF_TP_PACKED_POINT_BOTH_VALID_FP16),
      FD7_COUNTABLE(PERF_TP_PACKED_POINT_SINGLE_VALID_FP16),
      FD7_COUNTABLE(PERF_TP_PACKED_POINT_BOTH_VALID_FP32),
      FD7_COUNTABLE(PERF_TP_PACKED_POINT_SINGLE_VALID_FP32),
};

static const struct fd_perfcntr_counter sp_counters[] = {
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(0)), REG7(RBBM_PERFCTR_SP(0))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(1)), REG7(RBBM_PERFCTR_SP(1))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(2)), REG7(RBBM_PERFCTR_SP(2))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(3)), REG7(RBBM_PERFCTR_SP(3))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(4)), REG7(RBBM_PERFCTR_SP(4))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(5)), REG7(RBBM_PERFCTR_SP(5))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(6)), REG7(RBBM_PERFCTR_SP(6))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(7)), REG7(RBBM_PERFCTR_SP(7))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(8)), REG7(RBBM_PERFCTR_SP(8))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(9)), REG7(RBBM_PERFCTR_SP(9))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(10)), REG7(RBBM_PERFCTR_SP(10))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(11)), REG7(RBBM_PERFCTR_SP(11))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(12)), REG7(RBBM_PERFCTR_SP(12))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(13)), REG7(RBBM_PERFCTR_SP(13))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(14)), REG7(RBBM_PERFCTR_SP(14))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(15)), REG7(RBBM_PERFCTR_SP(15))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(16)), REG7(RBBM_PERFCTR_SP(16))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(17)), REG7(RBBM_PERFCTR_SP(17))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(18)), REG7(RBBM_PERFCTR_SP(18))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(19)), REG7(RBBM_PERFCTR_SP(19))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(20)), REG7(RBBM_PERFCTR_SP(20))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(21)), REG7(RBBM_PERFCTR_SP(21))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(22)), REG7(RBBM_PERFCTR_SP(22))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(23)), REG7(RBBM_PERFCTR_SP(23))),
};

static const struct fd_perfcntr_countable sp_countables[] = {
      FD7_COUNTABLE(PERF_SP_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_SP_ALU_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_EFU_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_STALL_CYCLES_VPC),
      FD7_COUNTABLE(PERF_SP_STALL_CYCLES_TP),
      FD7_COUNTABLE(PERF_SP_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_SP_STALL_CYCLES_RB),
      FD7_COUNTABLE(PERF_SP_NON_EXECUTION_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_CONTEXTS),
      FD7_COUNTABLE(PERF_SP_WAVE_CONTEXT_CYCLES),
      FD7_COUNTABLE(PERF_SP_STAGE_WAVE_CYCLES),
      FD7_COUNTABLE(PERF_SP_STAGE_WAVE_SAMPLES),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_WAVE_CYCLES),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_WAVE_SAMPLES),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_DURATION_CYCLES),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_DURATION_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_CTRL_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_LOAD_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_EMIT_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_NOP_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_WAIT_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_FETCH_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_IDLE_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_END_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_LONG_SYNC_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_SHORT_SYNC_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_JOIN_CYCLES),
      FD7_COUNTABLE(PERF_SP_LM_LOAD_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_LM_STORE_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_LM_ATOMICS),
      FD7_COUNTABLE(PERF_SP_GM_LOAD_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_GM_STORE_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_GM_ATOMICS),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_TEX_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_EFU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_HALF_ALU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_TEX_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_CFLOW_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_EFU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_BARY_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_VS_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_ADDR_LOCK_COUNT),
      FD7_COUNTABLE(PERF_SP_UCHE_READ_TRANS),
      FD7_COUNTABLE(PERF_SP_UCHE_WRITE_TRANS),
      FD7_COUNTABLE(PERF_SP_EXPORT_VPC_TRANS),
      FD7_COUNTABLE(PERF_SP_EXPORT_RB_TRANS),
      FD7_COUNTABLE(PERF_SP_PIXELS_KILLED),
      FD7_COUNTABLE(PERF_SP_ICL1_REQUESTS),
      FD7_COUNTABLE(PERF_SP_ICL1_MISSES),
      FD7_COUNTABLE(PERF_SP_HS_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_DS_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_GS_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_CS_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_GPR_READ),
      FD7_COUNTABLE(PERF_SP_GPR_WRITE),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_HALF_EFU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_VS_STAGE_HALF_EFU_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_LM_BANK_CONFLICTS),
      FD7_COUNTABLE(PERF_SP_TEX_CONTROL_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_LOAD_CONTROL_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_FLOW_CONTROL_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_LM_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_DISPATCHER_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_SEQUENCER_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_LOW_EFFICIENCY_STARVED_BY_TP),
      FD7_COUNTABLE(PERF_SP_STARVE_CYCLES_HLSQ),
      FD7_COUNTABLE(PERF_SP_NON_EXECUTION_LS_CYCLES),
      FD7_COUNTABLE(PERF_SP_WORKING_EU),
      FD7_COUNTABLE(PERF_SP_ANY_EU_WORKING),
      FD7_COUNTABLE(PERF_SP_WORKING_EU_FS_STAGE),
      FD7_COUNTABLE(PERF_SP_ANY_EU_WORKING_FS_STAGE),
      FD7_COUNTABLE(PERF_SP_WORKING_EU_VS_STAGE),
      FD7_COUNTABLE(PERF_SP_ANY_EU_WORKING_VS_STAGE),
      FD7_COUNTABLE(PERF_SP_WORKING_EU_CS_STAGE),
      FD7_COUNTABLE(PERF_SP_ANY_EU_WORKING_CS_STAGE),
      FD7_COUNTABLE(PERF_SP_GPR_READ_PREFETCH),
      FD7_COUNTABLE(PERF_SP_GPR_READ_CONFLICT),
      FD7_COUNTABLE(PERF_SP_GPR_WRITE_CONFLICT),
      FD7_COUNTABLE(PERF_SP_GM_LOAD_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_SP_GM_LOAD_LATENCY_SAMPLES),
      FD7_COUNTABLE(PERF_SP_EXECUTABLE_WAVES),
      FD7_COUNTABLE(PERF_SP_ICL1_MISS_FETCH_CYCLES),
      FD7_COUNTABLE(PERF_SP_WORKING_EU_LPAC),
      FD7_COUNTABLE(PERF_SP_BYPASS_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_SP_ANY_EU_WORKING_LPAC),
      FD7_COUNTABLE(PERF_SP_WAVE_ALU_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_EFU_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_INT_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_CSP_CYCLES),
      FD7_COUNTABLE(PERF_SP_EWAVE_CONTEXTS),
      FD7_COUNTABLE(PERF_SP_EWAVE_CONTEXT_CYCLES),
      FD7_COUNTABLE(PERF_SP_LPAC_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_SP_LPAC_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_1X_WAVES),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_2X_WAVES),
      FD7_COUNTABLE(PERF_SP_QUADS),
      FD7_COUNTABLE(PERF_SP_CS_INVOCATIONS),
      FD7_COUNTABLE(PERF_SP_PIXELS),
      FD7_COUNTABLE(PERF_SP_LPAC_DRAWCALLS),
      FD7_COUNTABLE(PERF_SP_PI_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_INPUT_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_OUTPUT_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_HWAVE_WAIT_CYCLES),
      FD7_COUNTABLE(PERF_SP_WAVE_HWAVE_SYNC),
      FD7_COUNTABLE(PERF_SP_OUTPUT_3D_PIXELS),
      FD7_COUNTABLE(PERF_SP_FULL_ALU_MAD_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_HALF_ALU_MAD_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FULL_ALU_MUL_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_HALF_ALU_MUL_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_FULL_ALU_ADD_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_HALF_ALU_ADD_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_BARY_FP32_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_ALU_GPR_READ_CYCLES),
      FD7_COUNTABLE(PERF_SP_ALU_DATA_FORWARDING_CYCLES),
      FD7_COUNTABLE(PERF_SP_LM_FULL_CYCLES),
      FD7_COUNTABLE(PERF_SP_TEXTURE_FETCH_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_SP_TEXTURE_FETCH_LATENCY_SAMPLES),
      FD7_COUNTABLE(PERF_SP_FS_STAGE_PI_TEX_INSTRUCTION),
      FD7_COUNTABLE(PERF_SP_RAY_QUERY_INSTRUCTIONS),
      FD7_COUNTABLE(PERF_SP_RBRT_KICKOFF_FIBERS),
      FD7_COUNTABLE(PERF_SP_RBRT_KICKOFF_DQUADS),
      FD7_COUNTABLE(PERF_SP_RTU_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_SP_RTU_L0_HITS),
      FD7_COUNTABLE(PERF_SP_RTU_L0_MISSES),
      FD7_COUNTABLE(PERF_SP_RTU_L0_HIT_ON_MISS),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_WAVE_QUEUE),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_L0_HIT_QUEUE),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_L0_MISS_QUEUE),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_L0D_IDX_QUEUE),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_L0DATA),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_REPLACE_CNT),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_MRG_CNT),
      FD7_COUNTABLE(PERF_SP_RTU_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_SP_RTU_OPERAND_FETCH_STALL_CYCLES_L0),
      FD7_COUNTABLE(PERF_SP_RTU_OPERAND_FETCH_STALL_CYCLES_INS_FIFO),
      FD7_COUNTABLE(PERF_SP_RTU_BVH_FETCH_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_SP_RTU_BVH_FETCH_LATENCY_SAMPLES),
      FD7_COUNTABLE(PERF_SP_STCHE_MISS_INC_VS),
      FD7_COUNTABLE(PERF_SP_STCHE_MISS_INC_FS),
      FD7_COUNTABLE(PERF_SP_STCHE_MISS_INC_BV),
      FD7_COUNTABLE(PERF_SP_STCHE_MISS_INC_LPAC),
      FD7_COUNTABLE(PERF_SP_VGPR_ACTIVE_CONTEXTS),
      FD7_COUNTABLE(PERF_SP_PGPR_ALLOC_CONTEXTS),
      FD7_COUNTABLE(PERF_SP_VGPR_ALLOC_CONTEXTS),
      FD7_COUNTABLE(PERF_SP_RTU_RAY_BOX_INTERSECTIONS),
      FD7_COUNTABLE(PERF_SP_RTU_RAY_TRIANGLE_INTERSECTIONS),
      FD7_COUNTABLE(PERF_SP_SCH_STALL_CYCLES_RTU),
};

static const struct fd_perfcntr_counter rb_counters[] = {
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(0)), REG7(RBBM_PERFCTR_RB(0))),
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(1)), REG7(RBBM_PERFCTR_RB(1))),
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(2)), REG7(RBBM_PERFCTR_RB(2))),
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(3)), REG7(RBBM_PERFCTR_RB(3))),
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(4)), REG7(RBBM_PERFCTR_RB(4))),
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(5)), REG7(RBBM_PERFCTR_RB(5))),
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(6)), REG7(RBBM_PERFCTR_RB(6))),
      FD7_COUNTER(REG6(RB_PERFCTR_RB_SEL(7)), REG7(RBBM_PERFCTR_RB(7))),
};

static const struct fd_perfcntr_countable rb_countables[] = {
      FD7_COUNTABLE(PERF_RB_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_HLSQ),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_FIFO0_FULL),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_FIFO1_FULL),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_FIFO2_FULL),
      FD7_COUNTABLE(PERF_RB_STARVE_CYCLES_SP),
      FD7_COUNTABLE(PERF_RB_STARVE_CYCLES_LRZ_TILE),
      FD7_COUNTABLE(PERF_RB_STARVE_CYCLES_CCU),
      FD7_COUNTABLE(PERF_RB_STARVE_CYCLES_Z_PLANE),
      FD7_COUNTABLE(PERF_RB_STARVE_CYCLES_BARY_PLANE),
      FD7_COUNTABLE(PERF_RB_Z_WORKLOAD),
      FD7_COUNTABLE(PERF_RB_HLSQ_ACTIVE),
      FD7_COUNTABLE(PERF_RB_Z_READ),
      FD7_COUNTABLE(PERF_RB_Z_WRITE),
      FD7_COUNTABLE(PERF_RB_C_READ),
      FD7_COUNTABLE(PERF_RB_C_WRITE),
      FD7_COUNTABLE(PERF_RB_TOTAL_PASS),
      FD7_COUNTABLE(PERF_RB_Z_PASS),
      FD7_COUNTABLE(PERF_RB_Z_FAIL),
      FD7_COUNTABLE(PERF_RB_S_FAIL),
      FD7_COUNTABLE(PERF_RB_BLENDED_FXP_COMPONENTS),
      FD7_COUNTABLE(PERF_RB_BLENDED_FP16_COMPONENTS),
      FD7_COUNTABLE(PERF_RB_PS_INVOCATIONS),
      FD7_COUNTABLE(PERF_RB_2D_ALIVE_CYCLES),
      FD7_COUNTABLE(PERF_RB_2D_STALL_CYCLES_A2D),
      FD7_COUNTABLE(PERF_RB_2D_STARVE_CYCLES_SRC),
      FD7_COUNTABLE(PERF_RB_2D_STARVE_CYCLES_SP),
      FD7_COUNTABLE(PERF_RB_2D_STARVE_CYCLES_DST),
      FD7_COUNTABLE(PERF_RB_2D_VALID_PIXELS),
      FD7_COUNTABLE(PERF_RB_3D_PIXELS),
      FD7_COUNTABLE(PERF_RB_BLENDER_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_RB_ZPROC_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_RB_CPROC_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_RB_SAMPLER_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_CCU_COLOR_READ),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_CCU_COLOR_WRITE),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_CCU_DEPTH_READ),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_CCU_DEPTH_WRITE),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_VPC),
      FD7_COUNTABLE(PERF_RB_2D_INPUT_TRANS),
      FD7_COUNTABLE(PERF_RB_2D_OUTPUT_RB_DST_TRANS),
      FD7_COUNTABLE(PERF_RB_2D_OUTPUT_RB_SRC_TRANS),
      FD7_COUNTABLE(PERF_RB_BLENDED_FP32_COMPONENTS),
      FD7_COUNTABLE(PERF_RB_COLOR_PIX_TILES),
      FD7_COUNTABLE(PERF_RB_STALL_CYCLES_CCU),
      FD7_COUNTABLE(PERF_RB_EARLY_Z_ARB3_GRANT),
      FD7_COUNTABLE(PERF_RB_LATE_Z_ARB3_GRANT),
      FD7_COUNTABLE(PERF_RB_EARLY_Z_SKIP_GRANT),
      FD7_COUNTABLE(PERF_RB_VRS_1x1_QUADS),
      FD7_COUNTABLE(PERF_RB_VRS_2x1_QUADS),
      FD7_COUNTABLE(PERF_RB_VRS_1x2_QUADS),
      FD7_COUNTABLE(PERF_RB_VRS_2x2_QUADS),
      FD7_COUNTABLE(PERF_RB_VRS_4x2_QUADS),
      FD7_COUNTABLE(PERF_RB_VRS_4x4_QUADS),
};

static const struct fd_perfcntr_counter vsc_counters[] = {
      FD7_COUNTER(REG6(VSC_PERFCTR_VSC_SEL(0)), REG7(RBBM_PERFCTR_VSC(0))),
      FD7_COUNTER(REG6(VSC_PERFCTR_VSC_SEL(1)), REG7(RBBM_PERFCTR_VSC(1))),
};

static const struct fd_perfcntr_countable vsc_countables[] = {
      FD7_COUNTABLE(PERF_VSC_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_VSC_WORKING_CYCLES),
      FD7_COUNTABLE(PERF_VSC_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_VSC_EOT_NUM),
      FD7_COUNTABLE(PERF_VSC_INPUT_TILES),
};

static const struct fd_perfcntr_counter ccu_counters[] = {
      FD7_COUNTER(REG6(RB_PERFCTR_CCU_SEL(0)), REG7(RBBM_PERFCTR_CCU(0))),
      FD7_COUNTER(REG6(RB_PERFCTR_CCU_SEL(1)), REG7(RBBM_PERFCTR_CCU(1))),
      FD7_COUNTER(REG6(RB_PERFCTR_CCU_SEL(2)), REG7(RBBM_PERFCTR_CCU(2))),
      FD7_COUNTER(REG6(RB_PERFCTR_CCU_SEL(3)), REG7(RBBM_PERFCTR_CCU(3))),
      FD7_COUNTER(REG6(RB_PERFCTR_CCU_SEL(4)), REG7(RBBM_PERFCTR_CCU(4))),
};

static const struct fd_perfcntr_countable ccu_countables[] = {
      FD7_COUNTABLE(PERF_CCU_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_CCU_STALL_CYCLES_RB_DEPTH_RETURN),
      FD7_COUNTABLE(PERF_CCU_STALL_CYCLES_RB_COLOR_RETURN),
      FD7_COUNTABLE(PERF_CCU_DEPTH_BLOCKS),
      FD7_COUNTABLE(PERF_CCU_COLOR_BLOCKS),
      FD7_COUNTABLE(PERF_CCU_DEPTH_BLOCK_HIT),
      FD7_COUNTABLE(PERF_CCU_COLOR_BLOCK_HIT),
      FD7_COUNTABLE(PERF_CCU_PARTIAL_BLOCK_READ),
      FD7_COUNTABLE(PERF_CCU_GMEM_READ),
      FD7_COUNTABLE(PERF_CCU_GMEM_WRITE),
      FD7_COUNTABLE(PERF_CCU_2D_RD_REQ),
      FD7_COUNTABLE(PERF_CCU_2D_WR_REQ),
      FD7_COUNTABLE(PERF_CCU_UBWC_COLOR_BLOCKS_CONCURRENT),
      FD7_COUNTABLE(PERF_CCU_UBWC_DEPTH_BLOCKS_CONCURRENT),
      FD7_COUNTABLE(PERF_CCU_COLOR_RESOLVE_DROPPED),
      FD7_COUNTABLE(PERF_CCU_DEPTH_RESOLVE_DROPPED),
      FD7_COUNTABLE(PERF_CCU_COLOR_RENDER_CONCURRENT),
      FD7_COUNTABLE(PERF_CCU_DEPTH_RENDER_CONCURRENT),
      FD7_COUNTABLE(PERF_CCU_COLOR_RESOLVE_AFTER_RENDER),
      FD7_COUNTABLE(PERF_CCU_DEPTH_RESOLVE_AFTER_RENDER),
      FD7_COUNTABLE(PERF_CCU_GMEM_EXTRA_DEPTH_READ),
      FD7_COUNTABLE(PERF_CCU_GMEM_COLOR_READ_4AA),
      FD7_COUNTABLE(PERF_CCU_GMEM_COLOR_READ_4AA_FULL),
};

static const struct fd_perfcntr_counter lrz_counters[] = {
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(0)), REG7(RBBM_PERFCTR_LRZ(0))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(1)), REG7(RBBM_PERFCTR_LRZ(1))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(2)), REG7(RBBM_PERFCTR_LRZ(2))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(3)), REG7(RBBM_PERFCTR_LRZ(3))),
};

static const struct fd_perfcntr_countable lrz_countables[] = {
      FD7_COUNTABLE(PERF_LRZ_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_LRZ_STARVE_CYCLES_RAS),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_RB),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_VSC),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_VPC),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_FLAG_PREFETCH),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_UCHE),
      FD7_COUNTABLE(PERF_LRZ_LRZ_READ),
      FD7_COUNTABLE(PERF_LRZ_LRZ_WRITE),
      FD7_COUNTABLE(PERF_LRZ_READ_LATENCY),
      FD7_COUNTABLE(PERF_LRZ_MERGE_CACHE_UPDATING),
      FD7_COUNTABLE(PERF_LRZ_PRIM_KILLED_BY_MASKGEN),
      FD7_COUNTABLE(PERF_LRZ_PRIM_KILLED_BY_LRZ),
      FD7_COUNTABLE(PERF_LRZ_VISIBLE_PRIM_AFTER_LRZ),
      FD7_COUNTABLE(PERF_LRZ_FULL_8X8_TILES),
      FD7_COUNTABLE(PERF_LRZ_PARTIAL_8X8_TILES),
      FD7_COUNTABLE(PERF_LRZ_TILE_KILLED),
      FD7_COUNTABLE(PERF_LRZ_TOTAL_PIXEL),
      FD7_COUNTABLE(PERF_LRZ_VISIBLE_PIXEL_AFTER_LRZ),
      FD7_COUNTABLE(PERF_LRZ_FEEDBACK_ACCEPT),
      FD7_COUNTABLE(PERF_LRZ_FEEDBACK_DISCARD),
      FD7_COUNTABLE(PERF_LRZ_FEEDBACK_STALL),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_RB_ZPLANE),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_RB_BPLANE),
      FD7_COUNTABLE(PERF_LRZ_RAS_MASK_TRANS),
      FD7_COUNTABLE(PERF_LRZ_STALL_CYCLES_MVC),
      FD7_COUNTABLE(PERF_LRZ_TILE_KILLED_BY_IMAGE_VRS),
      FD7_COUNTABLE(PERF_LRZ_TILE_KILLED_BY_Z),
};

static const struct fd_perfcntr_counter cmp_counters[] = {
      FD7_COUNTER(REG6(RB_PERFCTR_CMP_SEL(0)), REG7(RBBM_PERFCTR_CMP(0))),
      FD7_COUNTER(REG6(RB_PERFCTR_CMP_SEL(1)), REG7(RBBM_PERFCTR_CMP(1))),
      FD7_COUNTER(REG6(RB_PERFCTR_CMP_SEL(2)), REG7(RBBM_PERFCTR_CMP(2))),
      FD7_COUNTER(REG6(RB_PERFCTR_CMP_SEL(3)), REG7(RBBM_PERFCTR_CMP(3))),
};

static const struct fd_perfcntr_countable cmp_countables[] = {
      FD7_COUNTABLE(PERF_CMPDECMP_STALL_CYCLES_ARB),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_LATENCY_SAMPLES),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_READ_DATA_CCU),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_WRITE_DATA_CCU),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_READ_REQUEST),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_WRITE_REQUEST),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_READ_DATA),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_WRITE_DATA),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG1_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG2_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG3_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG4_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG5_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG6_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG8_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG1_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG2_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG3_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG4_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG5_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG6_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG8_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_READ_DATA_UCHE_CH0),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_READ_DATA_UCHE_CH1),
      FD7_COUNTABLE(PERF_CMPDECMP_VBIF_WRITE_DATA_UCHE),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_WRITE_FLAG0_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAG0_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_WRITE_FLAGALPHA_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_RESOLVE_EVENTS),
      FD7_COUNTABLE(PERF_CMPDECMP_CONCURRENT_RESOLVE_EVENTS),
      FD7_COUNTABLE(PERF_CMPDECMP_DROPPED_CLEAR_EVENTS),
      FD7_COUNTABLE(PERF_CMPDECMP_ST_BLOCKS_CONCURRENT),
      FD7_COUNTABLE(PERF_CMPDECMP_LRZ_ST_BLOCKS_CONCURRENT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG0_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG1_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG2_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG3_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG4_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG5_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG6_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_DEPTH_READ_FLAG8_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG0_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG1_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG2_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG3_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG4_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG5_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG6_COUNT),
      FD7_COUNTABLE(PERF_CMPDECMP_COLOR_READ_FLAG8_COUNT),
};

static const struct fd_perfcntr_counter ufc_counters[] = {
      FD7_COUNTER(REG7(RB_PERFCTR_UFC_SEL(0)), REG7(RBBM_PERFCTR_UFC(0))),
      FD7_COUNTER(REG7(RB_PERFCTR_UFC_SEL(1)), REG7(RBBM_PERFCTR_UFC(1))),
      FD7_COUNTER(REG7(RB_PERFCTR_UFC_SEL(2)), REG7(RBBM_PERFCTR_UFC(2))),
      FD7_COUNTER(REG7(RB_PERFCTR_UFC_SEL(3)), REG7(RBBM_PERFCTR_UFC(3))),
};

static const struct fd_perfcntr_countable ufc_countables[] = {
      FD7_COUNTABLE(PERF_UFC_BUSY_CYCLES),
      FD7_COUNTABLE(PERF_UFC_READ_DATA_VBIF),
      FD7_COUNTABLE(PERF_UFC_WRITE_DATA_VBIF),
      FD7_COUNTABLE(PERF_UFC_READ_REQUEST_VBIF),
      FD7_COUNTABLE(PERF_UFC_WRITE_REQUEST_VBIF),
      FD7_COUNTABLE(PERF_UFC_LRZ_FILTER_HIT),
      FD7_COUNTABLE(PERF_UFC_LRZ_FILTER_MISS),
      FD7_COUNTABLE(PERF_UFC_CRE_FILTER_HIT),
      FD7_COUNTABLE(PERF_UFC_CRE_FILTER_MISS),
      FD7_COUNTABLE(PERF_UFC_SP_FILTER_HIT),
      FD7_COUNTABLE(PERF_UFC_SP_FILTER_MISS),
      FD7_COUNTABLE(PERF_UFC_SP_REQUESTS),
      FD7_COUNTABLE(PERF_UFC_TP_FILTER_HIT),
      FD7_COUNTABLE(PERF_UFC_TP_FILTER_MISS),
      FD7_COUNTABLE(PERF_UFC_TP_REQUESTS),
      FD7_COUNTABLE(PERF_UFC_MAIN_HIT_LRZ_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_HIT_CRE_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_HIT_SP_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_HIT_TP_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_HIT_UBWC_READ),
      FD7_COUNTABLE(PERF_UFC_MAIN_HIT_UBWC_WRITE),
      FD7_COUNTABLE(PERF_UFC_MAIN_MISS_LRZ_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_MISS_CRE_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_MISS_SP_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_MISS_TP_PREFETCH),
      FD7_COUNTABLE(PERF_UFC_MAIN_MISS_UBWC_READ),
      FD7_COUNTABLE(PERF_UFC_MAIN_MISS_UBWC_WRITE),
      FD7_COUNTABLE(PERF_UFC_UBWC_READ_UFC_TRANS),
      FD7_COUNTABLE(PERF_UFC_UBWC_WRITE_UFC_TRANS),
      FD7_COUNTABLE(PERF_UFC_STALL_CYCLES_GBIF_CMD),
      FD7_COUNTABLE(PERF_UFC_STALL_CYCLES_GBIF_RDATA),
      FD7_COUNTABLE(PERF_UFC_STALL_CYCLES_GBIF_WDATA),
      FD7_COUNTABLE(PERF_UFC_STALL_CYCLES_UBWC_WR_FLAG),
      FD7_COUNTABLE(PERF_UFC_STALL_CYCLES_UBWC_FLAG_RTN),
      FD7_COUNTABLE(PERF_UFC_STALL_CYCLES_UBWC_EVENT),
      FD7_COUNTABLE(PERF_UFC_LRZ_PREFETCH_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_CRE_PREFETCH_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_SPTP_PREFETCH_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_UBWC_RD_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_UBWC_WR_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_PREFETCH_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_EVICTION_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_LOCK_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_MISS_LATENCY_CYCLES),
      FD7_COUNTABLE(PERF_UFC_MISS_LATENCY_SAMPLES),
      FD7_COUNTABLE(PERF_UFC_UBWC_REQ_STALLED_CYCLES),
      FD7_COUNTABLE(PERF_UFC_TP_HINT_TAG_MISS),
      FD7_COUNTABLE(PERF_UFC_TP_HINT_TAG_HIT_RDY),
      FD7_COUNTABLE(PERF_UFC_TP_HINT_TAG_HIT_NRDY),
      FD7_COUNTABLE(PERF_UFC_TP_HINT_IS_FCLEAR),
      FD7_COUNTABLE(PERF_UFC_TP_HINT_IS_ALPHA0),
      FD7_COUNTABLE(PERF_UFC_SP_L1_FILTER_HIT),
      FD7_COUNTABLE(PERF_UFC_SP_L1_FILTER_MISS),
      FD7_COUNTABLE(PERF_UFC_SP_L1_FILTER_REQUESTS),
      FD7_COUNTABLE(PERF_UFC_TP_L1_TAG_HIT_RDY),
      FD7_COUNTABLE(PERF_UFC_TP_L1_TAG_HIT_NRDY),
      FD7_COUNTABLE(PERF_UFC_TP_L1_TAG_MISS),
      FD7_COUNTABLE(PERF_UFC_TP_L1_FILTER_REQUESTS),
};

static const struct fd_perfcntr_counter bv_cp_counters[] = {
      FD7_COUNTER(REG7(CP_BV_PERFCTR_CP_SEL(0)), REG7(RBBM_PERFCTR2_CP(0))),
      FD7_COUNTER(REG7(CP_BV_PERFCTR_CP_SEL(1)), REG7(RBBM_PERFCTR2_CP(1))),
      FD7_COUNTER(REG7(CP_BV_PERFCTR_CP_SEL(2)), REG7(RBBM_PERFCTR2_CP(2))),
      FD7_COUNTER(REG7(CP_BV_PERFCTR_CP_SEL(3)), REG7(RBBM_PERFCTR2_CP(3))),
      FD7_COUNTER(REG7(CP_BV_PERFCTR_CP_SEL(4)), REG7(RBBM_PERFCTR2_CP(4))),
      FD7_COUNTER(REG7(CP_BV_PERFCTR_CP_SEL(5)), REG7(RBBM_PERFCTR2_CP(5))),
      FD7_COUNTER(REG7(CP_BV_PERFCTR_CP_SEL(6)), REG7(RBBM_PERFCTR2_CP(6))),
};

static const struct fd_perfcntr_counter bv_pc_counters[] = {
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(8)), REG7(RBBM_PERFCTR_BV_PC(0))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(9)), REG7(RBBM_PERFCTR_BV_PC(1))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(10)), REG7(RBBM_PERFCTR_BV_PC(2))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(11)), REG7(RBBM_PERFCTR_BV_PC(3))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(12)), REG7(RBBM_PERFCTR_BV_PC(4))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(13)), REG7(RBBM_PERFCTR_BV_PC(5))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(14)), REG7(RBBM_PERFCTR_BV_PC(6))),
      FD7_COUNTER(REG7(PC_PERFCTR_PC_SEL(15)), REG7(RBBM_PERFCTR_BV_PC(7))),
};

static const struct fd_perfcntr_counter bv_vfd_counters[] = {
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(8)), REG7(RBBM_PERFCTR_BV_VFD(0))),
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(9)), REG7(RBBM_PERFCTR_BV_VFD(1))),
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(10)), REG7(RBBM_PERFCTR_BV_VFD(2))),
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(11)), REG7(RBBM_PERFCTR_BV_VFD(3))),
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(12)), REG7(RBBM_PERFCTR_BV_VFD(4))),
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(13)), REG7(RBBM_PERFCTR_BV_VFD(5))),
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(14)), REG7(RBBM_PERFCTR_BV_VFD(6))),
      FD7_COUNTER(REG7(VFD_PERFCTR_VFD_SEL(15)), REG7(RBBM_PERFCTR_BV_VFD(7))),
};

static const struct fd_perfcntr_counter bv_vpc_counters[] = {
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(6)), REG7(RBBM_PERFCTR_BV_VPC(0))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(7)), REG7(RBBM_PERFCTR_BV_VPC(1))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(8)), REG7(RBBM_PERFCTR_BV_VPC(2))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(9)), REG7(RBBM_PERFCTR_BV_VPC(3))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(10)), REG7(RBBM_PERFCTR_BV_VPC(4))),
      FD7_COUNTER(REG7(VPC_PERFCTR_VPC_SEL(11)), REG7(RBBM_PERFCTR_BV_VPC(5))),
};

static const struct fd_perfcntr_counter bv_tp_counters[] = {
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(12)), REG7(RBBM_PERFCTR2_TP(0))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(13)), REG7(RBBM_PERFCTR2_TP(1))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(14)), REG7(RBBM_PERFCTR2_TP(2))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(15)), REG7(RBBM_PERFCTR2_TP(3))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(16)), REG7(RBBM_PERFCTR2_TP(4))),
      FD7_COUNTER(REG7(TPL1_PERFCTR_TP_SEL(17)), REG7(RBBM_PERFCTR2_TP(5))),
};

static const struct fd_perfcntr_counter bv_sp_counters[] = {
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(24)), REG7(RBBM_PERFCTR2_SP(0))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(25)), REG7(RBBM_PERFCTR2_SP(1))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(26)), REG7(RBBM_PERFCTR2_SP(2))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(27)), REG7(RBBM_PERFCTR2_SP(3))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(28)), REG7(RBBM_PERFCTR2_SP(4))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(29)), REG7(RBBM_PERFCTR2_SP(5))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(30)), REG7(RBBM_PERFCTR2_SP(6))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(31)), REG7(RBBM_PERFCTR2_SP(7))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(32)), REG7(RBBM_PERFCTR2_SP(8))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(33)), REG7(RBBM_PERFCTR2_SP(9))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(34)), REG7(RBBM_PERFCTR2_SP(10))),
      FD7_COUNTER(REG7(SP_PERFCTR_SP_SEL(35)), REG7(RBBM_PERFCTR2_SP(11))),
};

static const struct fd_perfcntr_counter bv_ufc_counters[] = {
      FD7_COUNTER(REG7(RB_PERFCTR_UFC_SEL(4)), REG7(RBBM_PERFCTR2_UFC(0))),
      FD7_COUNTER(REG7(RB_PERFCTR_UFC_SEL(5)), REG7(RBBM_PERFCTR2_UFC(1))),
};

static const struct fd_perfcntr_counter bv_tse_counters[] = {
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(0)), REG7(RBBM_PERFCTR_BV_TSE(0))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(1)), REG7(RBBM_PERFCTR_BV_TSE(1))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(2)), REG7(RBBM_PERFCTR_BV_TSE(2))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_TSE_SEL(3)), REG7(RBBM_PERFCTR_BV_TSE(3))),
};

static const struct fd_perfcntr_counter bv_ras_counters[] = {
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(0)), REG7(RBBM_PERFCTR_BV_RAS(0))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(1)), REG7(RBBM_PERFCTR_BV_RAS(1))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(2)), REG7(RBBM_PERFCTR_BV_RAS(2))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_RAS_SEL(3)), REG7(RBBM_PERFCTR_BV_RAS(3))),
};

static const struct fd_perfcntr_counter bv_lrz_counters[] = {
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(0)), REG7(RBBM_PERFCTR_BV_LRZ(0))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(1)), REG7(RBBM_PERFCTR_BV_LRZ(1))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(2)), REG7(RBBM_PERFCTR_BV_LRZ(2))),
      FD7_COUNTER(REG6(GRAS_PERFCTR_LRZ_SEL(3)), REG7(RBBM_PERFCTR_BV_LRZ(3))),
};

static const struct fd_perfcntr_counter bv_hlsq_counters[] = {
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(0)), REG7(RBBM_PERFCTR2_HLSQ(0))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(1)), REG7(RBBM_PERFCTR2_HLSQ(1))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(2)), REG7(RBBM_PERFCTR2_HLSQ(2))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(3)), REG7(RBBM_PERFCTR2_HLSQ(3))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(4)), REG7(RBBM_PERFCTR2_HLSQ(4))),
      FD7_COUNTER(REG7(SP_PERFCTR_HLSQ_SEL(5)), REG7(RBBM_PERFCTR2_HLSQ(5))),
};

const struct fd_perfcntr_group a7xx_perfcntr_groups[] = {
      GROUP("CP", cp_counters, cp_countables),
      GROUP("RBBM", rbbm_counters, rbbm_countables),
      GROUP("PC", pc_counters, pc_countables),
      GROUP("VFD", vfd_counters, vfd_countables),
      GROUP("HLSQ", hlsq_counters, hlsq_countables),
      GROUP("VPC", vpc_counters, vpc_countables),
      GROUP("TSE", tse_counters, tse_countables),
      GROUP("RAS", ras_counters, ras_countables),
      GROUP("UCHE", uche_counters, uche_countables),
      GROUP("TP", tp_counters, tp_countables),
      GROUP("SP", sp_counters, sp_countables),
      GROUP("RB", rb_counters, rb_countables),
      GROUP("VSC", vsc_counters, vsc_countables),
      GROUP("CCU", ccu_counters, ccu_countables),
      GROUP("LRZ", lrz_counters, lrz_countables),
      GROUP("CMP", cmp_counters, cmp_countables),
      GROUP("UFC", ufc_counters, ufc_countables),
      GROUP("BV_CP", bv_cp_counters, cp_countables),
      GROUP("BV_PC", bv_pc_counters, pc_countables),
      GROUP("BV_VFD", bv_vfd_counters, vfd_countables),
      GROUP("BV_VPC", bv_vpc_counters, vpc_countables),
      GROUP("BV_TP", bv_tp_counters, tp_countables),
      GROUP("BV_SP", bv_sp_counters, sp_countables),
      GROUP("BV_UFC", bv_ufc_counters, ufc_countables),
      GROUP("BV_TSE", bv_tse_counters, tse_countables),
      GROUP("BV_RAS", bv_ras_counters, ras_countables),
      GROUP("BV_LRZ", bv_lrz_counters, lrz_countables),
      GROUP("BV_HLSQ", bv_hlsq_counters, hlsq_countables),
};

const unsigned a7xx_num_perfcntr_groups = ARRAY_SIZE(a7xx_perfcntr_groups);


enum {
   DERIVED_COUNTER_PERFCNTR_CP_ALWAYS_COUNT,
   DERIVED_COUNTER_PERFCNTR_CP_NUM_PREEMPTIONS,
   DERIVED_COUNTER_PERFCNTR_CP_PREEMPTION_REACTION_DELAY,

   DERIVED_COUNTER_PERFCNTR_RBBM_STATUS_MASKED,

   DERIVED_COUNTER_PERFCNTR_PC_STALL_CYCLES_VFD,
   DERIVED_COUNTER_PERFCNTR_PC_VERTEX_HITS,
   DERIVED_COUNTER_PERFCNTR_PC_VS_INVOCATIONS,

   DERIVED_COUNTER_PERFCNTR_TSE_INPUT_PRIM,
   DERIVED_COUNTER_PERFCNTR_TSE_TRIVAL_REJ_PRIM,
   DERIVED_COUNTER_PERFCNTR_TSE_CLIPPED_PRIM,
   DERIVED_COUNTER_PERFCNTR_TSE_OUTPUT_VISIBLE_PRIM,

   DERIVED_COUNTER_PERFCNTR_UCHE_STALL_CYCLES_ARBITER,
   DERIVED_COUNTER_PERFCNTR_UCHE_VBIF_READ_BEATS_TP,
   DERIVED_COUNTER_PERFCNTR_UCHE_VBIF_READ_BEATS_VFD,
   DERIVED_COUNTER_PERFCNTR_UCHE_VBIF_READ_BEATS_SP,
   DERIVED_COUNTER_PERFCNTR_UCHE_READ_REQUESTS_TP,

   DERIVED_COUNTER_PERFCNTR_TP_BUSY_CYCLES,
   DERIVED_COUNTER_PERFCNTR_TP_L1_CACHELINE_REQUESTS,
   DERIVED_COUNTER_PERFCNTR_TP_L1_CACHELINE_MISSES,
   DERIVED_COUNTER_PERFCNTR_TP_OUTPUT_PIXELS,
   DERIVED_COUNTER_PERFCNTR_TP_OUTPUT_PIXELS_POINT,
   DERIVED_COUNTER_PERFCNTR_TP_OUTPUT_PIXELS_BILINEAR,
   DERIVED_COUNTER_PERFCNTR_TP_OUTPUT_PIXELS_ANISO,

   DERIVED_COUNTER_PERFCNTR_SP_BUSY_CYCLES,
   DERIVED_COUNTER_PERFCNTR_SP_ALU_WORKING_CYCLES,
   DERIVED_COUNTER_PERFCNTR_SP_EFU_WORKING_CYCLES,
   DERIVED_COUNTER_PERFCNTR_SP_STALL_CYCLES_TP,
   DERIVED_COUNTER_PERFCNTR_SP_NON_EXECUTION_CYCLES,
   DERIVED_COUNTER_PERFCNTR_SP_VS_STAGE_TEX_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_VS_STAGE_EFU_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_FS_STAGE_EFU_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_ICL1_REQUESTS,
   DERIVED_COUNTER_PERFCNTR_SP_ICL1_MISSES,
   DERIVED_COUNTER_PERFCNTR_SP_ANY_EU_WORKING_FS_STAGE,
   DERIVED_COUNTER_PERFCNTR_SP_ANY_EU_WORKING_VS_STAGE,
   DERIVED_COUNTER_PERFCNTR_SP_ANY_EU_WORKING_CS_STAGE,
   DERIVED_COUNTER_PERFCNTR_SP_PIXELS,
   DERIVED_COUNTER_PERFCNTR_SP_RAY_QUERY_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_RTU_BUSY_CYCLES,
   DERIVED_COUNTER_PERFCNTR_SP_RTU_BVH_FETCH_LATENCY_CYCLES,
   DERIVED_COUNTER_PERFCNTR_SP_RTU_BVH_FETCH_LATENCY_SAMPLES,
   DERIVED_COUNTER_PERFCNTR_SP_RTU_RAY_BOX_INTERSECTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_RTU_RAY_TRIANGLE_INTERSECTIONS,
   DERIVED_COUNTER_PERFCNTR_SP_SCH_STALL_CYCLES_RTU,

   DERIVED_COUNTER_PERFCNTR_CMPDECMP_VBIF_READ_DATA,

   DERIVED_COUNTER_PERFCNTR_BV_PC_STALL_CYCLES_VFD,
   DERIVED_COUNTER_PERFCNTR_BV_PC_VERTEX_HITS,
   DERIVED_COUNTER_PERFCNTR_BV_PC_VS_INVOCATIONS,

   DERIVED_COUNTER_PERFCNTR_BV_TP_L1_CACHELINE_REQUESTS,
   DERIVED_COUNTER_PERFCNTR_BV_TP_L1_CACHELINE_MISSES,
   DERIVED_COUNTER_PERFCNTR_BV_TP_OUTPUT_PIXELS,
   DERIVED_COUNTER_PERFCNTR_BV_TP_OUTPUT_PIXELS_POINT,
   DERIVED_COUNTER_PERFCNTR_BV_TP_OUTPUT_PIXELS_BILINEAR,
   DERIVED_COUNTER_PERFCNTR_BV_TP_OUTPUT_PIXELS_ANISO,

   DERIVED_COUNTER_PERFCNTR_BV_SP_STALL_CYCLES_TP,
   DERIVED_COUNTER_PERFCNTR_BV_SP_VS_STAGE_TEX_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_BV_SP_VS_STAGE_EFU_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_BV_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS,
   DERIVED_COUNTER_PERFCNTR_BV_SP_ICL1_REQUESTS,
   DERIVED_COUNTER_PERFCNTR_BV_SP_ICL1_MISSES,
   DERIVED_COUNTER_PERFCNTR_BV_SP_ANY_EU_WORKING_FS_STAGE,
   DERIVED_COUNTER_PERFCNTR_BV_SP_ANY_EU_WORKING_VS_STAGE,

   DERIVED_COUNTER_PERFCNTR_LRZ_TOTAL_PIXEL,
   DERIVED_COUNTER_PERFCNTR_LRZ_VISIBLE_PIXEL_AFTER_LRZ,
   DERIVED_COUNTER_PERFCNTR_LRZ_PRIM_KILLED_BY_LRZ,
   DERIVED_COUNTER_PERFCNTR_LRZ_TILE_KILLED,

   DERIVED_COUNTER_PERFCNTR_MAX_VALUE,
};

static_assert(DERIVED_COUNTER_PERFCNTR_MAX_VALUE <= FD_DERIVED_COUNTER_COLLECTION_MAX_ENABLED_PERFCNTRS, "");

#define DERIVED_COUNTER_PERFCNTR(_enum, _counter) \
   [DERIVED_COUNTER_PERFCNTR_##_enum] = { .counter = _counter, .countable = A7XX_PERF_##_enum }
#define DERIVED_COUNTER_PERFCNTR_BV(_enum, _counter) \
   [DERIVED_COUNTER_PERFCNTR_BV_##_enum] = { .counter = _counter, .countable = A7XX_PERF_##_enum }

static const struct {
   const struct fd_perfcntr_counter *counter;
   unsigned countable;
} a7xx_derived_counter_perfcntrs[] = {
   /* CP: 3/14 counters */
   DERIVED_COUNTER_PERFCNTR(CP_ALWAYS_COUNT,              &cp_counters[0]),
   DERIVED_COUNTER_PERFCNTR(CP_NUM_PREEMPTIONS,           &cp_counters[1]),
   DERIVED_COUNTER_PERFCNTR(CP_PREEMPTION_REACTION_DELAY, &cp_counters[2]),

   /* RBBM: 1/4 counters */
   DERIVED_COUNTER_PERFCNTR(RBBM_STATUS_MASKED, &rbbm_counters[0]),

   /* PC: 3/8 counters */
   DERIVED_COUNTER_PERFCNTR(PC_STALL_CYCLES_VFD, &pc_counters[0]),
   DERIVED_COUNTER_PERFCNTR(PC_VERTEX_HITS,      &pc_counters[1]),
   DERIVED_COUNTER_PERFCNTR(PC_VS_INVOCATIONS,   &pc_counters[2]),

   /* TSE: 4/4 counters */
   DERIVED_COUNTER_PERFCNTR(TSE_INPUT_PRIM,          &tse_counters[0]),
   DERIVED_COUNTER_PERFCNTR(TSE_TRIVAL_REJ_PRIM,     &tse_counters[1]),
   DERIVED_COUNTER_PERFCNTR(TSE_CLIPPED_PRIM,        &tse_counters[2]),
   DERIVED_COUNTER_PERFCNTR(TSE_OUTPUT_VISIBLE_PRIM, &tse_counters[3]),

   /* UCHE: 5/12 counters */
   DERIVED_COUNTER_PERFCNTR(UCHE_STALL_CYCLES_ARBITER, &uche_counters[0]),
   DERIVED_COUNTER_PERFCNTR(UCHE_VBIF_READ_BEATS_TP,   &uche_counters[1]),
   DERIVED_COUNTER_PERFCNTR(UCHE_VBIF_READ_BEATS_VFD,  &uche_counters[2]),
   DERIVED_COUNTER_PERFCNTR(UCHE_VBIF_READ_BEATS_SP,   &uche_counters[3]),
   DERIVED_COUNTER_PERFCNTR(UCHE_READ_REQUESTS_TP,     &uche_counters[4]),

   /* TP: 7/12 counters */
   DERIVED_COUNTER_PERFCNTR(TP_BUSY_CYCLES,            &tp_counters[0]),
   DERIVED_COUNTER_PERFCNTR(TP_L1_CACHELINE_REQUESTS,  &tp_counters[1]),
   DERIVED_COUNTER_PERFCNTR(TP_L1_CACHELINE_MISSES,    &tp_counters[2]),
   DERIVED_COUNTER_PERFCNTR(TP_OUTPUT_PIXELS,          &tp_counters[3]),
   DERIVED_COUNTER_PERFCNTR(TP_OUTPUT_PIXELS_POINT,    &tp_counters[4]),
   DERIVED_COUNTER_PERFCNTR(TP_OUTPUT_PIXELS_BILINEAR, &tp_counters[5]),
   DERIVED_COUNTER_PERFCNTR(TP_OUTPUT_PIXELS_ANISO,    &tp_counters[6]),

   /* SP: 24/24 counters */
   DERIVED_COUNTER_PERFCNTR(SP_BUSY_CYCLES,                    &sp_counters[ 0]),
   DERIVED_COUNTER_PERFCNTR(SP_ALU_WORKING_CYCLES,             &sp_counters[ 1]),
   DERIVED_COUNTER_PERFCNTR(SP_EFU_WORKING_CYCLES,             &sp_counters[ 2]),
   DERIVED_COUNTER_PERFCNTR(SP_STALL_CYCLES_TP,                &sp_counters[ 3]),
   DERIVED_COUNTER_PERFCNTR(SP_NON_EXECUTION_CYCLES,           &sp_counters[ 4]),
   DERIVED_COUNTER_PERFCNTR(SP_VS_STAGE_TEX_INSTRUCTIONS,      &sp_counters[ 5]),
   DERIVED_COUNTER_PERFCNTR(SP_VS_STAGE_EFU_INSTRUCTIONS,      &sp_counters[ 6]),
   DERIVED_COUNTER_PERFCNTR(SP_VS_STAGE_FULL_ALU_INSTRUCTIONS, &sp_counters[ 7]),
   DERIVED_COUNTER_PERFCNTR(SP_FS_STAGE_EFU_INSTRUCTIONS,      &sp_counters[ 8]),
   DERIVED_COUNTER_PERFCNTR(SP_FS_STAGE_FULL_ALU_INSTRUCTIONS, &sp_counters[ 9]),
   DERIVED_COUNTER_PERFCNTR(SP_FS_STAGE_HALF_ALU_INSTRUCTIONS, &sp_counters[10]),
   DERIVED_COUNTER_PERFCNTR(SP_ICL1_REQUESTS,                  &sp_counters[11]),
   DERIVED_COUNTER_PERFCNTR(SP_ICL1_MISSES,                    &sp_counters[12]),
   DERIVED_COUNTER_PERFCNTR(SP_ANY_EU_WORKING_FS_STAGE,        &sp_counters[13]),
   DERIVED_COUNTER_PERFCNTR(SP_ANY_EU_WORKING_VS_STAGE,        &sp_counters[14]),
   DERIVED_COUNTER_PERFCNTR(SP_ANY_EU_WORKING_CS_STAGE,        &sp_counters[15]),
   DERIVED_COUNTER_PERFCNTR(SP_PIXELS,                         &sp_counters[16]),
   DERIVED_COUNTER_PERFCNTR(SP_RAY_QUERY_INSTRUCTIONS,         &sp_counters[17]),
   DERIVED_COUNTER_PERFCNTR(SP_RTU_BUSY_CYCLES,                &sp_counters[18]),
   DERIVED_COUNTER_PERFCNTR(SP_RTU_BVH_FETCH_LATENCY_CYCLES,   &sp_counters[19]),
   DERIVED_COUNTER_PERFCNTR(SP_RTU_BVH_FETCH_LATENCY_SAMPLES,  &sp_counters[20]),
   DERIVED_COUNTER_PERFCNTR(SP_RTU_RAY_BOX_INTERSECTIONS,      &sp_counters[21]),
   DERIVED_COUNTER_PERFCNTR(SP_RTU_RAY_TRIANGLE_INTERSECTIONS, &sp_counters[22]),
   DERIVED_COUNTER_PERFCNTR(SP_SCH_STALL_CYCLES_RTU,           &sp_counters[23]),

   /* CMP: 1/4 counters */
   DERIVED_COUNTER_PERFCNTR(CMPDECMP_VBIF_READ_DATA, &cmp_counters[0]),

   /* BV_PC: 3/8 counters */
   DERIVED_COUNTER_PERFCNTR_BV(PC_STALL_CYCLES_VFD, &bv_pc_counters[0]),
   DERIVED_COUNTER_PERFCNTR_BV(PC_VERTEX_HITS,      &bv_pc_counters[1]),
   DERIVED_COUNTER_PERFCNTR_BV(PC_VS_INVOCATIONS,   &bv_pc_counters[2]),

   /* BV_TP: 6/6 counters */
   DERIVED_COUNTER_PERFCNTR_BV(TP_L1_CACHELINE_REQUESTS,  &bv_tp_counters[0]),
   DERIVED_COUNTER_PERFCNTR_BV(TP_L1_CACHELINE_MISSES,    &bv_tp_counters[1]),
   DERIVED_COUNTER_PERFCNTR_BV(TP_OUTPUT_PIXELS,          &bv_tp_counters[2]),
   DERIVED_COUNTER_PERFCNTR_BV(TP_OUTPUT_PIXELS_POINT,    &bv_tp_counters[3]),
   DERIVED_COUNTER_PERFCNTR_BV(TP_OUTPUT_PIXELS_BILINEAR, &bv_tp_counters[4]),
   DERIVED_COUNTER_PERFCNTR_BV(TP_OUTPUT_PIXELS_ANISO,    &bv_tp_counters[5]),

   /* GP: 8/12 counters */
   DERIVED_COUNTER_PERFCNTR_BV(SP_STALL_CYCLES_TP,                &bv_sp_counters[0]),
   DERIVED_COUNTER_PERFCNTR_BV(SP_VS_STAGE_TEX_INSTRUCTIONS,      &bv_sp_counters[1]),
   DERIVED_COUNTER_PERFCNTR_BV(SP_VS_STAGE_EFU_INSTRUCTIONS,      &bv_sp_counters[2]),
   DERIVED_COUNTER_PERFCNTR_BV(SP_VS_STAGE_FULL_ALU_INSTRUCTIONS, &bv_sp_counters[3]),
   DERIVED_COUNTER_PERFCNTR_BV(SP_ICL1_REQUESTS,                  &bv_sp_counters[4]),
   DERIVED_COUNTER_PERFCNTR_BV(SP_ICL1_MISSES,                    &bv_sp_counters[5]),
   DERIVED_COUNTER_PERFCNTR_BV(SP_ANY_EU_WORKING_FS_STAGE,        &bv_sp_counters[6]),
   DERIVED_COUNTER_PERFCNTR_BV(SP_ANY_EU_WORKING_VS_STAGE,        &bv_sp_counters[7]),

   /* LRZ: 4/4 counters */
   DERIVED_COUNTER_PERFCNTR(LRZ_TOTAL_PIXEL, &lrz_counters[0]),
   DERIVED_COUNTER_PERFCNTR(LRZ_VISIBLE_PIXEL_AFTER_LRZ, &lrz_counters[1]),
   DERIVED_COUNTER_PERFCNTR(LRZ_TILE_KILLED, &lrz_counters[2]),
   DERIVED_COUNTER_PERFCNTR(LRZ_PRIM_KILLED_BY_LRZ, &lrz_counters[3]),
};

static uint64_t
safe_div(uint64_t a, uint64_t b)
{
   double value = 0.0;
   if (b)
      value = a / (double) b;

   union {
      double d;
      uint64_t u;
   } v;
   v.d = value;
   return v.u;
}

static uint64_t
percent(uint64_t a, uint64_t b)
{
   float value = 0;
   if (b)
      value = (a / (float) b) * 100.0f;

   union {
      float f;
      uint32_t u;
   } v;
   v.f = value;
   return (uint64_t )v.u & 0xffffffff;
}

#define DERIVED_COUNTER_CATEGORY_GPU_GENERAL "GPU General"
#define DERIVED_COUNTER_CATEGORY_GPU_MEMORY_STATS "GPU Memory Stats"
#define DERIVED_COUNTER_CATEGORY_GPU_PREEMPTION "GPU Preemption"
#define DERIVED_COUNTER_CATEGORY_GPU_PRIMITIVE_PROCESSING "GPU Primitive Processing"
#define DERIVED_COUNTER_CATEGORY_GPU_SHADER_PROCESSING "GPU Shader Processing"
#define DERIVED_COUNTER_CATEGORY_GPU_STALLS "GPU Stalls"
#define DERIVED_COUNTER_CATEGORY_GPU_LRZ "GPU LRZ"

#define DERIVED_COUNTER_PERFCNTRS_COUNT_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, N, ...) N
#define DERIVED_COUNTER_PERFCNTRS_COUNT(...) DERIVED_COUNTER_PERFCNTRS_COUNT_IMPL(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define DERIVED_COUNTER_PERFCNTRS(...) __VA_ARGS__

#define PERFCNTR_VALUE_0(OP, _0, ...) OP(0, _0)
#define PERFCNTR_VALUE_1(OP, _0, _1, ...) PERFCNTR_VALUE_0(OP, _0) OP(1, _1)
#define PERFCNTR_VALUE_2(OP, _0, _1, _2, ...) PERFCNTR_VALUE_1(OP, _0, _1) OP(2, _2)
#define PERFCNTR_VALUE_3(OP, _0, _1, _2, _3, ...) PERFCNTR_VALUE_2(OP, _0, _1, _2) OP(3, _3)
#define PERFCNTR_VALUE_4(OP, _0, _1, _2, _3, _4, ...) PERFCNTR_VALUE_3(OP, _0, _1, _2, _3) OP(4, _4)
#define PERFCNTR_HANDLE_VALUES(OP, _0, _1, _2, _3, _4, N, ...) PERFCNTR_VALUE_##N(OP, _0, _1, _2, _3, _4)
#define PERFCNTR_OP_LIST(_index, _name) DERIVED_COUNTER_PERFCNTR_##_name,
#define PERFCNTR_OP_DECLARE(_index, _name) uint64_t _name = values[_index];

#define DERIVED_COUNTER_PERFCNTR_LIST_VALUES(...) PERFCNTR_HANDLE_VALUES(PERFCNTR_OP_LIST, __VA_ARGS__, 4, 3, 2, 1, 0)
#define DERIVED_COUNTER_PERFCNTR_DECLARE_VALUES(...) PERFCNTR_HANDLE_VALUES(PERFCNTR_OP_DECLARE, __VA_ARGS__, 4, 3, 2, 1, 0)

#define DERIVED_COUNTER(_impl_name, _name, _description, _category, _type, _perfcntrs, _derivation) \
   static uint64_t a7xx_derived_counter_##_impl_name##_derive(struct fd_derivation_context *context, uint64_t *values) {\
      DERIVED_COUNTER_PERFCNTR_DECLARE_VALUES(_perfcntrs) \
      _derivation \
   } \
   const struct fd_derived_counter a7xx_derived_counter_##_impl_name = { \
      .name = _name, .description = _description, \
      .category = DERIVED_COUNTER_CATEGORY_##_category, \
      .type = FD_PERFCNTR_TYPE_##_type, \
      .num_perfcntrs = DERIVED_COUNTER_PERFCNTRS_COUNT(_perfcntrs), \
      .perfcntrs = { DERIVED_COUNTER_PERFCNTR_LIST_VALUES(_perfcntrs) }, \
      .derive = a7xx_derived_counter_##_impl_name##_derive, \
   }
#define DERIVED_COUNTER_PTR(_impl_name) &a7xx_derived_counter_##_impl_name

DERIVED_COUNTER(clocks, "Clocks", "Number of GPU clocks", GPU_GENERAL, UINT64,
   DERIVED_COUNTER_PERFCNTRS(CP_ALWAYS_COUNT),
   {
      return CP_ALWAYS_COUNT;
   });

DERIVED_COUNTER(avg_bytes_per_fragment,
   "Avg Bytes / Fragment",
   "Average number of bytes transferred from main memory for each fragment",
   GPU_MEMORY_STATS, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(UCHE_VBIF_READ_BEATS_TP,
                             SP_PIXELS),
   {
      return safe_div(UCHE_VBIF_READ_BEATS_TP * 32, SP_PIXELS);
   });

DERIVED_COUNTER(avg_bytes_per_vertex,
   "Avg Bytes / Vertex",
   "Average number of bytes transferred from main memory for each vertex",
   GPU_MEMORY_STATS, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(UCHE_VBIF_READ_BEATS_VFD,
                             PC_VS_INVOCATIONS,
                             BV_PC_VS_INVOCATIONS),
   {
      return safe_div(UCHE_VBIF_READ_BEATS_VFD * 32,
                      PC_VS_INVOCATIONS + BV_PC_VS_INVOCATIONS);
   });

DERIVED_COUNTER(sp_memory_read,
   "SP Memory Read (Bytes)",
   "Bytes of data read from memory by the Shader Processors",
   GPU_MEMORY_STATS, UINT64,
   DERIVED_COUNTER_PERFCNTRS(UCHE_VBIF_READ_BEATS_SP),
   {
      return UCHE_VBIF_READ_BEATS_SP * 32;
   });

DERIVED_COUNTER(texture_memory_read,
   "Texture Memory Read BW (Bytes)",
   "Bytes of texture data read from memory",
   GPU_MEMORY_STATS, UINT64,
   DERIVED_COUNTER_PERFCNTRS(UCHE_VBIF_READ_BEATS_TP,
                             CMPDECMP_VBIF_READ_DATA),
   {
      return (UCHE_VBIF_READ_BEATS_TP + CMPDECMP_VBIF_READ_DATA) * 32;
   });

DERIVED_COUNTER(vertex_memory_read,
   "Vertex Memory Read (Bytes)",
   "Bytes of vertex data read from memory",
   GPU_MEMORY_STATS, UINT64,
   DERIVED_COUNTER_PERFCNTRS(UCHE_VBIF_READ_BEATS_VFD),
   {
      return UCHE_VBIF_READ_BEATS_VFD * 32;
   });

/* FIXME: disabled due to lack of support for VBIF perfcounters which
          have a more complex way of being enabled.
DERIVED_COUNTER(read_total,
   "Read Total (Bytes)",
   "Total number of bytes read by the GPU from memory",
   GPU_MEMORY_STATS, UINT64,
   DERIVED_COUNTER_PERFCNTRS(...),
   {
      return 0;
   });

DERIVED_COUNTER(write_total,
   "Write Total (Bytes)",
   "Total number of bytes written by the GPU to memory",
   GPU_MEMORY_STATS, UINT64,
   DERIVED_COUNTER_PERFCNTRS(...),
   {
      return 0;
   });
*/

DERIVED_COUNTER(avg_preemption_delay,
   "Avg Preemption Delay",
   "Average number of cycles from the preemption request to preemption start",
   GPU_PREEMPTION, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(CP_PREEMPTION_REACTION_DELAY,
                             CP_NUM_PREEMPTIONS,
                             CP_ALWAYS_COUNT),
   {
      if (!CP_ALWAYS_COUNT || !CP_NUM_PREEMPTIONS)
         return 0;

      union {
         double d;
         uint64_t u;
      } v;

      double delay = CP_PREEMPTION_REACTION_DELAY / (double) CP_ALWAYS_COUNT;
      v.d = delay / (CP_NUM_PREEMPTIONS / 2);
      return v.u;
   });

DERIVED_COUNTER(preemptions,
   "Preemptions",
   "The number of GPU preemptions that occurred",
   GPU_PREEMPTION, UINT64,
   DERIVED_COUNTER_PERFCNTRS(CP_NUM_PREEMPTIONS),
   {
      return CP_NUM_PREEMPTIONS / 2;
   });

DERIVED_COUNTER(average_polygon_area,
   "Average Polygon Area",
   "Average number of pixels per polygon",
   GPU_PRIMITIVE_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(TSE_OUTPUT_VISIBLE_PRIM,
                             SP_PIXELS),
   {
      return safe_div(SP_PIXELS, TSE_OUTPUT_VISIBLE_PRIM);
   });

DERIVED_COUNTER(average_vertices_per_polygon,
   "Average Vertices / Polygon",
   "Average number of vertices per polygon",
   GPU_PRIMITIVE_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(PC_VS_INVOCATIONS,
                             BV_PC_VS_INVOCATIONS,
                             TSE_INPUT_PRIM),
   {
      return safe_div(PC_VS_INVOCATIONS + BV_PC_VS_INVOCATIONS, TSE_INPUT_PRIM);
   });

DERIVED_COUNTER(preclipped_polygon,
   "Pre-clipped Polygon",
   "Number of polygons submitted to the GPU before any hardware clipping",
   GPU_PRIMITIVE_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(TSE_INPUT_PRIM),
   {
      return TSE_INPUT_PRIM;
   });

DERIVED_COUNTER(percent_prims_clipped,
   "% Prims Clipped",
   "Percentage of primitives clipped by the GPU (where new primitives are generated)",
   GPU_PRIMITIVE_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(TSE_CLIPPED_PRIM,
                             TSE_INPUT_PRIM),
   {
      return percent(TSE_CLIPPED_PRIM, TSE_INPUT_PRIM);
   });

DERIVED_COUNTER(percent_prims_trivially_rejected,
   "% Prims Trivially Rejected",
   "Percentage of primitives that are trivially rejected",
   GPU_PRIMITIVE_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(TSE_TRIVAL_REJ_PRIM,
                             TSE_INPUT_PRIM),
   {
      return percent(TSE_TRIVAL_REJ_PRIM, TSE_INPUT_PRIM);
   });

DERIVED_COUNTER(reused_vertices,
   "Reused Vertices",
   "Number of vertices used from the post-transform vertex buffer cache",
   GPU_PRIMITIVE_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(PC_VERTEX_HITS,
                             BV_PC_VERTEX_HITS),
   {
      return PC_VERTEX_HITS + BV_PC_VERTEX_HITS;
   });

DERIVED_COUNTER(alu_per_fragment,
   "ALU / Fragment",
   "Average number of scalar fragment shader ALU instructions issued per shaded fragment, expressed as full precision ALUs (2 mediump = 1 fullp)",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(SP_FS_STAGE_FULL_ALU_INSTRUCTIONS,
                             SP_FS_STAGE_HALF_ALU_INSTRUCTIONS,
                             SP_PIXELS),
   {
      return safe_div(SP_FS_STAGE_FULL_ALU_INSTRUCTIONS + SP_FS_STAGE_HALF_ALU_INSTRUCTIONS / 2,
                      SP_PIXELS);
   });

DERIVED_COUNTER(alu_per_vertex,
   "ALU / Vertex",
   "Average number of vertex scalar shader ALU instructions issued per shaded vertex",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(PC_VS_INVOCATIONS,
                             BV_PC_VS_INVOCATIONS,
                             SP_VS_STAGE_FULL_ALU_INSTRUCTIONS,
                             BV_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS),
   {
      return safe_div(SP_VS_STAGE_FULL_ALU_INSTRUCTIONS + BV_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS,
                      PC_VS_INVOCATIONS + BV_PC_VS_INVOCATIONS);
   });

DERIVED_COUNTER(percent_anisotropic_filtered,
   "% Anisotropic Filtered",
   "Percent of texels filtered using the 'Anisotropic' sampling method",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(TP_OUTPUT_PIXELS,
                             BV_TP_OUTPUT_PIXELS,
                             TP_OUTPUT_PIXELS_ANISO,
                             BV_TP_OUTPUT_PIXELS_ANISO),
   {
      return percent(TP_OUTPUT_PIXELS_ANISO + BV_TP_OUTPUT_PIXELS_ANISO,
                     TP_OUTPUT_PIXELS + BV_TP_OUTPUT_PIXELS);
   });

DERIVED_COUNTER(average_bvh_fetch_latency_cycles,
   "Average BVH Fetch Latency Cycles",
   "The Average BVH Fetch Latency cycles is the latency counted from start of BVH query request till getting BVH Query result back",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(SP_RTU_BVH_FETCH_LATENCY_CYCLES,
                             SP_RTU_BVH_FETCH_LATENCY_SAMPLES),
   {
      return safe_div(SP_RTU_BVH_FETCH_LATENCY_CYCLES, SP_RTU_BVH_FETCH_LATENCY_SAMPLES);
   });

DERIVED_COUNTER(efu_per_fragment,
   "EFU / Fragment",
   "Average number of scalar fragment shader EFU instructions issued per shaded fragment",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(SP_FS_STAGE_EFU_INSTRUCTIONS,
                             SP_PIXELS),
   {
      return safe_div(SP_FS_STAGE_EFU_INSTRUCTIONS, SP_PIXELS);
   });

DERIVED_COUNTER(efu_per_vertex,
   "EFU / Vertex",
   "Average number of scalar vertex shader EFU instructions issued per shaded vertex",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(PC_VS_INVOCATIONS,
                             BV_PC_VS_INVOCATIONS,
                             SP_VS_STAGE_EFU_INSTRUCTIONS,
                             BV_SP_VS_STAGE_EFU_INSTRUCTIONS),
   {
      return safe_div(SP_VS_STAGE_EFU_INSTRUCTIONS + BV_SP_VS_STAGE_EFU_INSTRUCTIONS,
                      PC_VS_INVOCATIONS + BV_PC_VS_INVOCATIONS);
   });

DERIVED_COUNTER(fragment_alu_instructions_full,
   "Fragment ALU Instructions (Full)",
   "Total number of full precision fragment shader instructions issued",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(SP_FS_STAGE_FULL_ALU_INSTRUCTIONS),
   {
      return SP_FS_STAGE_FULL_ALU_INSTRUCTIONS * 4;
   });

DERIVED_COUNTER(fragment_alu_instructions_half,
   "Fragment ALU Instructions (Half)",
   "Total number of half precision Scalar fragment shader instructions issued",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(SP_FS_STAGE_HALF_ALU_INSTRUCTIONS),
   {
      return SP_FS_STAGE_HALF_ALU_INSTRUCTIONS * 4;
   });

DERIVED_COUNTER(fragment_efu_instructions,
   "Fragment EFU Instructions",
   "Total number of Scalar fragment shader Elementary Function Unit (EFU) instructions issued",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(SP_FS_STAGE_EFU_INSTRUCTIONS),
   {
      return SP_FS_STAGE_EFU_INSTRUCTIONS * 4;
   });

DERIVED_COUNTER(fragment_instructions,
   "Fragment Instructions",
   "Total number of fragment shader instructions issued",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(SP_FS_STAGE_EFU_INSTRUCTIONS,
                             SP_FS_STAGE_FULL_ALU_INSTRUCTIONS,
                             SP_FS_STAGE_HALF_ALU_INSTRUCTIONS),
   {
      return (SP_FS_STAGE_EFU_INSTRUCTIONS + SP_FS_STAGE_FULL_ALU_INSTRUCTIONS +
              SP_FS_STAGE_HALF_ALU_INSTRUCTIONS / 2) * 4;
   });

DERIVED_COUNTER(fragments_shaded,
   "Fragments Shaded",
   "Number of fragments submitted to the shader engine",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(SP_PIXELS),
   {
      return SP_PIXELS;
   });

DERIVED_COUNTER(percent_linear_filtered,
   "% Linear Filtered",
   "Percent of texels filtered using the 'Linear' sampling method",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(TP_OUTPUT_PIXELS,
                             BV_TP_OUTPUT_PIXELS,
                             TP_OUTPUT_PIXELS_BILINEAR,
                             BV_TP_OUTPUT_PIXELS_BILINEAR),
   {
      return percent(TP_OUTPUT_PIXELS_BILINEAR + BV_TP_OUTPUT_PIXELS_BILINEAR,
                     TP_OUTPUT_PIXELS + BV_TP_OUTPUT_PIXELS);
   });

DERIVED_COUNTER(percent_nearest_filtered,
   "% Nearest Filtered",
   "Percent of texels filtered using the 'Nearest' sampling method",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(TP_OUTPUT_PIXELS,
                             BV_TP_OUTPUT_PIXELS,
                             TP_OUTPUT_PIXELS_POINT,
                             BV_TP_OUTPUT_PIXELS_POINT),
   {
      return percent(TP_OUTPUT_PIXELS_POINT + BV_TP_OUTPUT_PIXELS_POINT,
                     TP_OUTPUT_PIXELS + BV_TP_OUTPUT_PIXELS);
   });

DERIVED_COUNTER(percent_rtu_busy,
   "% RTU Busy",
   "Percentage of time that Ray Tracing Unit in SP is busy compared to whole SP",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_RTU_BUSY_CYCLES,
                             SP_BUSY_CYCLES),
   {
      return percent(SP_RTU_BUSY_CYCLES, SP_BUSY_CYCLES);
   });

DERIVED_COUNTER(rtu_ray_box_intersections_per_instruction,
   "RTU Ray Box Intersections Per Instruction",
   "Number of Ray Box intersections per instruction",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(SP_RTU_RAY_BOX_INTERSECTIONS,
                             SP_RAY_QUERY_INSTRUCTIONS),
   {
      return safe_div(SP_RTU_RAY_BOX_INTERSECTIONS, SP_RAY_QUERY_INSTRUCTIONS);
   });

DERIVED_COUNTER(rtu_ray_triangle_intersections_per_instruction,
   "RTU Ray Triangle Intersections Per Instruction",
   "Number of Ray Triangle intersections per instruction",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(SP_RTU_RAY_TRIANGLE_INTERSECTIONS,
                             SP_RAY_QUERY_INSTRUCTIONS),
   {
      return safe_div(SP_RTU_RAY_TRIANGLE_INTERSECTIONS, SP_RAY_QUERY_INSTRUCTIONS);
   });


/* FIXME: disabled due to lack of TP counter capacity
DERIVED_COUNTER(percent_non_base_level_textures,
   "% Non-Base Level Textures",
   "Percent of texels coming from a non-base MIP level",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(...),
   {
      return 0;
   });
*/

DERIVED_COUNTER(percent_shader_alu_capacity_utilized,
   "% Shader ALU Capacity Utilized",
   "Percent of maximum shader capacity (ALU operations) utilized",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_BUSY_CYCLES,
                             SP_VS_STAGE_FULL_ALU_INSTRUCTIONS,
                             BV_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS,
                             SP_FS_STAGE_FULL_ALU_INSTRUCTIONS,
                             SP_FS_STAGE_HALF_ALU_INSTRUCTIONS),
   {
      return percent(SP_VS_STAGE_FULL_ALU_INSTRUCTIONS + BV_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS +
                     SP_FS_STAGE_FULL_ALU_INSTRUCTIONS + SP_FS_STAGE_HALF_ALU_INSTRUCTIONS / 2,
                     SP_BUSY_CYCLES * context->a7xx.number_of_alus_per_usptp);
   });

DERIVED_COUNTER(percent_shaders_busy,
   "% Shaders Busy",
   "Percentage of time that all Shader cores are busy",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_BUSY_CYCLES,
                             TP_BUSY_CYCLES,
                             RBBM_STATUS_MASKED),
   {
      uint64_t numerator = SP_BUSY_CYCLES;
      if (!numerator)
         numerator = TP_BUSY_CYCLES;
      return percent(numerator, context->a7xx.number_of_usptp * RBBM_STATUS_MASKED);
   });

DERIVED_COUNTER(percent_shaders_stalled,
   "% Shaders Stalled",
   "Percentage of time that all shader cores are idle with at least one active wave",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_NON_EXECUTION_CYCLES,
                             RBBM_STATUS_MASKED),
   {
      return percent(SP_NON_EXECUTION_CYCLES, context->a7xx.number_of_usptp * RBBM_STATUS_MASKED);
   });

DERIVED_COUNTER(percent_texture_pipes_busy,
   "% Texture Pipes Busy",
   "Percentage of time that any texture pipe is busy",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(TP_BUSY_CYCLES,
                             RBBM_STATUS_MASKED),
   {
      return percent(TP_BUSY_CYCLES, context->a7xx.number_of_usptp * RBBM_STATUS_MASKED);
   });

DERIVED_COUNTER(textures_per_fragment,
   "Textures / Fragment",
   "Average number of textures referenced per fragment",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(SP_VS_STAGE_TEX_INSTRUCTIONS,
                             TP_OUTPUT_PIXELS,
                             SP_PIXELS),
   {
      /* FIXME: SP_VS_STAGE_TEX_INSTRUCTIONS seems to be unused. */
      (void)SP_VS_STAGE_TEX_INSTRUCTIONS;

      return safe_div(TP_OUTPUT_PIXELS, SP_PIXELS);
   });

DERIVED_COUNTER(textures_per_vertex,
   "Textures / Vertex",
   "Average number of textures referenced per vertex",
   GPU_SHADER_PROCESSING, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(PC_VS_INVOCATIONS,
                             BV_PC_VS_INVOCATIONS,
                             SP_VS_STAGE_TEX_INSTRUCTIONS,
                             BV_SP_VS_STAGE_TEX_INSTRUCTIONS),
   {
      return safe_div(4 * (SP_VS_STAGE_TEX_INSTRUCTIONS + BV_SP_VS_STAGE_TEX_INSTRUCTIONS),
                      PC_VS_INVOCATIONS + BV_PC_VS_INVOCATIONS);
   });

DERIVED_COUNTER(percent_time_alus_working,
   "% Time ALUs Working",
   "Percentage of time the ALUs are working while the Shaders are busy",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_BUSY_CYCLES,
                             SP_ALU_WORKING_CYCLES),
   {
      return percent(SP_ALU_WORKING_CYCLES / 2, SP_BUSY_CYCLES);
   });

DERIVED_COUNTER(percent_time_compute,
   "% Time Compute",
   "Percentage of time spent in compute work compared to the total time spent shading everything",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_ANY_EU_WORKING_FS_STAGE,
                             SP_ANY_EU_WORKING_VS_STAGE,
                             BV_SP_ANY_EU_WORKING_VS_STAGE,
                             SP_ANY_EU_WORKING_CS_STAGE),
   {
      uint64_t total = SP_ANY_EU_WORKING_VS_STAGE + BV_SP_ANY_EU_WORKING_VS_STAGE +
                       SP_ANY_EU_WORKING_FS_STAGE;
      return percent(SP_ANY_EU_WORKING_CS_STAGE, total);
   });

DERIVED_COUNTER(percent_time_efus_working,
   "% Time EFUs Working",
   "Percentage of time the EFUs are working while the Shaders are busy",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_BUSY_CYCLES,
                             SP_EFU_WORKING_CYCLES),
   {
      return percent(SP_EFU_WORKING_CYCLES, SP_BUSY_CYCLES);
   });

DERIVED_COUNTER(percent_time_shading_fragments,
   "% Time Shading Fragments",
   "Percentage of time spent shading fragments compared to the total time spent shading everything",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_ANY_EU_WORKING_FS_STAGE,
                             SP_ANY_EU_WORKING_VS_STAGE,
                             BV_SP_ANY_EU_WORKING_VS_STAGE,
                             SP_ANY_EU_WORKING_CS_STAGE),
   {
      uint64_t total = SP_ANY_EU_WORKING_VS_STAGE + BV_SP_ANY_EU_WORKING_VS_STAGE +
                       SP_ANY_EU_WORKING_FS_STAGE;
      return percent(SP_ANY_EU_WORKING_FS_STAGE - SP_ANY_EU_WORKING_CS_STAGE, total);
   });

DERIVED_COUNTER(percent_time_shading_vertices,
   "% Time Shading Vertices",
   "Percentage of time spent shading vertices compared to the total time spent shading everything",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_ANY_EU_WORKING_FS_STAGE,
                             BV_SP_ANY_EU_WORKING_FS_STAGE,
                             SP_ANY_EU_WORKING_VS_STAGE,
                             BV_SP_ANY_EU_WORKING_VS_STAGE),
   {
      uint64_t total = SP_ANY_EU_WORKING_FS_STAGE + BV_SP_ANY_EU_WORKING_FS_STAGE +
                       SP_ANY_EU_WORKING_VS_STAGE + BV_SP_ANY_EU_WORKING_VS_STAGE;
      return percent(SP_ANY_EU_WORKING_VS_STAGE + BV_SP_ANY_EU_WORKING_VS_STAGE, total);
   });

DERIVED_COUNTER(vertex_instructions,
   "Vertex Instructions",
   "Total number of scalar vertex shader instructions issued",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(SP_VS_STAGE_EFU_INSTRUCTIONS,
                             SP_VS_STAGE_FULL_ALU_INSTRUCTIONS,
                             BV_SP_VS_STAGE_EFU_INSTRUCTIONS,
                             BV_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS),
   {
      return (SP_VS_STAGE_EFU_INSTRUCTIONS + BV_SP_VS_STAGE_EFU_INSTRUCTIONS +
              SP_VS_STAGE_FULL_ALU_INSTRUCTIONS + BV_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS) * 4;
   });

DERIVED_COUNTER(vertices_shaded,
   "Vertices Shaded",
   "Number of vertices submitted to the shader engine",
   GPU_SHADER_PROCESSING, UINT64,
   DERIVED_COUNTER_PERFCNTRS(PC_VS_INVOCATIONS,
                             BV_PC_VS_INVOCATIONS),
   {
      return PC_VS_INVOCATIONS + BV_PC_VS_INVOCATIONS;
   });

/* FIXME: disabled due to lack of SP counter capacity
DERIVED_COUNTER(percent_wave_context_occupancy,
   "% Wave Context Occupancy",
   "Average percentage of wave context occupancy per cycle",
   GPU_SHADER_PROCESSING, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(...),
   {
   });
*/

DERIVED_COUNTER(percent_bvh_fetch_stall,
   "% BVH Fetch Stall",
   "Percentage of clock cycles where the RTU could not make any more requests for BVH fetch from scheduler",
   GPU_STALLS, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_SCH_STALL_CYCLES_RTU,
                             RBBM_STATUS_MASKED),
   {
      return percent(SP_SCH_STALL_CYCLES_RTU, RBBM_STATUS_MASKED);
   });

DERIVED_COUNTER(percent_instruction_cache_miss,
   "% Instruction Cache Miss",
   "Number of L1 instruction cache misses divided by L1 instruction cache requests",
   GPU_STALLS, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_ICL1_REQUESTS,
                             SP_ICL1_MISSES,
                             BV_SP_ICL1_REQUESTS,
                             BV_SP_ICL1_MISSES),
   {
      return percent(SP_ICL1_MISSES + BV_SP_ICL1_MISSES,
                     SP_ICL1_REQUESTS + BV_SP_ICL1_REQUESTS);
   });

DERIVED_COUNTER(l1_texture_cache_miss_per_pixel,
   "L1 Texture Cache Miss Per Pixel",
   "Average number of Texture L1 cache misses per pixel",
   GPU_STALLS, DOUBLE,
   DERIVED_COUNTER_PERFCNTRS(TP_L1_CACHELINE_MISSES,
                             BV_TP_L1_CACHELINE_MISSES,
                             SP_PIXELS),
   {
      return safe_div(TP_L1_CACHELINE_MISSES + BV_TP_L1_CACHELINE_MISSES, SP_PIXELS);
   });

DERIVED_COUNTER(percent_stalled_on_system_memory,
   "% Stalled on System Memory",
   "Percentage of cycles the L2 cache is stalled waiting for data from system memory",
   GPU_STALLS, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(UCHE_STALL_CYCLES_ARBITER,
                             RBBM_STATUS_MASKED),
   {
      return percent(UCHE_STALL_CYCLES_ARBITER, 4 * RBBM_STATUS_MASKED);
   });

DERIVED_COUNTER(percent_texture_fetch_stall,
   "% Texture Fetch Stall",
   "Percentage of clock cycles where the shader processors cannot make any more requests for texture data",
   GPU_STALLS, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(SP_STALL_CYCLES_TP,
                             BV_SP_STALL_CYCLES_TP,
                             RBBM_STATUS_MASKED),
   {
      return percent(SP_STALL_CYCLES_TP + BV_SP_STALL_CYCLES_TP,
                     context->a7xx.number_of_usptp * RBBM_STATUS_MASKED);
   });

DERIVED_COUNTER(percent_texture_l1_miss,
   "% Texture L1 Miss",
   "Number of L1 texture cache misses divided by L1 texture cache requests",
   GPU_STALLS, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(TP_L1_CACHELINE_REQUESTS,
                             TP_L1_CACHELINE_MISSES,
                             BV_TP_L1_CACHELINE_REQUESTS,
                             BV_TP_L1_CACHELINE_MISSES),
   {
      return percent(TP_L1_CACHELINE_MISSES + BV_TP_L1_CACHELINE_MISSES,
                     TP_L1_CACHELINE_REQUESTS + BV_TP_L1_CACHELINE_REQUESTS);
   });

DERIVED_COUNTER(percent_texture_l2_miss,
   "% Texture L2 Miss",
   "Number of L2 texture cache misses divided by L2 texture cache requests",
   GPU_STALLS, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(UCHE_VBIF_READ_BEATS_TP,
                             UCHE_READ_REQUESTS_TP),
   {
      return percent(2 * UCHE_VBIF_READ_BEATS_TP, UCHE_READ_REQUESTS_TP);
   });

DERIVED_COUNTER(percent_vertex_fetch_stall,
   "% Vertex Fetch Stall",
   "Percentage of clock cycles where the GPU cannot make any more requests for vertex data",
   GPU_STALLS, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(PC_STALL_CYCLES_VFD,
                             BV_PC_STALL_CYCLES_VFD,
                             RBBM_STATUS_MASKED),
   {
      return percent(PC_STALL_CYCLES_VFD + BV_PC_STALL_CYCLES_VFD,
                     RBBM_STATUS_MASKED);
   });

DERIVED_COUNTER(percent_lrz_pixel_killed,
   "% LRZ Pixel Killed",
   "Percentage of pixels killed by LRZ",
   GPU_LRZ, PERCENTAGE,
   DERIVED_COUNTER_PERFCNTRS(LRZ_TOTAL_PIXEL,
                             LRZ_VISIBLE_PIXEL_AFTER_LRZ),
   {
      return percent(LRZ_TOTAL_PIXEL - LRZ_VISIBLE_PIXEL_AFTER_LRZ, LRZ_TOTAL_PIXEL);
   });

DERIVED_COUNTER(lrz_primitives_killed,
   "LRZ Primitives Killed",
   "",
   GPU_LRZ, UINT64,
   DERIVED_COUNTER_PERFCNTRS(LRZ_PRIM_KILLED_BY_LRZ),
   {
      return LRZ_PRIM_KILLED_BY_LRZ;
   });

DERIVED_COUNTER(lrz_tiles_killed,
   "LRZ Tiles Killed",
   "",
   GPU_LRZ, UINT64,
   DERIVED_COUNTER_PERFCNTRS(LRZ_TILE_KILLED),
   {
      return LRZ_TILE_KILLED;
   });

const struct fd_derived_counter *a7xx_derived_counters[] = {
   /* Category: GPU General */
   DERIVED_COUNTER_PTR(clocks),

   /* Category: GPU Memory Stats */
   DERIVED_COUNTER_PTR(avg_bytes_per_fragment),
   DERIVED_COUNTER_PTR(avg_bytes_per_vertex),
   DERIVED_COUNTER_PTR(sp_memory_read),
   DERIVED_COUNTER_PTR(texture_memory_read),
   DERIVED_COUNTER_PTR(vertex_memory_read),

   /* Category: GPU Preemption */
   DERIVED_COUNTER_PTR(avg_preemption_delay),
   DERIVED_COUNTER_PTR(preemptions),

   /* Category: GPU Primitive Processing */
   DERIVED_COUNTER_PTR(average_polygon_area),
   DERIVED_COUNTER_PTR(average_vertices_per_polygon),
   DERIVED_COUNTER_PTR(preclipped_polygon),
   DERIVED_COUNTER_PTR(percent_prims_clipped),
   DERIVED_COUNTER_PTR(percent_prims_trivially_rejected),
   DERIVED_COUNTER_PTR(reused_vertices),

   /* Category: GPU Shader Processing */
   DERIVED_COUNTER_PTR(alu_per_fragment),
   DERIVED_COUNTER_PTR(alu_per_vertex),
   DERIVED_COUNTER_PTR(percent_anisotropic_filtered),
   DERIVED_COUNTER_PTR(average_bvh_fetch_latency_cycles),
   DERIVED_COUNTER_PTR(efu_per_fragment),
   DERIVED_COUNTER_PTR(efu_per_vertex),
   DERIVED_COUNTER_PTR(fragment_alu_instructions_full),
   DERIVED_COUNTER_PTR(fragment_alu_instructions_half),
   DERIVED_COUNTER_PTR(fragment_efu_instructions),
   DERIVED_COUNTER_PTR(fragment_instructions),
   DERIVED_COUNTER_PTR(fragments_shaded),
   DERIVED_COUNTER_PTR(percent_linear_filtered),
   DERIVED_COUNTER_PTR(percent_nearest_filtered),
   DERIVED_COUNTER_PTR(percent_rtu_busy),
   DERIVED_COUNTER_PTR(rtu_ray_box_intersections_per_instruction),
   DERIVED_COUNTER_PTR(rtu_ray_triangle_intersections_per_instruction),
   DERIVED_COUNTER_PTR(percent_shader_alu_capacity_utilized),
   DERIVED_COUNTER_PTR(percent_shaders_busy),
   DERIVED_COUNTER_PTR(percent_shaders_stalled),
   DERIVED_COUNTER_PTR(percent_texture_pipes_busy),
   DERIVED_COUNTER_PTR(textures_per_fragment),
   DERIVED_COUNTER_PTR(textures_per_vertex),
   DERIVED_COUNTER_PTR(percent_time_alus_working),
   DERIVED_COUNTER_PTR(percent_time_compute),
   DERIVED_COUNTER_PTR(percent_time_efus_working),
   DERIVED_COUNTER_PTR(percent_time_shading_fragments),
   DERIVED_COUNTER_PTR(percent_time_shading_vertices),
   DERIVED_COUNTER_PTR(vertex_instructions),
   DERIVED_COUNTER_PTR(vertices_shaded),

   /* Category: GPU Stalls */
   DERIVED_COUNTER_PTR(percent_bvh_fetch_stall),
   DERIVED_COUNTER_PTR(percent_instruction_cache_miss),
   DERIVED_COUNTER_PTR(l1_texture_cache_miss_per_pixel),
   DERIVED_COUNTER_PTR(percent_stalled_on_system_memory),
   DERIVED_COUNTER_PTR(percent_texture_fetch_stall),
   DERIVED_COUNTER_PTR(percent_texture_l1_miss),
   DERIVED_COUNTER_PTR(percent_texture_l2_miss),
   DERIVED_COUNTER_PTR(percent_vertex_fetch_stall),

   /* Category: GPU LRZ */
   DERIVED_COUNTER_PTR(percent_lrz_pixel_killed),
   DERIVED_COUNTER_PTR(lrz_primitives_killed),
   DERIVED_COUNTER_PTR(lrz_tiles_killed),
};

const unsigned a7xx_num_derived_counters = ARRAY_SIZE(a7xx_derived_counters);
static_assert(ARRAY_SIZE(a7xx_derived_counters) <= FD_DERIVED_COUNTER_COLLECTION_MAX_DERIVED_COUNTERS, "");

/* Prototype for linking purposes. */
void
a7xx_generate_derived_counter_collection(const struct fd_dev_id *id, struct fd_derived_counter_collection *collection);

void
a7xx_generate_derived_counter_collection(const struct fd_dev_id *id, struct fd_derived_counter_collection *collection)
{
   /* The provided collection should already specify the derived counters that will be measured.
    * This function will set up enabled_perfcntrs_map and enabled_perfcntrs array so that each
    * used DERIVED_COUNTER_PERFCNTR_* enum value will map to the corresponding index in the
    * array where the relevant fd_perfcntr_counter and fd_perfcntr_countable are stored.
    */

   collection->num_enabled_perfcntrs = 0;
   memset(collection->enabled_perfcntrs_map, 0xff, ARRAY_SIZE(collection->enabled_perfcntrs_map));

   for (unsigned i = 0; i < collection->num_counters; ++i) {
      const struct fd_derived_counter *counter = collection->counters[i];

      for (unsigned j = 0; j < counter->num_perfcntrs; ++j) {
         uint8_t perfcntr = counter->perfcntrs[j];
         collection->enabled_perfcntrs_map[perfcntr] = 0x00;
      }
   }

   /* Note if CP_ALWAYS_COUNT is enabled. This is the zero-index perfcntr. */
   collection->cp_always_count_enabled = !collection->enabled_perfcntrs_map[0];

   for (unsigned i = 0; i < ARRAY_SIZE(collection->enabled_perfcntrs_map); ++i) {
      if (collection->enabled_perfcntrs_map[i] == 0xff)
         continue;

      uint8_t enabled_perfcntr_index = collection->num_enabled_perfcntrs++;
      collection->enabled_perfcntrs_map[i] = enabled_perfcntr_index;

      collection->enabled_perfcntrs[enabled_perfcntr_index].counter =
         a7xx_derived_counter_perfcntrs[i].counter;
      collection->enabled_perfcntrs[enabled_perfcntr_index].countable =
         a7xx_derived_counter_perfcntrs[i].countable;
   }

   const struct fd_dev_info *info = fd_dev_info_raw(id);
   collection->derivation_context.a7xx.number_of_usptp = info->num_sp_cores * 2;
   collection->derivation_context.a7xx.number_of_alus_per_usptp = 128;
}

