Commit 84e76d8a2 for llama.cpp

commit 84e76d8a23162eca70490da131945ebec1f09bf4
Author: Georgi Gerganov <ggerganov@gmail.com>
Date:   Thu Sep 24 22:44:53 2026 +0300

    metal : fix graph capture and handle empty graphs (#29390)

    - return early when the graph has no nodes
    - drop the redundant reset of capture_compute: the decrement at the top
      of the function already transitions the counter from 0 to -1, so a
      capture happens exactly once
    - hint at METAL_CAPTURE_ENABLED=1 in the capture error message
    - pass capture_compute == 0 (not the raw counter) as use_capture to
      ggml_metal_op_init, so GPU debug-group markers are only emitted on the
      captured compute

    Assisted-by: pi:llama.cpp/Qwen3.8-27B

diff --git a/ggml/src/ggml-metal/ggml-metal-context.m b/ggml/src/ggml-metal/ggml-metal-context.m
index 442ed2a07..e9064666f 100644
--- a/ggml/src/ggml-metal/ggml-metal-context.m
+++ b/ggml/src/ggml-metal/ggml-metal-context.m
@@ -477,6 +477,10 @@ enum ggml_status ggml_metal_graph_compute(ggml_metal_t ctx, struct ggml_cgraph *
         return GGML_STATUS_FAILED;
     }

+    if (gf->n_nodes == 0) {
+        return GGML_STATUS_SUCCESS;
+    }
+
     // number of nodes encoded by the main thread (empirically determined)
     const int n_main = MAX(64, 0.1*gf->n_nodes);

@@ -514,8 +518,6 @@ enum ggml_status ggml_metal_graph_compute(ggml_metal_t ctx, struct ggml_cgraph *

         const bool use_capture = ctx->capture_compute == 0;
         if (use_capture) {
-            ctx->capture_compute = -1;
-
             // make sure all previous computations have finished before starting the capture
             if (ctx->cmd_buf_last) {
                 [ctx->cmd_buf_last waitUntilCompleted];
@@ -538,7 +540,7 @@ enum ggml_status ggml_metal_graph_compute(ggml_metal_t ctx, struct ggml_cgraph *

                 NSError * error = nil;
                 if (![[MTLCaptureManager sharedCaptureManager] startCaptureWithDescriptor:descriptor error:&error]) {
-                    GGML_LOG_ERROR("%s: error: unable to start capture '%s'\n", __func__, [[error localizedDescription] UTF8String]);
+                    GGML_LOG_ERROR("%s: error: unable to start capture '%s' (did you set METAL_CAPTURE_ENABLED=1 ?)\n", __func__, [[error localizedDescription] UTF8String]);
                 } else {
                     [ctx->capture_scope beginScope];
                     ctx->capture_started = true;
@@ -749,7 +751,7 @@ void ggml_metal_set_n_cb(ggml_metal_t ctx, int n_cb) {
             idx_start,
             idx_end,
             ctx->use_concurrency,
-            ctx->capture_compute,
+            ctx->capture_compute == 0,
             ctx->debug_graph);

         for (int idx = 0; idx < ggml_metal_op_n_nodes(ctx_op); ++idx) {