From cc58e3456dce86187f42fba24658846c9965e0c2 Mon Sep 17 00:00:00 2001 From: "Michal J. Gajda" Date: Tue, 14 Apr 2026 23:12:46 +0200 Subject: [PATCH 1/3] Fix GRBM_STATUS bit positions and labels for RDNA (GFX10+) On RDNA, the GRBM_STATUS register layout changed: - Bit 10 (Event Engine): reserved/undefined - Bits 16-17 (VGT): replaced by Geometry Engine at bit 21 - Bit 21 (Sequencer Instruction Cache): now Geometry Engine Repurpose the VGT field to read GE_BUSY (bit 21) and label it "Geometry Engine" in the UI and dump output. Hide Event Engine and Sequencer Instruction Cache on RDNA since those blocks no longer exist. Other bits (TA, SX, SPI, SC, PA, DB, CB, GUI) are unchanged across all generations. --- detect.c | 8 ++++++++ dump.c | 8 +++++--- ui.c | 21 ++++++++++++++------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/detect.c b/detect.c index f9a1e843..d66aeef5 100644 --- a/detect.c +++ b/detect.c @@ -377,4 +377,12 @@ void initbits(int fam) { bits.vce0 = (1U << 7); } } + + // RDNA (GFX10+): VGT replaced by Geometry Engine at bit 21, + // Event Engine and Sequencer Instruction Cache bits undefined. + if (fam >= NAVI10) { + bits.ee = 0; + bits.vgt = (1U << 21); + bits.sh = 0; + } } diff --git a/dump.c b/dump.c index e0ab409c..bd526c27 100644 --- a/dump.c +++ b/dump.c @@ -108,15 +108,17 @@ void dumpdata(const unsigned int ticks, const char file[], const unsigned int li float sclk_ghz = results->sclk * k / 1000.0f; fprintf(f, "gpu %.2f%%, ", gui); - fprintf(f, "ee %.2f%%, ", ee); - fprintf(f, "vgt %.2f%%, ", vgt); + if (bits.ee) + fprintf(f, "ee %.2f%%, ", ee); + fprintf(f, "%s %.2f%%, ", bits.ee ? "vgt" : "ge", vgt); fprintf(f, "ta %.2f%%, ", ta); if (bits.tc) fprintf(f, "tc %.2f%%, ", tc); fprintf(f, "sx %.2f%%, ", sx); - fprintf(f, "sh %.2f%%, ", sh); + if (bits.sh) + fprintf(f, "sh %.2f%%, ", sh); fprintf(f, "spi %.2f%%, ", spi); if (bits.smx) diff --git a/ui.c b/ui.c index 34e815d7..df76a0a0 100644 --- a/ui.c +++ b/ui.c @@ -175,15 +175,20 @@ void present(const unsigned int ticks, const char card[], unsigned int color, unsigned int start = 4; - percentage(start, w, ee); - printright(start++, hw, _("Event Engine %6.2f%%"), ee); + if (bits.ee) { + percentage(start, w, ee); + printright(start++, hw, _("Event Engine %6.2f%%"), ee); - // Enough height? - if (h > bigh) start++; + // Enough height? + if (h > bigh) start++; + } if (color) attron(COLOR_PAIR(2)); percentage(start, w, vgt); - printright(start++, hw, _("Vertex Grouper + Tesselator %6.2f%%"), vgt); + if (bits.ee) + printright(start++, hw, _("Vertex Grouper + Tesselator %6.2f%%"), vgt); + else + printright(start++, hw, _("Geometry Engine %6.2f%%"), vgt); if (color) attroff(COLOR_PAIR(2)); // Enough height? @@ -207,8 +212,10 @@ void present(const unsigned int ticks, const char card[], unsigned int color, percentage(start, w, sx); printright(start++, hw, _("Shader Export %6.2f%%"), sx); - percentage(start, w, sh); - printright(start++, hw, _("Sequencer Instruction Cache %6.2f%%"), sh); + if (bits.sh) { + percentage(start, w, sh); + printright(start++, hw, _("Sequencer Instruction Cache %6.2f%%"), sh); + } percentage(start, w, spi); printright(start++, hw, _("Shader Interpolator %6.2f%%"), spi); From 0dec4c0fdd9c432972e84ca3cec669f868cd920f Mon Sep 17 00:00:00 2001 From: "Michal J. Gajda" Date: Wed, 15 Apr 2026 11:09:50 +0200 Subject: [PATCH 2/3] Add VCN (Video Core Next) monitoring for RDNA VCN (Video Core Next) is the video decode/encode block on RDNA GPUs, replacing UVD/VCE from older architectures. Monitor bit 1 of SRBM_STATUS2 for VCN utilization on NAVI10+. Changes: - Add bits.vcn field to track VCN busy status in SRBM_STATUS2 bit 1 - Configure VCN bit in initbits() for RDNA (fam >= NAVI10) - Collect VCN data in ticks.c and aggregate in result histograms - Display VCN utilization in ui.c and dump.c output VCN monitoring is available without root via amdgpu driver (SRBM_STATUS2 is whitelisted for read access). --- detect.c | 6 ++++++ dump.c | 3 +++ include/radeontop.h | 1 + ticks.c | 10 +++++++--- ui.c | 5 +++++ 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/detect.c b/detect.c index d66aeef5..60a3036b 100644 --- a/detect.c +++ b/detect.c @@ -361,6 +361,7 @@ void initbits(int fam) { bits.gui = (1U << 31); bits.uvd = 0; bits.vce0 = 0; + bits.vcn = 0; // R600 has a different texture bit, and only R600 has the TC, CR, SMX bits if (fam < RV770) { @@ -378,6 +379,11 @@ void initbits(int fam) { } } + // VCN (Video Core Next) on RDNA: bit 1 of SRBM_STATUS2 + if (fam >= NAVI10) { + bits.vcn = (1U << 1); + } + // RDNA (GFX10+): VGT replaced by Geometry Engine at bit 21, // Event Engine and Sequencer Instruction Cache bits undefined. if (fam >= NAVI10) { diff --git a/dump.c b/dump.c index bd526c27..4b1f4717 100644 --- a/dump.c +++ b/dump.c @@ -98,6 +98,7 @@ void dumpdata(const unsigned int ticks, const char file[], const unsigned int li float cb = 100 * results->cb * k; float uvd = 100 * results->uvd * k; float vce0 = 100 * results->vce0 * k; + float vcn = 100 * results->vcn * k; float vram = 100.0f * results->vram / vramsize; float vrammb = results->vram / 1024.0f / 1024.0f; float gtt = 100.0f * results->gtt / gttsize; @@ -135,6 +136,8 @@ void dumpdata(const unsigned int ticks, const char file[], const unsigned int li fprintf(f, ", uvd %.2f%%", uvd); if (bits.vce0) fprintf(f, ", vce0 %.2f%%", vce0); + if (bits.vcn) + fprintf(f, ", vcn %.2f%%", vcn); if (bits.vram) fprintf(f, ", vram %.2f%% %.2fmb", vram, vrammb); diff --git a/include/radeontop.h b/include/radeontop.h index b1a13226..0fac933f 100644 --- a/include/radeontop.h +++ b/include/radeontop.h @@ -160,6 +160,7 @@ struct bits_t { unsigned int cr; unsigned int uvd; unsigned int vce0; + unsigned int vcn; uint64_t vram; uint64_t gtt; unsigned int sclk; diff --git a/ticks.c b/ticks.c index 90b8cab4..0716824d 100644 --- a/ticks.c +++ b/ticks.c @@ -43,8 +43,8 @@ static void *collector(void *arg) { getgrbm(&stat); unsigned int uvd; if (bits.uvd) getsrbm(&uvd); - unsigned int vce; - if (bits.vce0) getsrbm2(&vce); + unsigned int srbm2; + if (bits.vce0 || bits.vcn) getsrbm2(&srbm2); memset(&history[cur], 0, sizeof(struct bits_t)); @@ -63,7 +63,10 @@ static void *collector(void *arg) { if (stat & bits.cr) history[cur].cr = 1; if (stat & bits.cb) history[cur].cb = 1; if (uvd & bits.uvd) history[cur].uvd = 1; - if (vce & bits.vce0) history[cur].vce0 = 1; + if (bits.vce0 || bits.vcn) { + if (srbm2 & bits.vce0) history[cur].vce0 = 1; + if (srbm2 & bits.vcn) history[cur].vcn = 1; + } getsclk(&history[cur].sclk); getmclk(&history[cur].mclk); @@ -94,6 +97,7 @@ static void *collector(void *arg) { res[curres].cr += history[i].cr; res[curres].uvd += history[i].uvd; res[curres].vce0 += history[i].vce0; + res[curres].vcn += history[i].vcn; res[curres].mclk += history[i].mclk; res[curres].sclk += history[i].sclk; } diff --git a/ui.c b/ui.c index df76a0a0..12892b88 100644 --- a/ui.c +++ b/ui.c @@ -153,6 +153,7 @@ void present(const unsigned int ticks, const char card[], unsigned int color, float cb = 100 * results->cb * k; float uvd = 100 * results->uvd * k; float vce0 = 100 * results->vce0 * k; + float vcn = 100 * results->vcn * k; float vram = 100.0f * results->vram / vramsize; float vrammb = results->vram / 1024.0f / 1024.0f; float vramsizemb = vramsize / 1024.0f / 1024.0f; @@ -261,6 +262,10 @@ void present(const unsigned int ticks, const char card[], unsigned int color, percentage(start, w, vce0); printright(start++, hw, _("VCE %6.2f%%"), vce0); } + if (bits.vcn) { + percentage(start, w, vcn); + printright(start++, hw, _("VCN %6.2f%%"), vcn); + } if (bits.vram || bits.gtt) { // Enough height? From 0233d16035b8f23d64366474c6b62e242d187aa3 Mon Sep 17 00:00:00 2001 From: "Michal J. Gajda" Date: Wed, 15 Apr 2026 11:43:22 +0200 Subject: [PATCH 3/3] Update VCN label to 'Video Core' Change display label from 'VCN' to 'Video Core' for consistency and clarity. Keeps internal vcn field name for backward compatibility. Changes: - detect.c: Comment updated for clarity - ui.c: UI label changed to 'Video Core' - dump.c: CSV key changed to 'vc' for compact output --- detect.c | 2 +- dump.c | 2 +- ui.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/detect.c b/detect.c index 60a3036b..131b0a70 100644 --- a/detect.c +++ b/detect.c @@ -379,7 +379,7 @@ void initbits(int fam) { } } - // VCN (Video Core Next) on RDNA: bit 1 of SRBM_STATUS2 + // Video Core (VCN) on RDNA: bit 1 of SRBM_STATUS2 if (fam >= NAVI10) { bits.vcn = (1U << 1); } diff --git a/dump.c b/dump.c index 4b1f4717..62fc13b5 100644 --- a/dump.c +++ b/dump.c @@ -137,7 +137,7 @@ void dumpdata(const unsigned int ticks, const char file[], const unsigned int li if (bits.vce0) fprintf(f, ", vce0 %.2f%%", vce0); if (bits.vcn) - fprintf(f, ", vcn %.2f%%", vcn); + fprintf(f, ", vc %.2f%%", vcn); if (bits.vram) fprintf(f, ", vram %.2f%% %.2fmb", vram, vrammb); diff --git a/ui.c b/ui.c index 12892b88..c3d18743 100644 --- a/ui.c +++ b/ui.c @@ -264,7 +264,7 @@ void present(const unsigned int ticks, const char card[], unsigned int color, } if (bits.vcn) { percentage(start, w, vcn); - printright(start++, hw, _("VCN %6.2f%%"), vcn); + printright(start++, hw, _("Video Core %6.2f%%"), vcn); } if (bits.vram || bits.gtt) {