Improve the skvm debug panel

Use SkVMBlitter::DebugName for the string. This is easier to read, and
has some actually useful information about the blitter.

Added magenta highlight of the hovered element, similar to the GPU.

Change-Id: Ic9b5a0f61e092c8aa555f375d5d2f2de22cc45fe
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/467977
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/core/SkVMBlitter.h b/src/core/SkVMBlitter.h
index 58270e0..5445048 100644
--- a/src/core/SkVMBlitter.h
+++ b/src/core/SkVMBlitter.h
@@ -8,6 +8,7 @@
 #ifndef SkVMBlitter_DEFINED
 #define SkVMBlitter_DEFINED
 
+#include "src/core/SkArenaAlloc.h"
 #include "src/core/SkBlitter.h"
 #include "src/core/SkLRUCache.h"
 #include "src/core/SkVM.h"
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index 637a1f5..94c6176 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -1853,6 +1853,29 @@
     return highlight;
 }
 
+static skvm::Program build_skvm_highlight_program(SkColorType ct, int nargs) {
+    // Code here is heavily tied to (and inspired by) SkVMBlitter::BuildProgram
+    skvm::Builder b;
+
+    // All VM blitters start with two arguments (uniforms, dst surface)
+    SkASSERT(nargs >= 2);
+    (void)b.uniform();
+    skvm::Ptr dst_ptr = b.varying(SkColorTypeBytesPerPixel(ct));
+
+    // Depending on coverage and shader, there can be additional arguments.
+    // Make sure that we append the right number, so that we don't assert when
+    // the CPU backend tries to run this program.
+    for (int i = 2; i < nargs; ++i) {
+        (void)b.uniform();
+    }
+
+    skvm::Color magenta = {b.splat(1.0f), b.splat(0.0f), b.splat(1.0f), b.splat(0.5f)};
+    skvm::PixelFormat dstFormat = skvm::SkColorType_to_PixelFormat(ct);
+    store(dstFormat, dst_ptr, magenta);
+
+    return b.done();
+}
+
 void Viewer::drawImGui() {
     // Support drawing the ImGui demo window. Superfluous, but gives a good idea of what's possible
     if (fShowImGuiTestWindow) {
@@ -2615,21 +2638,33 @@
             }
 
             if (ImGui::CollapsingHeader("SkVM")) {
-                if (ImGui::Button("Clear")) {
-                    if (auto* cache = SkVMBlitter::TryAcquireProgramCache()) {
-                        cache->reset();
-                        SkVMBlitter::ReleaseProgramCache();
-                    }
-                }
-                auto showVMEntry = [](const SkVMBlitter::Key* key, const skvm::Program* program) {
-                    uint8_t keyData[sizeof(*key)];
-                    memcpy(keyData, key, sizeof(*key));
-                    SkString keyString;
-                    for (size_t i = 0; i < sizeof(*key); ++i) {
-                        keyString.appendf("%02X", keyData[i]);
-                    }
+                auto* cache = SkVMBlitter::TryAcquireProgramCache();
+                SkASSERT(cache);
 
-                    if (ImGui::TreeNode(keyString.c_str())) {
+                if (ImGui::Button("Clear")) {
+                    cache->reset();
+                }
+
+                // First, go through the cache and restore the original program if we were hovering
+                if (!fHoveredProgram.empty()) {
+                    auto restoreHoveredProgram = [this](const SkVMBlitter::Key* key,
+                                                        skvm::Program* program) {
+                        if (*key == fHoveredKey) {
+                            *program = std::move(fHoveredProgram);
+                            fHoveredProgram = {};
+                        }
+                    };
+                    cache->foreach(restoreHoveredProgram);
+                }
+
+                // Now iterate again, and dump any expanded program. If any program is hovered,
+                // patch it, and remember the original (so it can be restored next frame).
+                auto showVMEntry = [this](const SkVMBlitter::Key* key, skvm::Program* program) {
+                    SkString keyString = SkVMBlitter::DebugName(*key);
+                    bool inTreeNode = ImGui::TreeNode(keyString.c_str());
+                    bool hovered = ImGui::IsItemHovered();
+
+                    if (inTreeNode) {
                         SkDynamicMemoryWStream stream;
                         program->dump(&stream);
                         auto dumpData = stream.detachAsData();
@@ -2644,11 +2679,19 @@
 
                         ImGui::TreePop();
                     }
+                    if (hovered) {
+                        // Generate a new blitter that just draws magenta
+                        skvm::Program highlightProgram = build_skvm_highlight_program(
+                                static_cast<SkColorType>(key->colorType), program->nargs());
+
+                        fHoveredKey = *key;
+                        fHoveredProgram = std::move(*program);
+                        *program = std::move(highlightProgram);
+                    }
                 };
-                if (auto* cache = SkVMBlitter::TryAcquireProgramCache()) {
-                    cache->foreach(showVMEntry);
-                    SkVMBlitter::ReleaseProgramCache();
-                }
+                cache->foreach(showVMEntry);
+
+                SkVMBlitter::ReleaseProgramCache();
             }
         }
         if (displayParamsChanged || uiParamsChanged) {
diff --git a/tools/viewer/Viewer.h b/tools/viewer/Viewer.h
index d93cbcc..467adef 100644
--- a/tools/viewer/Viewer.h
+++ b/tools/viewer/Viewer.h
@@ -14,6 +14,7 @@
 #include "include/gpu/GrContextOptions.h"
 #include "include/private/SkSLString.h"
 #include "src/core/SkScan.h"
+#include "src/core/SkVMBlitter.h"
 #include "src/sksl/ir/SkSLProgram.h"
 #include "tools/gpu/MemoryCache.h"
 #include "tools/sk_app/Application.h"
@@ -271,6 +272,9 @@
         kShaderOptLevel_Inline,
     };
     ShaderOptLevel fOptLevel = kShaderOptLevel_Source;
+
+    SkVMBlitter::Key fHoveredKey;
+    skvm::Program    fHoveredProgram;
 };
 
 #endif