Skip to content

Commit 98987da

Browse files
Merge pull request #452 from janhq/update-dev-from-master-2026-03-14-00-44
Sync master with upstream release b8323
2 parents 6fffdd2 + 57819b8 commit 98987da

70 files changed

Lines changed: 3259 additions & 478 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,22 @@ jobs:
17271727
vulkaninfo --summary
17281728
GG_BUILD_VULKAN=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
17291729
1730+
ggml-ci-x64-linux-intel-vulkan:
1731+
runs-on: [self-hosted, Linux, X64, Intel]
1732+
1733+
steps:
1734+
- name: Clone
1735+
id: checkout
1736+
uses: actions/checkout@v6
1737+
with:
1738+
persist-credentials: false
1739+
1740+
- name: Test
1741+
id: ggml-ci
1742+
run: |
1743+
vulkaninfo --summary
1744+
GG_BUILD_VULKAN=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
1745+
17301746
ggml-ci-arm64-cpu-kleidiai:
17311747
runs-on: ubuntu-22.04-arm
17321748

common/arg.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -732,23 +732,28 @@ static void common_params_print_completion(common_params_context & ctx_arg) {
732732
"llama-completion",
733733
"llama-convert-llama2c-to-ggml",
734734
"llama-cvector-generator",
735+
"llama-debug",
736+
"llama-diffusion-cli",
735737
"llama-embedding",
736738
"llama-eval-callback",
737739
"llama-export-lora",
740+
"llama-finetune",
741+
"llama-fit-params",
742+
"llama-gemma3-cli",
738743
"llama-gen-docs",
739744
"llama-gguf",
740745
"llama-gguf-hash",
741746
"llama-gguf-split",
742-
"llama-gritlm",
747+
"llama-idle",
743748
"llama-imatrix",
744-
"llama-infill",
745-
"llama-mtmd-cli",
746-
"llama-llava-clip-quantize-cli",
749+
"llama-llava-cli",
747750
"llama-lookahead",
748751
"llama-lookup",
749752
"llama-lookup-create",
750753
"llama-lookup-merge",
751754
"llama-lookup-stats",
755+
"llama-minicpmv-cli",
756+
"llama-mtmd-cli",
752757
"llama-parallel",
753758
"llama-passkey",
754759
"llama-perplexity",
@@ -2666,7 +2671,8 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
26662671
[](common_params & params, const std::string & value) {
26672672
params.out_file = value;
26682673
}
2669-
).set_examples({LLAMA_EXAMPLE_IMATRIX, LLAMA_EXAMPLE_CVECTOR_GENERATOR, LLAMA_EXAMPLE_EXPORT_LORA, LLAMA_EXAMPLE_TTS, LLAMA_EXAMPLE_FINETUNE, LLAMA_EXAMPLE_RESULTS}));
2674+
).set_examples({LLAMA_EXAMPLE_IMATRIX, LLAMA_EXAMPLE_CVECTOR_GENERATOR, LLAMA_EXAMPLE_EXPORT_LORA, LLAMA_EXAMPLE_TTS, LLAMA_EXAMPLE_FINETUNE,
2675+
LLAMA_EXAMPLE_RESULTS, LLAMA_EXAMPLE_EXPORT_GRAPH_OPS}));
26702676
add_opt(common_arg(
26712677
{"-ofreq", "--output-frequency"}, "N",
26722678
string_format("output the imatrix every N iterations (default: %d)", params.n_out_freq),

common/chat.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,77 @@ static common_chat_params common_chat_params_init_lfm2(const common_chat_templat
13541354
return data;
13551355
}
13561356

1357+
static common_chat_params common_chat_params_init_gigachat_v3(
1358+
const common_chat_template & tmpl,
1359+
const autoparser::templates_params & inputs) {
1360+
1361+
common_chat_params data;
1362+
1363+
data.prompt = common_chat_template_direct_apply(tmpl, inputs);
1364+
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
1365+
data.supports_thinking = false;
1366+
data.preserved_tokens = {
1367+
"<|message_sep|>\n\n",
1368+
"<|role_sep|>\n",
1369+
};
1370+
1371+
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
1372+
auto include_grammar = has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE;
1373+
auto tool_call_start_prefix = "<|message_sep|>\n\nfunction call<|role_sep|>\n";
1374+
1375+
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
1376+
if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE) {
1377+
// Build a choice of all available tools
1378+
auto tool_choice = p.choice();
1379+
for (const auto & tool : inputs.tools) {
1380+
const auto & function = tool.at("function");
1381+
std::string name = function.at("name");
1382+
const auto & schema = function.at("parameters");
1383+
1384+
auto tool_name = p.json_member("name", "\"" + p.tool_name(p.literal(name)) + "\"");
1385+
auto tool_args = p.json_member("arguments", p.tool_args(p.schema(p.json(), "tool-" + name + "-schema", schema)));
1386+
1387+
auto tool_open = p.tool_open(p.literal("{") << tool_name);
1388+
1389+
tool_choice |= p.rule("tool-" + name, tool_open << "," << tool_args << "}");
1390+
}
1391+
1392+
// Define the tool call structure
1393+
auto min_calls = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ? 1 : 0;
1394+
auto max_calls = 1; // parallel toolcalls are not supported
1395+
auto tool_call = p.rule("tool-call", p.literal(tool_call_start_prefix) + tool_choice);
1396+
auto tool_calls = p.trigger_rule("tool-call-root", p.repeat(tool_call, /* min = */ min_calls, /* max = */ max_calls));
1397+
1398+
return p.content(p.until("<|message_sep|>\n\n")) << tool_calls;
1399+
}
1400+
1401+
// Content only parser
1402+
include_grammar = false;
1403+
return p.content(p.rest());
1404+
1405+
});
1406+
1407+
data.parser = parser.save();
1408+
1409+
if (include_grammar) {
1410+
data.grammar_lazy = has_tools && inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO;
1411+
1412+
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
1413+
foreach_function(inputs.tools, [&](const json & tool) {
1414+
const auto & function = tool.at("function");
1415+
auto schema = function.at("parameters");
1416+
builder.resolve_refs(schema);
1417+
});
1418+
parser.build_grammar(builder, data.grammar_lazy);
1419+
});
1420+
1421+
data.grammar_triggers = {
1422+
{COMMON_GRAMMAR_TRIGGER_TYPE_WORD, tool_call_start_prefix}
1423+
};
1424+
}
1425+
return data;
1426+
}
1427+
13571428
namespace workaround {
13581429

13591430
static void map_developer_role_to_system(json & messages) {
@@ -1525,6 +1596,15 @@ static common_chat_params common_chat_templates_apply_jinja(const struct common_
15251596
return common_chat_params_init_lfm2(tmpl, params);
15261597
}
15271598

1599+
// GigaChatV3 format detection
1600+
if (src.find("<|role_sep|>") != std::string::npos &&
1601+
src.find("<|message_sep|>") != std::string::npos &&
1602+
src.find("<|function_call|>") == std::string::npos
1603+
) {
1604+
LOG_DBG("Using specialized template: GigaChatV3\n");
1605+
return common_chat_params_init_gigachat_v3(tmpl, params);
1606+
}
1607+
15281608
try {
15291609
LOG_DBG("Using differential autoparser\n");
15301610
struct autoparser::autoparser autoparser;

common/common.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ enum llama_example {
105105
LLAMA_EXAMPLE_FINETUNE,
106106
LLAMA_EXAMPLE_FIT_PARAMS,
107107
LLAMA_EXAMPLE_RESULTS,
108+
LLAMA_EXAMPLE_EXPORT_GRAPH_OPS,
108109

109110
LLAMA_EXAMPLE_COUNT,
110111
};
@@ -926,7 +927,7 @@ const char * const LLM_KV_SPLIT_TENSORS_COUNT = "split.tensors.count";
926927
// MoE utils
927928
//
928929

929-
const char * const LLM_FFN_EXPS_REGEX = "\\.ffn_(up|down|gate)_(ch|)exps";
930+
const char * const LLM_FFN_EXPS_REGEX = "\\.ffn_(up|down|gate|gate_up)_(ch|)exps";
930931

931932
inline std::string llm_ffn_exps_block_regex(int idx) {
932933
return string_format("blk\\.%d%s", idx, LLM_FFN_EXPS_REGEX);

convert_hf_to_gguf.py

Lines changed: 126 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5062,7 +5062,7 @@ def set_gguf_parameters(self):
50625062
self.gguf_writer.add_add_bos_token(False)
50635063

50645064

5065-
@ModelBase.register("Phi3ForCausalLM")
5065+
@ModelBase.register("Phi3ForCausalLM", "Phi4ForCausalLMV")
50665066
class Phi3MiniModel(TextModel):
50675067
model_arch = gguf.MODEL_ARCH.PHI3
50685068

@@ -5237,6 +5237,129 @@ def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
52375237
yield (self.format_tensor_name(gguf.MODEL_TENSOR.ROPE_FACTORS_LONG), torch.tensor(long_factors, dtype=torch.float32))
52385238
yield (self.format_tensor_name(gguf.MODEL_TENSOR.ROPE_FACTORS_SHORT), torch.tensor(short_factors, dtype=torch.float32))
52395239

5240+
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
5241+
if name.startswith(("model.vision_tower.", "vision_tower.", "model.mm_projector.", "mm_projector.")):
5242+
return
5243+
5244+
yield from super().modify_tensors(data_torch, name, bid)
5245+
5246+
5247+
@ModelBase.register("Phi4ForCausalLMV")
5248+
class Phi4VisionMmprojModel(MmprojModel):
5249+
def __init__(self, *args, **kwargs):
5250+
super().__init__(*args, **kwargs)
5251+
assert self.hparams_vision is not None
5252+
5253+
self.vision_total_layers = int(self.find_vparam(self.n_block_keys))
5254+
if self.vision_total_layers < 2:
5255+
raise ValueError(
5256+
f"Phi-4 vision mmproj conversion requires at least 2 vision layers, got {self.vision_total_layers}"
5257+
)
5258+
5259+
# Phi-4 uses SigLIP2 hidden_states[-2], so export one fewer encoder block and
5260+
# drop post-layernorm/head weights. This makes the GGUF runtime output match
5261+
# the feature map consumed by the patched siglip.cpp Phi-4 projector path.
5262+
self.vision_export_layers = self.vision_total_layers - 1
5263+
self.vision_last_layer_idx = self.vision_total_layers - 1
5264+
5265+
for key in self.n_block_keys:
5266+
if key in self.hparams_vision:
5267+
self.hparams_vision[key] = self.vision_export_layers
5268+
break
5269+
5270+
self.block_count = self.vision_export_layers
5271+
self.tensor_map = gguf.get_tensor_name_map(gguf.MODEL_ARCH.MMPROJ, self.block_count)
5272+
5273+
patch_size = self.preprocessor_config.get("patch_size")
5274+
if patch_size is None:
5275+
raise KeyError("Phi-4 vision mmproj conversion requires patch_size in preprocessor_config.json")
5276+
5277+
self.hparams_vision["patch_size"] = patch_size
5278+
5279+
pos_emb_name = next(
5280+
(
5281+
name for name in self.model_tensors
5282+
if name.endswith("vision_model.embeddings.position_embedding.weight")
5283+
),
5284+
None,
5285+
)
5286+
if pos_emb_name is None:
5287+
raise KeyError("Phi-4 vision mmproj conversion could not find position_embedding.weight")
5288+
5289+
pos_emb_shape = self.model_tensors[pos_emb_name]().shape
5290+
base_grid_tokens = int(pos_emb_shape[0])
5291+
grid_side = math.isqrt(base_grid_tokens)
5292+
if grid_side * grid_side != base_grid_tokens:
5293+
raise ValueError(f"Unexpected Phi-4 position embedding shape: {tuple(pos_emb_shape)}")
5294+
5295+
self.hparams_vision["image_size"] = grid_side * patch_size
5296+
5297+
min_num_patches = self.preprocessor_config.get("min_num_patches", self.global_config.get("min_num_patches"))
5298+
max_num_patches = self.preprocessor_config.get("max_num_patches", self.global_config.get("max_num_patches"))
5299+
if min_num_patches is None or max_num_patches is None:
5300+
raise KeyError("Phi-4 vision mmproj conversion requires min_num_patches and max_num_patches")
5301+
5302+
self.min_pixels = int(min_num_patches) * patch_size * patch_size
5303+
self.max_pixels = int(max_num_patches) * patch_size * patch_size
5304+
5305+
def set_gguf_parameters(self):
5306+
super().set_gguf_parameters()
5307+
assert self.hparams_vision is not None
5308+
5309+
self.gguf_writer.add_clip_projector_type(gguf.VisionProjectorType.PHI4)
5310+
self.gguf_writer.add_vision_min_pixels(self.min_pixels)
5311+
self.gguf_writer.add_vision_max_pixels(self.max_pixels)
5312+
self.gguf_writer.add_vision_use_gelu(True)
5313+
self.gguf_writer.add_vision_attention_layernorm_eps(self.hparams_vision.get("layer_norm_eps", 1e-6))
5314+
5315+
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
5316+
if name.startswith(("model.vision_tower.vision_tower.", "vision_tower.")):
5317+
if ".vision_model.head." in name:
5318+
return
5319+
5320+
new_name = name.replace("model.vision_tower.vision_tower.", "vision_tower.")
5321+
5322+
if ".vision_model.post_layernorm." in new_name:
5323+
return
5324+
5325+
if bid is not None and bid == self.vision_last_layer_idx:
5326+
return
5327+
5328+
if new_name.endswith("vision_model.embeddings.patch_embedding.weight"):
5329+
assert self.hparams_vision is not None
5330+
if data_torch.ndim != 2:
5331+
raise ValueError(f"Unexpected Phi-4 patch embedding shape: {tuple(data_torch.shape)}")
5332+
5333+
patch_area = self.hparams_vision["patch_size"] ** 2
5334+
in_features = data_torch.shape[1]
5335+
if in_features % patch_area != 0:
5336+
raise ValueError(
5337+
f"Phi-4 patch embedding input dim {in_features} is not divisible by patch area {patch_area}"
5338+
)
5339+
5340+
num_channels = in_features // patch_area
5341+
patch_size = self.hparams_vision["patch_size"]
5342+
data_torch = data_torch.view(data_torch.shape[0], patch_size, patch_size, num_channels)
5343+
data_torch = data_torch.permute(0, 3, 1, 2)
5344+
5345+
yield from super().modify_tensors(data_torch, new_name, bid)
5346+
return
5347+
5348+
if name.startswith(("model.mm_projector.", "mm_projector.")):
5349+
local_name = name
5350+
local_name = local_name.replace("model.mm_projector.", "")
5351+
local_name = local_name.replace("mm_projector.", "")
5352+
5353+
if not (local_name.startswith("0.") or local_name.startswith("2.")):
5354+
return
5355+
5356+
suffix = ".bias" if local_name.endswith(".bias") else ".weight"
5357+
mm_idx = int(local_name.split(".", maxsplit=1)[0])
5358+
yield (self.format_tensor_name(gguf.MODEL_TENSOR.V_MMPROJ, mm_idx, suffix=suffix), data_torch)
5359+
return
5360+
5361+
return
5362+
52405363

52415364
@ModelBase.register("PhiMoEForCausalLM")
52425365
class PhiMoeModel(Phi3MiniModel):
@@ -9969,9 +10092,9 @@ def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iter
996910092
# Skip Multi-Token Prediction (MTP) tensors. These are used for
997010093
# for speculative decoding but we don't include them in this model
997110094
# conversion. See https://github.com/ggml-org/llama.cpp/pull/18886
9972-
if "mtp" in name:
10095+
if name.startswith("mtp."):
997310096
logger.info(f"gguf: Skipping MTP (Speculative) layer: {name}")
9974-
return []
10097+
return
997510098

997610099
if name.endswith("mixer.gate.e_score_correction_bias"):
997710100
new_name = name.replace("e_score_correction_bias", "e_score_correction.bias")

docs/backend/VirtGPU/development.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ LLAMA_MAC_BUILD=$PWD/build/ggml-virtgpu-backend
5555
cmake -S . -B $LLAMA_MAC_BUILD \
5656
-DGGML_NATIVE=OFF \
5757
-DLLAMA_CURL=ON \
58-
-DGGML_REMOTINGBACKEND=ONLY \
58+
-DGGML_VIRTGPU=ON \
59+
-DGGML_VIRTGPU_BACKEND=ONLY \
5960
-DGGML_METAL=ON
6061

6162
TARGETS="ggml-metal"
@@ -71,6 +72,7 @@ cmake --build $LLAMA_MAC_BUILD --parallel 8 --target $EXTRA_TARGETS
7172
```bash
7273
# Build virglrenderer with APIR support
7374
mkdir virglrenderer
75+
cd virglrenderer
7476
git clone https://gitlab.freedesktop.org/kpouget/virglrenderer -b main-macos src
7577
cd src
7678

@@ -95,7 +97,7 @@ mkdir llama.cpp
9597
git clone https://github.com/ggml-org/llama.cpp.git src
9698
cd src
9799

98-
LLAMA_LINUX_BUILD=$PWD//build-virtgpu
100+
LLAMA_LINUX_BUILD=$PWD/build-virtgpu
99101

100102
cmake -S . -B $LLAMA_LINUX_BUILD \
101103
-DGGML_VIRTGPU=ON

docs/ops.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Legend:
8080
| POOL_2D || 🟡 ||||||||||
8181
| REGLU ||||| 🟡 ||| 🟡 ||||
8282
| RELU |||| 🟡 | 🟡 | 🟡 || 🟡 ||||
83-
| REPEAT |||| 🟡 || 🟡 || 🟡 | |||
83+
| REPEAT |||| 🟡 || 🟡 || 🟡 | |||
8484
| REPEAT_BACK ||||||||||||
8585
| RMS_NORM ||||||||||||
8686
| RMS_NORM_BACK ||||||||||||

docs/ops/WebGPU.csv

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5023,20 +5023,20 @@
50235023
"WebGPU: WebGPU","ARGMAX","type=f32,ne=[1024,12,1,1]","support","1","yes","WebGPU"
50245024
"WebGPU: WebGPU","ARGMAX","type=f32,ne=[2000,10,1,1]","support","1","yes","WebGPU"
50255025
"WebGPU: WebGPU","ARGMAX","type=f32,ne=[5438,3,1,1]","support","1","yes","WebGPU"
5026-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,1,1]","support","0","no","WebGPU"
5027-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[2,1,1,1]","support","0","no","WebGPU"
5028-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,2,1,1]","support","0","no","WebGPU"
5029-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,2,1]","support","0","no","WebGPU"
5030-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,1,2]","support","0","no","WebGPU"
5031-
"WebGPU: WebGPU","REPEAT","type=i32,ne=[10,5,4,1],nr=[2,1,1,1]","support","0","no","WebGPU"
5032-
"WebGPU: WebGPU","REPEAT","type=i16,ne=[10,5,4,1],nr=[1,1,1,2]","support","0","no","WebGPU"
5033-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,1,1]","support","0","no","WebGPU"
5034-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[2,1,1,1]","support","0","no","WebGPU"
5035-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,2,1,1]","support","0","no","WebGPU"
5036-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,2,1]","support","0","no","WebGPU"
5037-
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,1,2]","support","0","no","WebGPU"
5038-
"WebGPU: WebGPU","REPEAT","type=i32,ne=[10,5,4,3],nr=[2,1,1,1]","support","0","no","WebGPU"
5039-
"WebGPU: WebGPU","REPEAT","type=i16,ne=[10,5,4,3],nr=[1,1,1,2]","support","0","no","WebGPU"
5026+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,1,1]","support","1","yes","WebGPU"
5027+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[2,1,1,1]","support","1","yes","WebGPU"
5028+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,2,1,1]","support","1","yes","WebGPU"
5029+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,2,1]","support","1","yes","WebGPU"
5030+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,1,2]","support","1","yes","WebGPU"
5031+
"WebGPU: WebGPU","REPEAT","type=i32,ne=[10,5,4,1],nr=[2,1,1,1]","support","1","yes","WebGPU"
5032+
"WebGPU: WebGPU","REPEAT","type=i16,ne=[10,5,4,1],nr=[1,1,1,2]","support","1","yes","WebGPU"
5033+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,1,1]","support","1","yes","WebGPU"
5034+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[2,1,1,1]","support","1","yes","WebGPU"
5035+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,2,1,1]","support","1","yes","WebGPU"
5036+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,2,1]","support","1","yes","WebGPU"
5037+
"WebGPU: WebGPU","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,1,2]","support","1","yes","WebGPU"
5038+
"WebGPU: WebGPU","REPEAT","type=i32,ne=[10,5,4,3],nr=[2,1,1,1]","support","1","yes","WebGPU"
5039+
"WebGPU: WebGPU","REPEAT","type=i16,ne=[10,5,4,3],nr=[1,1,1,2]","support","1","yes","WebGPU"
50405040
"WebGPU: WebGPU","REPEAT_BACK","type=f32,ne=[8,6,4,2],nr=[1,1,1,1],v=0","support","0","no","WebGPU"
50415041
"WebGPU: WebGPU","REPEAT_BACK","type=f32,ne=[8,6,4,2],nr=[2,1,1,1],v=0","support","0","no","WebGPU"
50425042
"WebGPU: WebGPU","REPEAT_BACK","type=f32,ne=[8,6,4,2],nr=[1,2,1,1],v=0","support","0","no","WebGPU"

0 commit comments

Comments
 (0)