char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
0190529ec
char/aliceai-t5-moe
1#ifndef GGML_WEBGPU_SHADER_LIB_HPP 2#define GGML_WEBGPU_SHADER_LIB_HPP 3 4#include "ggml-impl.h" 5#include "ggml-wgsl-shaders.hpp" 6#include "ggml.h" 7#include "pre_wgsl.hpp" 8 9#include <webgpu/webgpu_cpp.h> 10 11#include <algorithm> 12#include <memory> 13#include <string> 14#include <unordered_map> 15#include <vector> 16 17#define GGML_WEBGPU_F16_SIZE_BYTES 2 18#define GGML_WEBGPU_F32_SIZE_BYTES 4 19#define GGML_WEBGPU_I32_SIZE_BYTES 4 20#define GGML_WEBGPU_FLASH_ATTN_PREFERRED_KV_SG_TILES 8u 21#define GGML_WEBGPU_FLASH_ATTN_VEC_MAX_SEQ_LEN 20u 22#define GGML_WEBGPU_FLASH_ATTN_VEC_MAX_KV_TILE 32u 23#define GGML_WEBGPU_FLASH_ATTN_TILE_MAX_KV_TILE 64u 24#define GGML_WEBGPU_FLASH_ATTN_PREFERRED_WG_SIZE 128u 25// Matches GGML_PAD(..., 256) in src/llama-context.cpp for KV cache sizing. 26#define GGML_WEBGPU_KV_SEQ_PAD 256u 27 28#define GGML_WEBGPU_ARGSORT_MERGE_MAX_WG_SIZE 512u 29 30// Matrix multiplication parameters 31 32// Register tiling parameters 33#define WEBGPU_MUL_MAT_TILE_M 4 34#define WEBGPU_MUL_MAT_TILE_N 4 35#define WEBGPU_MUL_MAT_WG_SIZE_M 8 36#define WEBGPU_MUL_MAT_WG_SIZE_N 8 37#define WEBGPU_MUL_MAT_REG_TILE_K_FLOAT 8 38#define WEBGPU_MUL_MAT_REG_TILE_K_QUANT 32 39 40// Subgroup matrix parameters 41// The number of subgroups in the M dimension 42#define WEBGPU_MUL_MAT_SUBGROUP_M 2 43// The number of subgroups in the N dimension 44#define WEBGPU_MUL_MAT_SUBGROUP_N 4 45// The number of subgroup matrices each subgroup accumulates over 46#define WEBGPU_MUL_MAT_SUBGROUP_MATRIX_M 4 47#define WEBGPU_MUL_MAT_SUBGROUP_MATRIX_N 2 48#define WEBGPU_MUL_MAT_SUBGROUP_TILE_K_FLOAT 32 49#define WEBGPU_MUL_MAT_SUBGROUP_TILE_K_QUANT 32 50 51// Matrix-vector multiplication parameters 52#define WEBGPU_MUL_MAT_VEC_WG_SIZE 256 53 54#define WEBGPU_MUL_MAT_VEC_FLOAT_OUTPUTS_PER_WG 4 55#define WEBGPU_MUL_MAT_VEC_LEGACY_Q_OUTPUTS_PER_WG 4 56#define WEBGPU_MUL_MAT_VEC_K_Q_OUTPUTS_PER_WG 4 57 58// default size for reg-tile matrix multiplication 59#define WEBGPU_MUL_MAT_WG_SIZE 256 60 61// Same hash combine function as in boost 62template < typename T > inline void ggml_webgpu_hash_combine (size_t & seed ,const T & value ) { 63seed ^= std::hash < T > {}(value )+ 0x9e3779b9 + (seed <<6 )+ (seed >>2 ); 64} 65 66// Calculates base address of a tensor ignoring the fake base pointer 67inline uintptr_t ggml_webgpu_tensor_addr (const ggml_tensor * tensor ) { 68const ggml_tensor * base_tensor = tensor -> view_src ?tensor -> view_src :tensor ; 69return (uintptr_t )base_tensor -> data + tensor -> view_offs ; 70} 71 72inline bool ggml_webgpu_tensor_equal (const ggml_tensor * a ,const ggml_tensor * b ) { 73return a -> buffer == b -> buffer && ggml_webgpu_tensor_addr (a )== ggml_webgpu_tensor_addr (b ); 74} 75 76struct ggml_webgpu_shader_lib_context { 77ggml_tensor * src0 ; 78ggml_tensor * src1 ; 79ggml_tensor * src2 ; 80ggml_tensor * src3 ; 81ggml_tensor * src4 ; 82ggml_tensor * src5 ; 83ggml_tensor * dst ; 84 85uint32_t max_wg_size ; 86size_t wg_mem_limit_bytes = 0 ; 87bool supports_subgroups = false; 88bool supports_subgroup_matrix = false; 89uint32_t sg_mat_m = 0 ; 90uint32_t sg_mat_n = 0 ; 91uint32_t sg_mat_k = 0 ; 92uint32_t min_subgroup_size = 0 ; 93uint32_t max_subgroup_size = 0 ; 94bool supports_dot_product = false; 95 std::string vendor ; 96}; 97 98struct webgpu_pipeline { 99 wgpu::ComputePipeline pipeline ; 100 std::string name ; 101 std::shared_ptr < void > context = nullptr ; 102}; 103 104struct ggml_webgpu_generic_shader_decisions { 105uint32_t wg_size = 0 ; 106bool inplace = false; 107}; 108 109struct ggml_webgpu_binary_shader_decisions { 110uint32_t wg_size = 0 ; 111bool inplace = false; 112bool overlap = false; 113bool src_overlap = false; 114}; 115 116struct ggml_webgpu_glu_shader_decisions { 117uint32_t wg_size = 0 ; 118bool src_overlap = false; 119}; 120 121struct ggml_webgpu_processed_shader { 122 std::string wgsl ; 123 std::string variant ; 124 std::shared_ptr < void > decisions ; 125}; 126 127struct ggml_webgpu_ssm_conv_shader_decisions { 128uint32_t block_size ; 129uint32_t tokens_per_wg ; 130}; 131 132struct ggml_webgpu_ssm_scan_pipeline_key { 133int type ; 134int d_state ; 135bool xbc_overlap ; 136bool a_overlap ; 137bool ids_overlap ; 138 139bool operator== (const ggml_webgpu_ssm_scan_pipeline_key & other )const { 140return type == other .type && d_state == other .d_state && xbc_overlap == other .xbc_overlap && 141a_overlap == other .a_overlap && ids_overlap == other .ids_overlap ; 142 } 143}; 144 145struct ggml_webgpu_ssm_scan_pipeline_key_hash { 146size_t operator()(const ggml_webgpu_ssm_scan_pipeline_key & key )const { 147size_t seed = 0 ; 148ggml_webgpu_hash_combine (seed ,key .type ); 149ggml_webgpu_hash_combine (seed ,key .d_state ); 150ggml_webgpu_hash_combine (seed ,key .xbc_overlap ); 151ggml_webgpu_hash_combine (seed ,key .a_overlap ); 152ggml_webgpu_hash_combine (seed ,key .ids_overlap ); 153return seed ; 154 } 155}; 156 157struct ggml_webgpu_ssm_scan_shader_decisions { 158uint32_t wg_size ; 159uint32_t tokens_per_tile ; 160bool xbc_overlap = false; 161bool a_overlap = false; 162bool ids_overlap = false; 163}; 164 165/** Argsort **/ 166 167struct ggml_webgpu_argsort_shader_lib_context { 168uint32_t max_wg_size ; 169size_t wg_mem_limit_bytes ; 170int32_t order ; 171}; 172 173/** Set Rows **/ 174 175struct ggml_webgpu_set_rows_pipeline_key { 176int dst_type ; 177int vec4 ; 178int i64_idx ; 179int pair_blocks ; 180 181bool operator== (const ggml_webgpu_set_rows_pipeline_key & other )const { 182return dst_type == other .dst_type && vec4 == other .vec4 && i64_idx == other .i64_idx && 183pair_blocks == other .pair_blocks ; 184 } 185}; 186 187struct ggml_webgpu_set_rows_pipeline_key_hash { 188size_t operator()(const ggml_webgpu_set_rows_pipeline_key & key )const { 189size_t seed = 0 ; 190ggml_webgpu_hash_combine (seed ,key .dst_type ); 191ggml_webgpu_hash_combine (seed ,key .vec4 ); 192ggml_webgpu_hash_combine (seed ,key .i64_idx ); 193ggml_webgpu_hash_combine (seed ,key .pair_blocks ); 194return seed ; 195 } 196}; 197 198struct ggml_webgpu_set_rows_shader_decisions { 199bool vec4 ; 200bool i64_idx ; 201bool pair_blocks ; 202uint32_t wg_size ; 203}; 204 205/** Set **/ 206 207struct ggml_webgpu_set_pipeline_key { 208ggml_type type ; 209bool inplace ; 210 211bool operator== (const ggml_webgpu_set_pipeline_key & other )const { 212return type == other .type && inplace == other .inplace ; 213 } 214}; 215 216struct ggml_webgpu_set_pipeline_key_hash { 217size_t operator()(const ggml_webgpu_set_pipeline_key & key )const { 218size_t seed = 0 ; 219ggml_webgpu_hash_combine (seed ,key .type ); 220ggml_webgpu_hash_combine (seed ,key .inplace ); 221return seed ; 222 } 223}; 224 225/** Get Rows **/ 226 227struct ggml_webgpu_get_rows_pipeline_key { 228ggml_type src_type ; 229int vectorized ; 230 231bool operator== (const ggml_webgpu_get_rows_pipeline_key & other )const { 232return src_type == other .src_type && vectorized == other .vectorized ; 233 } 234}; 235 236struct ggml_webgpu_get_rows_pipeline_key_hash { 237size_t operator()(const ggml_webgpu_get_rows_pipeline_key & key )const { 238size_t seed = 0 ; 239ggml_webgpu_hash_combine (seed ,key .src_type ); 240ggml_webgpu_hash_combine (seed ,key .vectorized ); 241return seed ; 242 } 243}; 244 245/** Row Norm **/ 246 247struct ggml_webgpu_row_norm_pipeline_key { 248ggml_op op ; 249ggml_type src_type ; 250ggml_type dst_type ; 251bool inplace ; 252 253bool operator== (const ggml_webgpu_row_norm_pipeline_key & other )const { 254return op == other .op && src_type == other .src_type && dst_type == other .dst_type && inplace == other .inplace ; 255 } 256}; 257 258struct ggml_webgpu_row_norm_pipeline_key_hash { 259size_t operator()(const ggml_webgpu_row_norm_pipeline_key & key )const { 260size_t seed = 0 ; 261ggml_webgpu_hash_combine (seed ,key .op ); 262ggml_webgpu_hash_combine (seed ,key .src_type ); 263ggml_webgpu_hash_combine (seed ,key .dst_type ); 264ggml_webgpu_hash_combine (seed ,key .inplace ); 265return seed ; 266 } 267}; 268 269/** RMS_NORM + MUL **/ 270 271struct ggml_webgpu_rms_norm_mul_pipeline_key { 272bool inplace ;// rn_src == dst 273bool overlap ;// mul_src == dst 274bool src_overlap ;// rn_src binding overlaps mul_src binding 275 276bool operator== (const ggml_webgpu_rms_norm_mul_pipeline_key & other )const { 277return inplace == other .inplace && overlap == other .overlap && src_overlap == other .src_overlap ; 278 } 279}; 280 281struct ggml_webgpu_rms_norm_mul_pipeline_key_hash { 282size_t operator()(const ggml_webgpu_rms_norm_mul_pipeline_key & key )const { 283size_t seed = 0 ; 284ggml_webgpu_hash_combine (seed ,key .inplace ); 285ggml_webgpu_hash_combine (seed ,key .overlap ); 286ggml_webgpu_hash_combine (seed ,key .src_overlap ); 287return seed ; 288 } 289}; 290 291struct ggml_webgpu_rms_norm_mul_shader_decisions { 292uint32_t wg_size = 0 ; 293bool inplace = false; 294bool overlap = false; 295bool src_overlap = false; 296}; 297 298/** Pad **/ 299struct ggml_webgpu_pad_pipeline_key { 300bool circular ; 301 302bool operator== (const ggml_webgpu_pad_pipeline_key & other )const {return circular == other .circular ; } 303}; 304 305struct ggml_webgpu_pad_pipeline_key_hash { 306size_t operator()(const ggml_webgpu_pad_pipeline_key & key )const { 307size_t seed = 0 ; 308ggml_webgpu_hash_combine (seed ,key .circular ); 309return seed ; 310 } 311}; 312 313/** Solve Tri **/ 314struct ggml_webgpu_solve_tri_pipeline_key { 315int type ; 316int n ; 317int k ; 318 319bool operator== (const ggml_webgpu_solve_tri_pipeline_key & other )const { 320return type == other .type && n == other .n && k == other .k ; 321 } 322}; 323 324struct ggml_webgpu_solve_tri_pipeline_key_hash { 325size_t operator()(const ggml_webgpu_solve_tri_pipeline_key & key )const { 326size_t seed = 0 ; 327ggml_webgpu_hash_combine (seed ,key .type ); 328ggml_webgpu_hash_combine (seed ,key .n ); 329ggml_webgpu_hash_combine (seed ,key .k ); 330return seed ; 331 } 332}; 333 334/** SSM Conv **/ 335struct ggml_webgpu_ssm_conv_pipeline_key { 336int type ; 337int vectorized ; 338 339bool operator== (const ggml_webgpu_ssm_conv_pipeline_key & other )const { 340return type == other .type && vectorized == other .vectorized ; 341 } 342}; 343 344/** CONV 2D */ 345struct ggml_webgpu_conv2d_pipeline_key { 346ggml_type weight_type ; 347ggml_type input_type ; 348ggml_type output_type ; 349 350bool operator== (const ggml_webgpu_conv2d_pipeline_key & other )const { 351return weight_type == other .weight_type && input_type == other .input_type && output_type == other .output_type ; 352 } 353}; 354 355struct ggml_webgpu_conv2d_pipeline_key_hash { 356size_t operator()(const ggml_webgpu_conv2d_pipeline_key & key )const { 357size_t seed = 0 ; 358ggml_webgpu_hash_combine (seed ,key .weight_type ); 359ggml_webgpu_hash_combine (seed ,key .input_type ); 360ggml_webgpu_hash_combine (seed ,key .output_type ); 361return seed ; 362 } 363}; 364 365// Same type fields as conv2d plus the input layout (WHCN vs CWHN). 366struct ggml_webgpu_conv2d_dw_pipeline_key { 367ggml_type weight_type ; 368ggml_type input_type ; 369ggml_type output_type ; 370bool whcn ; 371 372bool operator== (const ggml_webgpu_conv2d_dw_pipeline_key & other )const { 373return weight_type == other .weight_type && input_type == other .input_type && output_type == other .output_type && 374whcn == other .whcn ; 375 } 376}; 377 378struct ggml_webgpu_conv2d_dw_pipeline_key_hash { 379size_t operator()(const ggml_webgpu_conv2d_dw_pipeline_key & key )const { 380size_t seed = 0 ; 381ggml_webgpu_hash_combine (seed ,key .weight_type ); 382ggml_webgpu_hash_combine (seed ,key .input_type ); 383ggml_webgpu_hash_combine (seed ,key .output_type ); 384ggml_webgpu_hash_combine (seed ,key .whcn ); 385return seed ; 386 } 387}; 388 389/** Im2Col **/ 390struct ggml_webgpu_im2col_pipeline_key { 391ggml_type input_type ; 392ggml_type output_type ; 393 394bool operator== (const ggml_webgpu_im2col_pipeline_key & other )const { 395return input_type == other .input_type && output_type == other .output_type ; 396 } 397}; 398 399struct ggml_webgpu_im2col_pipeline_key_hash { 400size_t operator()(const ggml_webgpu_im2col_pipeline_key & key )const { 401size_t seed = 0 ; 402ggml_webgpu_hash_combine (seed ,key .input_type ); 403ggml_webgpu_hash_combine (seed ,key .output_type ); 404return seed ; 405 } 406}; 407 408/** Gated Delta Net **/ 409struct ggml_webgpu_gated_delta_net_pipeline_key { 410int type ; 411int s_v ; 412int kda ; 413 414bool operator== (const ggml_webgpu_gated_delta_net_pipeline_key & other )const { 415return type == other .type && s_v == other .s_v && kda == other .kda ; 416 } 417}; 418 419struct ggml_webgpu_gated_delta_net_pipeline_key_hash { 420size_t operator()(const ggml_webgpu_gated_delta_net_pipeline_key & key )const { 421size_t seed = 0 ; 422ggml_webgpu_hash_combine (seed ,key .type ); 423ggml_webgpu_hash_combine (seed ,key .s_v ); 424ggml_webgpu_hash_combine (seed ,key .kda ); 425return seed ; 426 } 427}; 428 429struct ggml_webgpu_ssm_conv_pipeline_key_hash { 430size_t operator()(const ggml_webgpu_ssm_conv_pipeline_key & key )const { 431size_t seed = 0 ; 432ggml_webgpu_hash_combine (seed ,key .type ); 433ggml_webgpu_hash_combine (seed ,key .vectorized ); 434return seed ; 435 } 436}; 437 438/** Scale **/ 439 440struct ggml_webgpu_scale_pipeline_key { 441int inplace ; 442 443bool operator== (const ggml_webgpu_scale_pipeline_key & other )const {return inplace == other .inplace ; } 444}; 445 446struct ggml_webgpu_scale_pipeline_key_hash { 447size_t operator()(const ggml_webgpu_scale_pipeline_key & key )const { 448size_t seed = 0 ; 449ggml_webgpu_hash_combine (seed ,key .inplace ); 450return seed ; 451 } 452}; 453 454/** Upscale **/ 455 456struct ggml_webgpu_upscale_pipeline_key { 457ggml_type input_type ; 458ggml_type output_type ; 459uint32_t base_mode ; 460bool antialias ; 461 462bool operator== (const ggml_webgpu_upscale_pipeline_key & other )const { 463return input_type == other .input_type && output_type == other .output_type && base_mode == other .base_mode && 464antialias == other .antialias ; 465 } 466}; 467 468struct ggml_webgpu_upscale_pipeline_key_hash { 469size_t operator()(const ggml_webgpu_upscale_pipeline_key & key )const { 470size_t seed = 0 ; 471ggml_webgpu_hash_combine (seed ,key .input_type ); 472ggml_webgpu_hash_combine (seed ,key .output_type ); 473ggml_webgpu_hash_combine (seed ,key .base_mode ); 474ggml_webgpu_hash_combine (seed ,key .antialias ); 475return seed ; 476 } 477}; 478 479/** Concat **/ 480 481struct ggml_webgpu_concat_pipeline_key { 482int type ; 483bool src_overlap ; 484 485bool operator== (const ggml_webgpu_concat_pipeline_key & other )const { 486return type == other .type && src_overlap == other .src_overlap ; 487 } 488}; 489 490struct ggml_webgpu_concat_pipeline_key_hash { 491size_t operator()(const ggml_webgpu_concat_pipeline_key & key )const { 492size_t seed = 0 ; 493ggml_webgpu_hash_combine (seed ,key .type ); 494ggml_webgpu_hash_combine (seed ,key .src_overlap ); 495return seed ; 496 } 497}; 498 499/** Repeat **/ 500 501struct ggml_webgpu_repeat_pipeline_key { 502int type ; 503 504bool operator== (const ggml_webgpu_repeat_pipeline_key & other )const {return type == other .type ; } 505}; 506 507struct ggml_webgpu_repeat_pipeline_key_hash { 508size_t operator()(const ggml_webgpu_repeat_pipeline_key & key )const { 509size_t seed = 0 ; 510ggml_webgpu_hash_combine (seed ,key .type ); 511return seed ; 512 } 513}; 514 515/** Binary **/ 516 517struct ggml_webgpu_binary_pipeline_key { 518int type ; 519int op ; 520bool inplace ; 521bool overlap ; 522bool src_overlap ; 523 524bool operator== (const ggml_webgpu_binary_pipeline_key & other )const { 525return type == other .type && op == other .op && inplace == other .inplace && overlap == other .overlap && 526src_overlap == other .src_overlap ; 527 } 528}; 529 530struct ggml_webgpu_binary_pipeline_key_hash { 531size_t operator()(const ggml_webgpu_binary_pipeline_key & key )const { 532size_t seed = 0 ; 533ggml_webgpu_hash_combine (seed ,key .type ); 534ggml_webgpu_hash_combine (seed ,key .op ); 535ggml_webgpu_hash_combine (seed ,key .inplace ); 536ggml_webgpu_hash_combine (seed ,key .overlap ); 537ggml_webgpu_hash_combine (seed ,key .src_overlap ); 538return seed ; 539 } 540}; 541 542/* Add_Id */ 543 544struct ggml_webgpu_add_id_pipeline_key { 545bool inplace ; 546 547bool operator== (const ggml_webgpu_add_id_pipeline_key & other )const {return inplace == other .inplace ; } 548}; 549 550struct ggml_webgpu_add_id_pipeline_key_hash { 551size_t operator()(const ggml_webgpu_add_id_pipeline_key & key )const { 552size_t seed = 0 ; 553ggml_webgpu_hash_combine (seed ,key .inplace ); 554return seed ; 555 } 556}; 557 558/** Unary **/ 559 560struct ggml_webgpu_unary_pipeline_key { 561int type ; 562int op ; 563bool is_unary ;// many unary operators fall under the GGML_OP_UNARY umbrella 564bool inplace ; 565ggml_tri_type ttype ;// only used for GGML_OP_TRI 566 567bool operator== (const ggml_webgpu_unary_pipeline_key & other )const { 568return type == other .type && op == other .op && is_unary == other .is_unary && inplace == other .inplace && 569ttype == other .ttype ; 570 } 571}; 572 573struct ggml_webgpu_unary_pipeline_key_hash { 574size_t operator()(const ggml_webgpu_unary_pipeline_key & key )const { 575size_t seed = 0 ; 576ggml_webgpu_hash_combine (seed ,key .type ); 577ggml_webgpu_hash_combine (seed ,key .op ); 578ggml_webgpu_hash_combine (seed ,key .is_unary ); 579ggml_webgpu_hash_combine (seed ,key .inplace ); 580ggml_webgpu_hash_combine (seed ,key .ttype ); 581return seed ; 582 } 583}; 584 585/** FlashAttention */ 586 587struct ggml_webgpu_flash_attn_common_pipeline_key { 588ggml_type q_type ; 589ggml_type k_type ; 590ggml_type v_type ; 591ggml_type dst_type ; 592uint32_t head_dim_qk ; 593uint32_t head_dim_v ; 594bool k_direct ; 595bool v_direct ; 596bool kv_overlap ; 597bool has_mask ; 598bool has_sinks ; 599bool uses_logit_softcap ; 600 601bool operator== (const ggml_webgpu_flash_attn_common_pipeline_key & other )const { 602return q_type == other .q_type && k_type == other .k_type && v_type == other .v_type && 603dst_type == other .dst_type && head_dim_qk == other .head_dim_qk && head_dim_v == other .head_dim_v && 604k_direct == other .k_direct && v_direct == other .v_direct && kv_overlap == other .kv_overlap && 605has_mask == other .has_mask && has_sinks == other .has_sinks && 606uses_logit_softcap == other .uses_logit_softcap ; 607 } 608}; 609 610inline void ggml_webgpu_flash_attn_hash_common_pipeline_key (size_t & seed , 611const ggml_webgpu_flash_attn_common_pipeline_key & key ) { 612ggml_webgpu_hash_combine (seed ,key .q_type ); 613ggml_webgpu_hash_combine (seed ,key .k_type ); 614ggml_webgpu_hash_combine (seed ,key .v_type ); 615ggml_webgpu_hash_combine (seed ,key .dst_type ); 616ggml_webgpu_hash_combine (seed ,key .head_dim_qk ); 617ggml_webgpu_hash_combine (seed ,key .head_dim_v ); 618ggml_webgpu_hash_combine (seed ,key .k_direct ); 619ggml_webgpu_hash_combine (seed ,key .v_direct ); 620ggml_webgpu_hash_combine (seed ,key .kv_overlap ); 621ggml_webgpu_hash_combine (seed ,key .has_mask ); 622ggml_webgpu_hash_combine (seed ,key .has_sinks ); 623ggml_webgpu_hash_combine (seed ,key .uses_logit_softcap ); 624} 625 626struct ggml_webgpu_flash_attn_vec_pipeline_key { 627ggml_webgpu_flash_attn_common_pipeline_key common ; 628 629bool operator== (const ggml_webgpu_flash_attn_vec_pipeline_key & other )const {return common == other .common ; } 630}; 631 632struct ggml_webgpu_flash_attn_vec_pipeline_key_hash { 633size_t operator()(const ggml_webgpu_flash_attn_vec_pipeline_key & key )const { 634size_t seed = 0 ; 635ggml_webgpu_flash_attn_hash_common_pipeline_key (seed ,key .common ); 636return seed ; 637 } 638}; 639 640struct ggml_webgpu_flash_attn_pipeline_key { 641ggml_webgpu_flash_attn_common_pipeline_key common ; 642bool use_sg_matrix ; 643 644bool operator== (const ggml_webgpu_flash_attn_pipeline_key & other )const { 645return common == other .common && use_sg_matrix == other .use_sg_matrix ; 646 } 647}; 648 649struct ggml_webgpu_flash_attn_pipeline_key_hash { 650size_t operator()(const ggml_webgpu_flash_attn_pipeline_key & key )const { 651size_t seed = 0 ; 652ggml_webgpu_flash_attn_hash_common_pipeline_key (seed ,key .common ); 653ggml_webgpu_hash_combine (seed ,key .use_sg_matrix ); 654return seed ; 655 } 656}; 657 658struct ggml_webgpu_flash_attn_vec_decisions { 659uint32_t kv_tile = 0 ; 660uint32_t wg_size = 0 ; 661}; 662 663struct ggml_webgpu_flash_attn_decisions { 664bool use_sg_matrix = false; 665uint32_t q_tile = 0 ; 666uint32_t kv_tile = 0 ; 667uint32_t wg_size = 0 ; 668}; 669 670inline constexpr uint32_t GGML_WEBGPU_FLASH_ATTN_TILE_KV_VEC_WIDTH = 4u ; 671inline constexpr uint32_t GGML_WEBGPU_FLASH_ATTN_TILE_Q_TILE = 4u ; 672 673inline size_t ggml_webgpu_flash_attn_tensor_offset (const ggml_tensor * tensor ) { 674constexpr uintptr_t ptr_base_addr = 0x1000u ; 675const ggml_tensor * base = tensor -> view_src != nullptr ?tensor -> view_src :tensor ; 676return reinterpret_cast < uintptr_t > (base -> data )- ptr_base_addr + tensor -> view_offs ; 677} 678 679inline bool ggml_webgpu_flash_attn_float_vec4_aligned (const ggml_tensor * K ,size_t storage_offset_alignment ) { 680const uint32_t offset_elems = 681 (uint32_t ) ((ggml_webgpu_flash_attn_tensor_offset (K )& (storage_offset_alignment - 1 )) / 682ggml_type_size (K -> type )); 683return offset_elems %GGML_WEBGPU_FLASH_ATTN_TILE_KV_VEC_WIDTH == 0u ; 684} 685 686inline bool ggml_webgpu_flash_attn_float_vec4_aligned (const ggml_tensor * K , 687const ggml_tensor * V , 688size_t storage_offset_alignment ) { 689return ggml_webgpu_flash_attn_float_vec4_aligned (K ,storage_offset_alignment )&& 690ggml_webgpu_flash_attn_float_vec4_aligned (V ,storage_offset_alignment ); 691} 692 693inline bool ggml_webgpu_flash_attn_k_direct (const ggml_tensor * Q ,const ggml_tensor * K ,uint32_t kv_direct_align ) { 694return (K -> type == GGML_TYPE_F16 || K -> type == GGML_TYPE_Q8_0 || K -> type == GGML_TYPE_Q4_0 )&& 695 (Q -> ne [0 ] %kv_direct_align == 0 )&& (K -> ne [1 ] %GGML_WEBGPU_KV_SEQ_PAD == 0 ); 696} 697 698inline bool ggml_webgpu_flash_attn_v_direct (const ggml_tensor * Q ,const ggml_tensor * V ,uint32_t kv_direct_align ) { 699return ggml_webgpu_flash_attn_k_direct (Q ,V ,kv_direct_align ); 700} 701 702inline ggml_webgpu_flash_attn_common_pipeline_key ggml_webgpu_flash_attn_make_common_pipeline_key ( 703const ggml_webgpu_shader_lib_context & context , 704uint32_t kv_direct_align , 705bool kv_overlap ) { 706ggml_webgpu_flash_attn_common_pipeline_key key = {}; 707key .q_type = context .src0 -> type ; 708key .k_type = context .src1 -> type ; 709key .v_type = context .src2 -> type ; 710key .dst_type = context .dst -> type ; 711key .head_dim_qk = (uint32_t )context .src0 -> ne [0 ]; 712key .head_dim_v = (uint32_t )context .src2 -> ne [0 ]; 713key .k_direct = ggml_webgpu_flash_attn_k_direct (context .src0 ,context .src1 ,kv_direct_align ); 714key .v_direct = ggml_webgpu_flash_attn_v_direct (context .src0 ,context .src2 ,kv_direct_align ); 715key .kv_overlap = kv_overlap ; 716key .has_mask = context .src3 != nullptr ; 717key .has_sinks = context .src4 != nullptr ; 718key .uses_logit_softcap = ggml_get_op_params_f32 (context .dst ,2 )!= 0.0f ; 719return key ; 720} 721 722inline std::vector < std::string > ggml_webgpu_flash_attn_common_defines ( 723const ggml_webgpu_flash_attn_common_pipeline_key & key , 724 std::string & variant , 725uint32_t q_tile , 726uint32_t kv_tile , 727uint32_t wg_size ) { 728 std::vector < std::string > defines ; 729 730switch (key .k_type ) { 731case GGML_TYPE_F32 : 732defines .push_back ("K_F32" ); 733break ; 734case GGML_TYPE_F16 : 735defines .push_back ("K_F16" ); 736break ; 737case GGML_TYPE_Q4_0 : 738defines .push_back ("K_Q4_0" ); 739break ; 740case GGML_TYPE_Q8_0 : 741defines .push_back ("K_Q8_0" ); 742break ; 743default : 744GGML_ABORT ("Unsupported K type for flash attention shader" ); 745 } 746variant += std::string ("_k" )+ ggml_type_name (key .k_type ); 747 748switch (key .v_type ) { 749case GGML_TYPE_F32 : 750defines .push_back ("V_F32" ); 751break ; 752case GGML_TYPE_F16 : 753defines .push_back ("V_F16" ); 754break ; 755case GGML_TYPE_Q4_0 : 756defines .push_back ("V_Q4_0" ); 757break ; 758case GGML_TYPE_Q8_0 : 759defines .push_back ("V_Q8_0" ); 760break ; 761default : 762GGML_ABORT ("Unsupported V type for flash attention shader" ); 763 } 764variant += std::string ("_v" )+ ggml_type_name (key .v_type ); 765 766switch (key .q_type ) { 767case GGML_TYPE_F32 : 768defines .push_back ("Q_F32" ); 769break ; 770case GGML_TYPE_F16 : 771defines .push_back ("Q_F16" ); 772break ; 773default : 774GGML_ABORT ("Unsupported Q type for flash attention shader" ); 775 } 776variant += std::string ("_q" )+ ggml_type_name (key .q_type ); 777 778switch (key .dst_type ) { 779case GGML_TYPE_F32 : 780defines .push_back ("DST_F32" ); 781break ; 782case GGML_TYPE_F16 : 783defines .push_back ("DST_F16" ); 784break ; 785default : 786GGML_ABORT ("Unsupported dst type for flash attention shader" ); 787 } 788variant += std::string ("_dst" )+ ggml_type_name (key .dst_type ); 789 790if (key .has_mask ) { 791defines .push_back ("MASK" ); 792variant += "_mask" ; 793 } 794if (key .has_sinks ) { 795defines .push_back ("SINKS" ); 796variant += "_sinks" ; 797 } 798if (key .uses_logit_softcap ) { 799defines .push_back ("LOGIT_SOFTCAP" ); 800variant += "_lgsc" ; 801 } 802if (key .k_direct ) { 803defines .push_back ("K_DIRECT" ); 804variant += "_k_direct" ; 805 } 806if (key .v_direct ) { 807defines .push_back ("V_DIRECT" ); 808variant += "_v_direct" ; 809 } 810if (key .kv_overlap ) { 811defines .push_back ("KV_OVERLAP" ); 812variant += "_kv_overlap" ; 813 } 814 815defines .push_back (std::string ("HEAD_DIM_QK=" )+ std::to_string (key .head_dim_qk )); 816variant += std::string ("_hsqk" )+ std::to_string (key .head_dim_qk ); 817 818defines .push_back (std::string ("HEAD_DIM_V=" )+ std::to_string (key .head_dim_v )); 819variant += std::string ("_hsv" )+ std::to_string (key .head_dim_v ); 820 821defines .push_back (std::string ("Q_TILE=" )+ std::to_string (q_tile )); 822defines .push_back (std::string ("KV_TILE=" )+ std::to_string (kv_tile )); 823defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 824 825if (ggml_is_quantized (key .k_type )|| ggml_is_quantized (key .v_type )) { 826defines .push_back ("U32_DEQUANT_HELPERS" ); 827if (ggml_is_quantized (key .k_type )) { 828defines .push_back ("LOADERS_QUANTIZED_K" ); 829 } 830if (ggml_is_quantized (key .v_type )) { 831defines .push_back ("LOADERS_QUANTIZED_V" ); 832 } 833 } 834 835return defines ; 836} 837 838struct ggml_webgpu_flash_attn_vec_reduce_pipeline_key { 839uint32_t head_dim_v ; 840uint32_t wg_size ; 841ggml_type dst_type ; 842}; 843 844struct ggml_webgpu_flash_attn_vec_reduce_pipeline_key_hash { 845size_t operator()(const ggml_webgpu_flash_attn_vec_reduce_pipeline_key & key )const { 846size_t seed = 0 ; 847ggml_webgpu_hash_combine (seed ,key .head_dim_v ); 848ggml_webgpu_hash_combine (seed ,key .wg_size ); 849ggml_webgpu_hash_combine (seed ,key .dst_type ); 850return seed ; 851 } 852}; 853 854inline bool operator== (const ggml_webgpu_flash_attn_vec_reduce_pipeline_key & lhs , 855const ggml_webgpu_flash_attn_vec_reduce_pipeline_key & rhs ) { 856return lhs .head_dim_v == rhs .head_dim_v && lhs .wg_size == rhs .wg_size && lhs .dst_type == rhs .dst_type ; 857} 858 859struct ggml_webgpu_flash_attn_blk_pipeline_key { 860uint32_t kv_tile ; 861 862bool operator== (const ggml_webgpu_flash_attn_blk_pipeline_key & other )const {return kv_tile == other .kv_tile ; } 863}; 864 865struct ggml_webgpu_flash_attn_blk_pipeline_key_hash { 866size_t operator()(const ggml_webgpu_flash_attn_blk_pipeline_key & key )const { 867size_t seed = 0 ; 868ggml_webgpu_hash_combine (seed ,key .kv_tile ); 869return seed ; 870 } 871}; 872 873// Note: this will slightly overestimate memory usage for vec path 874// since row_max and exp_sum shmem are not needed. 875inline size_t ggml_webgpu_flash_attn_wg_mem_bytes (uint32_t q_tile , 876uint32_t kv_tile , 877uint32_t head_dim_qk , 878uint32_t head_dim_v , 879bool has_mask , 880bool kv_direct ) { 881const uint32_t max_head_dim = std::max (head_dim_qk ,head_dim_v ); 882size_t f16_elems = 0 ; 883size_t f32_elems = 0 ; 884 885f32_elems += q_tile * head_dim_qk ;// q_shmem 886if (!kv_direct ) { 887f32_elems += kv_tile * max_head_dim ;// kv_shmem 888 } 889f32_elems += q_tile * head_dim_v ;// o_shmem 890if (has_mask ) { 891f32_elems += q_tile * kv_tile ;// mask_shmem 892 } 893f32_elems += q_tile * kv_tile ;// inter_shmem 894f32_elems += q_tile ;// row_max_shmem 895f32_elems += q_tile ;// exp_sum_shmem 896return f16_elems * GGML_WEBGPU_F16_SIZE_BYTES + f32_elems * GGML_WEBGPU_F32_SIZE_BYTES ; 897} 898 899inline uint32_t ggml_webgpu_flash_attn_max_kv_tile (size_t limit_bytes , 900uint32_t q_tile , 901uint32_t kv_granularity , 902uint32_t head_dim_qk , 903uint32_t head_dim_v , 904bool has_mask , 905bool kv_direct ) { 906const size_t base_q_bytes = 907ggml_webgpu_flash_attn_wg_mem_bytes (q_tile ,0 ,head_dim_qk ,head_dim_v ,has_mask ,kv_direct ); 908if (limit_bytes <=base_q_bytes ) { 909return 0 ; 910 } 911const size_t one_kv_bytes = 912ggml_webgpu_flash_attn_wg_mem_bytes (q_tile ,1 ,head_dim_qk ,head_dim_v ,has_mask ,kv_direct ); 913const size_t bytes_per_kv = one_kv_bytes - base_q_bytes ; 914if (bytes_per_kv == 0 ) { 915return 0 ; 916 } 917const size_t max_kv_tile = (limit_bytes - base_q_bytes ) /bytes_per_kv ; 918return (uint32_t ) ((max_kv_tile /kv_granularity )* kv_granularity ); 919} 920 921inline uint32_t ggml_webgpu_flash_attn_get_vec_kv_tile (size_t wg_mem_limit_bytes , 922uint32_t head_dim_qk , 923uint32_t head_dim_v , 924bool has_mask , 925bool kv_direct ) { 926const uint32_t max_kv_tile = 927ggml_webgpu_flash_attn_max_kv_tile (wg_mem_limit_bytes ,1u ,1u ,head_dim_qk ,head_dim_v ,has_mask ,kv_direct ); 928GGML_ASSERT (max_kv_tile > 0 ); 929 930uint32_t kv_tile = std::min (GGML_WEBGPU_FLASH_ATTN_VEC_MAX_KV_TILE ,max_kv_tile ); 931if (kv_direct ) { 932kv_tile = std::min (kv_tile ,GGML_WEBGPU_KV_SEQ_PAD ); 933while (GGML_WEBGPU_KV_SEQ_PAD %kv_tile != 0 ) { 934kv_tile -= 1u ; 935 } 936 } 937 938return kv_tile ; 939} 940 941inline bool ggml_webgpu_flash_attn_can_use_subgroup_matrix_path (bool supports_subgroup_matrix , 942uint32_t sg_mat_k , 943uint32_t sg_mat_n , 944const ggml_tensor * Q , 945const ggml_tensor * V ) { 946return supports_subgroup_matrix && Q -> ne [0 ] %sg_mat_k == 0 && V -> ne [0 ] %sg_mat_n == 0 ; 947} 948 949/** Matrix Multiplication **/ 950 951struct ggml_webgpu_mul_mat_vec_pipeline_key { 952ggml_type src0_type ; 953ggml_type src1_type ; 954int vectorized ; 955uint32_t num_cols ; 956bool use_mmvq ; 957bool src_overlap ; 958 959bool operator== (const ggml_webgpu_mul_mat_vec_pipeline_key & other )const { 960return src0_type == other .src0_type && src1_type == other .src1_type && vectorized == other .vectorized && 961num_cols == other .num_cols && use_mmvq == other .use_mmvq && src_overlap == other .src_overlap ; 962 } 963}; 964 965struct ggml_webgpu_mul_mat_vec_pipeline_key_hash { 966size_t operator()(const ggml_webgpu_mul_mat_vec_pipeline_key & key )const { 967size_t seed = 0 ; 968ggml_webgpu_hash_combine (seed ,key .src0_type ); 969ggml_webgpu_hash_combine (seed ,key .src1_type ); 970ggml_webgpu_hash_combine (seed ,key .vectorized ); 971ggml_webgpu_hash_combine (seed ,key .num_cols ); 972ggml_webgpu_hash_combine (seed ,key .use_mmvq ); 973ggml_webgpu_hash_combine (seed ,key .src_overlap ); 974return seed ; 975 } 976}; 977 978struct ggml_webgpu_mul_mat_vec_shader_decisions { 979uint32_t wg_size ; 980uint32_t outputs_per_wg ; 981uint32_t vec_size ; 982bool src_overlap = false; 983}; 984 985struct ggml_webgpu_quantize_q8_pipeline_key { 986ggml_type src0_type ; 987 988bool operator== (const ggml_webgpu_quantize_q8_pipeline_key & other )const {return src0_type == other .src0_type ; } 989}; 990 991struct ggml_webgpu_quantize_q8_pipeline_key_hash { 992size_t operator()(const ggml_webgpu_quantize_q8_pipeline_key & key )const { 993size_t seed = 0 ; 994ggml_webgpu_hash_combine (seed ,key .src0_type ); 995return seed ; 996 } 997}; 998 999struct ggml_webgpu_mul_mat_pipeline_key { 1000ggml_type src0_type ; 1001ggml_type src1_type ; 1002int vectorized ; 1003int use_subgroup_matrix ; 1004bool src_overlap ; 1005 1006bool operator== (const ggml_webgpu_mul_mat_pipeline_key & other )const { 1007return src0_type == other .src0_type && src1_type == other .src1_type && vectorized == other .vectorized && 1008use_subgroup_matrix == other .use_subgroup_matrix && src_overlap == other .src_overlap ; 1009 } 1010}; 1011 1012struct ggml_webgpu_mul_mat_pipeline_key_hash { 1013size_t operator()(const ggml_webgpu_mul_mat_pipeline_key & key )const { 1014size_t seed = 0 ; 1015ggml_webgpu_hash_combine (seed ,key .src0_type ); 1016ggml_webgpu_hash_combine (seed ,key .src1_type ); 1017ggml_webgpu_hash_combine (seed ,key .vectorized ); 1018ggml_webgpu_hash_combine (seed ,key .use_subgroup_matrix ); 1019ggml_webgpu_hash_combine (seed ,key .src_overlap ); 1020return seed ; 1021 } 1022}; 1023 1024struct ggml_webgpu_mul_mat_shader_decisions { 1025uint32_t tile_k ; 1026uint32_t wg_size_m ; 1027uint32_t wg_size_n ; 1028uint32_t wg_size ; 1029uint32_t outputs_per_wg ; 1030int use_subgroup_matrix ; 1031 1032uint32_t tile_m ; 1033uint32_t tile_n ; 1034 1035// Subgroup matrix parameters 1036uint32_t subgroup_m ; 1037uint32_t subgroup_n ; 1038uint32_t subgroup_matrix_m ; 1039uint32_t subgroup_matrix_n ; 1040 1041uint32_t mul_mat_wg_size ; 1042bool src_overlap = false; 1043}; 1044 1045/** MUL_MAT_ID **/ 1046 1047struct ggml_webgpu_mul_mat_id_pipeline_key { 1048ggml_type src0_type ; 1049ggml_type src1_type ; 1050uint32_t n_experts ; 1051uint32_t num_cols ; 1052int vectorized ; 1053 1054bool operator== (const ggml_webgpu_mul_mat_id_pipeline_key & other )const { 1055return src0_type == other .src0_type && src1_type == other .src1_type && n_experts == other .n_experts && 1056num_cols == other .num_cols && vectorized == other .vectorized ; 1057 } 1058}; 1059 1060struct ggml_webgpu_mul_mat_id_pipeline_key_hash { 1061size_t operator()(const ggml_webgpu_mul_mat_id_pipeline_key & key )const { 1062size_t seed = 0 ; 1063ggml_webgpu_hash_combine (seed ,key .src0_type ); 1064ggml_webgpu_hash_combine (seed ,key .src1_type ); 1065ggml_webgpu_hash_combine (seed ,key .n_experts ); 1066ggml_webgpu_hash_combine (seed ,key .num_cols ); 1067ggml_webgpu_hash_combine (seed ,key .vectorized ); 1068return seed ; 1069 } 1070}; 1071 1072/** Cpy **/ 1073 1074struct ggml_webgpu_cpy_pipeline_key { 1075ggml_type src_type ; 1076ggml_type dst_type ; 1077 1078bool operator== (const ggml_webgpu_cpy_pipeline_key & other )const { 1079return src_type == other .src_type && dst_type == other .dst_type ; 1080 } 1081}; 1082 1083struct ggml_webgpu_cpy_pipeline_key_hash { 1084size_t operator()(const ggml_webgpu_cpy_pipeline_key & key )const { 1085size_t seed = 0 ; 1086ggml_webgpu_hash_combine (seed ,key .src_type ); 1087ggml_webgpu_hash_combine (seed ,key .dst_type ); 1088return seed ; 1089 } 1090}; 1091 1092/** Glu **/ 1093 1094struct ggml_webgpu_glu_pipeline_key { 1095ggml_glu_op glu_op ; 1096ggml_type type ; 1097bool split ; 1098bool src_overlap ; 1099 1100bool operator== (const ggml_webgpu_glu_pipeline_key & other )const { 1101return glu_op == other .glu_op && type == other .type && split == other .split && src_overlap == other .src_overlap ; 1102 } 1103}; 1104 1105struct ggml_webgpu_glu_pipeline_key_hash { 1106size_t operator()(const ggml_webgpu_glu_pipeline_key & key )const { 1107size_t seed = 0 ; 1108ggml_webgpu_hash_combine (seed ,key .glu_op ); 1109ggml_webgpu_hash_combine (seed ,key .type ); 1110ggml_webgpu_hash_combine (seed ,key .split ); 1111ggml_webgpu_hash_combine (seed ,key .src_overlap ); 1112return seed ; 1113 } 1114}; 1115 1116/** Rope **/ 1117 1118struct ggml_webgpu_rope_pipeline_key { 1119ggml_type type ; 1120bool inplace ; 1121bool has_ff ; 1122 1123bool operator== (const ggml_webgpu_rope_pipeline_key & other )const { 1124return type == other .type && inplace == other .inplace && has_ff == other .has_ff ; 1125 } 1126}; 1127 1128struct ggml_webgpu_rope_pipeline_key_hash { 1129size_t operator()(const ggml_webgpu_rope_pipeline_key & key )const { 1130size_t seed = 0 ; 1131ggml_webgpu_hash_combine (seed ,key .type ); 1132ggml_webgpu_hash_combine (seed ,key .inplace ); 1133ggml_webgpu_hash_combine (seed ,key .has_ff ); 1134return seed ; 1135 } 1136}; 1137 1138/** SoftMax **/ 1139 1140struct ggml_webgpu_soft_max_pipeline_key { 1141ggml_type mask_type ; 1142bool has_mask ; 1143bool has_sink ; 1144bool inplace ; 1145 1146bool operator== (const ggml_webgpu_soft_max_pipeline_key & other )const { 1147return mask_type == other .mask_type && has_mask == other .has_mask && has_sink == other .has_sink && 1148inplace == other .inplace ; 1149 } 1150}; 1151 1152struct ggml_webgpu_soft_max_pipeline_key_hash { 1153size_t operator()(const ggml_webgpu_soft_max_pipeline_key & key )const { 1154size_t seed = 0 ; 1155ggml_webgpu_hash_combine (seed ,key .mask_type ); 1156ggml_webgpu_hash_combine (seed ,key .has_mask ); 1157ggml_webgpu_hash_combine (seed ,key .has_sink ); 1158ggml_webgpu_hash_combine (seed ,key .inplace ); 1159return seed ; 1160 } 1161}; 1162 1163/** MMVQ **/ 1164 1165inline bool ggml_webgpu_can_use_mmvq (const ggml_tensor * src0 , 1166const ggml_tensor * src1 , 1167bool supports_dot_product , 1168const std::string & vendor ) { 1169if (src1 -> ne [1 ] <=4 ) { 1170bool supports_dp4a = vendor == "amd" || vendor == "intel" || vendor == "nvidia" ; 1171if (supports_dp4a && supports_dot_product ) { 1172switch (src1 -> type ) { 1173case GGML_TYPE_F32 : 1174switch (src0 -> type ) { 1175case GGML_TYPE_Q4_0 : 1176case GGML_TYPE_Q4_1 : 1177case GGML_TYPE_Q8_0 : 1178case GGML_TYPE_Q2_K : 1179case GGML_TYPE_Q4_K : 1180return src0 -> ne [0 ] %4 == 0 ; 1181default : 1182break ; 1183 } 1184break ; 1185default : 1186break ; 1187 } 1188 } 1189 } 1190return false; 1191} 1192 1193class ggml_webgpu_shader_lib { 1194 wgpu::Device device ; 1195 pre_wgsl::Preprocessor preprocessor ; 1196 1197 std::unordered_map < int ,webgpu_pipeline > sum_rows_pipelines ;// key is fixed, no variants yet 1198 std::unordered_map < int ,webgpu_pipeline > argmax_pipelines ;// key is vec4 1199 std::unordered_map < int ,webgpu_pipeline > argsort_pipelines ;// key is order 1200 std::unordered_map < int ,webgpu_pipeline > argsort_merge_pipelines ;// key is order 1201 std::unordered_map < int ,webgpu_pipeline > cumsum_pipelines ;// key is fixed, no variants yet 1202 std::unordered_map < ggml_webgpu_row_norm_pipeline_key ,webgpu_pipeline ,ggml_webgpu_row_norm_pipeline_key_hash > 1203row_norm_pipelines ;// op/inplace 1204 1205 std::unordered_map < ggml_webgpu_get_rows_pipeline_key ,webgpu_pipeline ,ggml_webgpu_get_rows_pipeline_key_hash > 1206get_rows_pipelines ;// src_type, vectorized 1207 std::unordered_map < ggml_webgpu_unary_pipeline_key ,webgpu_pipeline ,ggml_webgpu_unary_pipeline_key_hash > 1208unary_pipelines ;// type/op/inplace 1209 std::unordered_map < ggml_webgpu_scale_pipeline_key ,webgpu_pipeline ,ggml_webgpu_scale_pipeline_key_hash > 1210scale_pipelines ;// inplace 1211 std::unordered_map < ggml_webgpu_solve_tri_pipeline_key ,webgpu_pipeline ,ggml_webgpu_solve_tri_pipeline_key_hash > 1212solve_tri_pipelines ;// type 1213 std::unordered_map < ggml_webgpu_ssm_conv_pipeline_key ,webgpu_pipeline ,ggml_webgpu_ssm_conv_pipeline_key_hash > 1214ssm_conv_pipelines ;// type/vectorized 1215 std::unordered_map < ggml_webgpu_ssm_scan_pipeline_key ,webgpu_pipeline ,ggml_webgpu_ssm_scan_pipeline_key_hash > 1216ssm_scan_pipelines ;// type/d_state 1217 std::unordered_map < ggml_webgpu_gated_delta_net_pipeline_key , 1218webgpu_pipeline , 1219ggml_webgpu_gated_delta_net_pipeline_key_hash > 1220gated_delta_net_pipelines ;// type/S_v/kda 1221 std::unordered_map < ggml_webgpu_pad_pipeline_key ,webgpu_pipeline ,ggml_webgpu_pad_pipeline_key_hash > 1222pad_pipelines ;// circular/non-circular 1223 std::unordered_map < ggml_webgpu_binary_pipeline_key ,webgpu_pipeline ,ggml_webgpu_binary_pipeline_key_hash > 1224binary_pipelines ;// type/op/inplace/overlap/src_overlap 1225 std::unordered_map < ggml_webgpu_add_id_pipeline_key ,webgpu_pipeline ,ggml_webgpu_add_id_pipeline_key_hash > 1226add_id_pipelines ;// inplace 1227 std::unordered_map < ggml_webgpu_concat_pipeline_key ,webgpu_pipeline ,ggml_webgpu_concat_pipeline_key_hash > 1228concat_pipelines ;// type 1229 std::unordered_map < ggml_webgpu_repeat_pipeline_key ,webgpu_pipeline ,ggml_webgpu_repeat_pipeline_key_hash > 1230repeat_pipelines ;// type 1231 std::unordered_map < ggml_webgpu_flash_attn_vec_pipeline_key , 1232webgpu_pipeline , 1233ggml_webgpu_flash_attn_vec_pipeline_key_hash > 1234flash_attn_vec_pipelines ; 1235 std::unordered_map < ggml_webgpu_flash_attn_pipeline_key ,webgpu_pipeline ,ggml_webgpu_flash_attn_pipeline_key_hash > 1236flash_attn_pipelines ; 1237 std::unordered_map < ggml_webgpu_flash_attn_vec_reduce_pipeline_key , 1238webgpu_pipeline , 1239ggml_webgpu_flash_attn_vec_reduce_pipeline_key_hash > 1240flash_attn_vec_reduce_pipelines ; 1241 std::unordered_map < ggml_webgpu_flash_attn_blk_pipeline_key , 1242webgpu_pipeline , 1243ggml_webgpu_flash_attn_blk_pipeline_key_hash > 1244flash_attn_blk_pipelines ; 1245 std::unordered_map < ggml_webgpu_mul_mat_vec_pipeline_key ,webgpu_pipeline ,ggml_webgpu_mul_mat_vec_pipeline_key_hash > 1246mul_mat_vec_pipelines ;// fast mat-vec (n==1) 1247 std::unordered_map < ggml_webgpu_mul_mat_pipeline_key ,webgpu_pipeline ,ggml_webgpu_mul_mat_pipeline_key_hash > 1248mul_mat_fast_pipelines ;// fast mat-mat (reg-tile or subgroup) 1249 std::unordered_map < ggml_webgpu_quantize_q8_pipeline_key ,webgpu_pipeline ,ggml_webgpu_quantize_q8_pipeline_key_hash > 1250quantize_q8_pipelines ; 1251 std::unordered_map < int ,webgpu_pipeline > mul_mat_id_gather_pipelines ;// key is fixed 1252 std::unordered_map < ggml_webgpu_mul_mat_id_pipeline_key ,webgpu_pipeline ,ggml_webgpu_mul_mat_id_pipeline_key_hash > 1253mul_mat_id_pipelines ;// src0_type/src1_type 1254 std::unordered_map < ggml_webgpu_mul_mat_id_pipeline_key ,webgpu_pipeline ,ggml_webgpu_mul_mat_id_pipeline_key_hash > 1255mul_mat_id_vec_pipelines ;// src0_type/src1_type 1256 1257 std::unordered_map < ggml_webgpu_set_rows_pipeline_key ,webgpu_pipeline ,ggml_webgpu_set_rows_pipeline_key_hash > 1258set_rows_pipelines ; 1259 std::unordered_map < ggml_webgpu_set_pipeline_key ,webgpu_pipeline ,ggml_webgpu_set_pipeline_key_hash > set_pipelines ; 1260 std::unordered_map < ggml_webgpu_cpy_pipeline_key ,webgpu_pipeline ,ggml_webgpu_cpy_pipeline_key_hash > cpy_pipelines ; 1261 std::unordered_map < ggml_webgpu_glu_pipeline_key ,webgpu_pipeline ,ggml_webgpu_glu_pipeline_key_hash > glu_pipelines ; 1262 std::unordered_map < ggml_webgpu_rope_pipeline_key ,webgpu_pipeline ,ggml_webgpu_rope_pipeline_key_hash > 1263rope_pipelines ; 1264 std::unordered_map < ggml_webgpu_soft_max_pipeline_key ,webgpu_pipeline ,ggml_webgpu_soft_max_pipeline_key_hash > 1265soft_max_pipelines ; 1266 std::unordered_map < ggml_webgpu_conv2d_pipeline_key ,webgpu_pipeline ,ggml_webgpu_conv2d_pipeline_key_hash > 1267conv2d_pipelines ; 1268 std::unordered_map < ggml_webgpu_conv2d_dw_pipeline_key ,webgpu_pipeline ,ggml_webgpu_conv2d_dw_pipeline_key_hash > 1269conv2d_dw_pipelines ; 1270 std::unordered_map < ggml_webgpu_im2col_pipeline_key ,webgpu_pipeline ,ggml_webgpu_im2col_pipeline_key_hash > 1271im2col_pipelines ; 1272 1273 std::unordered_map < ggml_webgpu_rms_norm_mul_pipeline_key , 1274webgpu_pipeline , 1275ggml_webgpu_rms_norm_mul_pipeline_key_hash > 1276rms_norm_mul_pipelines ; 1277 std::unordered_map < ggml_webgpu_upscale_pipeline_key ,webgpu_pipeline ,ggml_webgpu_upscale_pipeline_key_hash > 1278upscale_pipelines ; 1279 1280public : 1281ggml_webgpu_shader_lib (wgpu::Device device ) {this -> device = device ; } 1282 1283webgpu_pipeline get_sum_rows_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1284auto it = sum_rows_pipelines .find (1 ); 1285if (it != sum_rows_pipelines .end ()) { 1286return it -> second ; 1287 } 1288 std::vector < std::string > defines ; 1289defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 1290 1291auto processed = preprocessor .preprocess (wgsl_sum_rows ,defines ); 1292sum_rows_pipelines [1 ]= ggml_webgpu_create_pipeline (device ,processed ,"sum_rows" ); 1293return sum_rows_pipelines [1 ]; 1294 } 1295 1296webgpu_pipeline get_row_norm_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1297ggml_webgpu_row_norm_pipeline_key key = {}; 1298key .op = context .dst -> op ; 1299key .src_type = context .src0 -> type ; 1300key .dst_type = context .dst -> type ; 1301key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 1302 1303auto it = row_norm_pipelines .find (key ); 1304if (it != row_norm_pipelines .end ()) { 1305return it -> second ; 1306 } 1307 std::vector < std::string > defines ; 1308 std::string variant ; 1309 1310switch (key .op ) { 1311case GGML_OP_RMS_NORM : 1312defines .push_back ("RMS_NORM" ); 1313variant = "rms_norm" ; 1314break ; 1315case GGML_OP_NORM : 1316defines .push_back ("NORM" ); 1317variant = "norm" ; 1318break ; 1319case GGML_OP_L2_NORM : 1320defines .push_back ("L2_NORM" ); 1321variant = "l2_norm" ; 1322break ; 1323default : 1324GGML_ABORT ("Unsupported op for row_norm shader" ); 1325 } 1326 1327if (key .inplace ) { 1328defines .push_back ("INPLACE" ); 1329variant += "_inplace" ; 1330 } 1331 1332if (key .src_type == GGML_TYPE_F32 ) { 1333defines .push_back ("SRC_F32" ); 1334variant += "_src_f32" ; 1335 }else if (key .src_type == GGML_TYPE_F16 ) { 1336defines .push_back ("SRC_F16" ); 1337variant += "_src_f16" ; 1338 } 1339 1340if (key .dst_type == GGML_TYPE_F32 ) { 1341defines .push_back ("DST_F32" ); 1342variant += "_dst_f32" ; 1343 }else if (key .dst_type == GGML_TYPE_F16 ) { 1344defines .push_back ("DST_F16" ); 1345variant += "_dst_f16" ; 1346 } 1347 1348const uint32_t row_norm_wg_size = 128u ; 1349uint32_t wg_size = std::min (context .max_wg_size ,row_norm_wg_size ); 1350defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 1351auto processed = preprocessor .preprocess (wgsl_row_norm ,defines ); 1352auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1353decisions -> wg_size = wg_size ; 1354decisions -> inplace = key .inplace ; 1355row_norm_pipelines [key ]= ggml_webgpu_create_pipeline (device ,processed ,variant ); 1356row_norm_pipelines [key ].context = decisions ; 1357return row_norm_pipelines [key ]; 1358 } 1359 1360webgpu_pipeline get_argmax_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1361bool vec4 = context .src0 -> ne [0 ] %4 == 0 ; 1362 1363auto it = argmax_pipelines .find (vec4 ); 1364if (it != argmax_pipelines .end ()) { 1365return it -> second ; 1366 } 1367 std::string variant = "argmax" ; 1368 std::vector < std::string > defines ; 1369defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 1370if (vec4 ) { 1371defines .push_back ("VEC4" ); 1372variant += "_vec4" ; 1373 } 1374 1375auto processed = preprocessor .preprocess (wgsl_argmax ,defines ); 1376argmax_pipelines [vec4 ]= ggml_webgpu_create_pipeline (device ,processed ,variant ); 1377return argmax_pipelines .at (vec4 ); 1378 } 1379 1380webgpu_pipeline get_set_rows_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1381const bool quantized = ggml_is_quantized (context .dst -> type ); 1382ggml_webgpu_set_rows_pipeline_key key = {}; 1383key .dst_type = context .dst -> type ; 1384key .vec4 = 1385 (context .dst -> type == GGML_TYPE_F32 || context .dst -> type == GGML_TYPE_F16 )&& context .src0 -> ne [0 ] %4 == 0 ; 1386key .i64_idx = context .src1 -> type == GGML_TYPE_I64 ; 1387key .pair_blocks = quantized && ((context .src0 -> ne [0 ] /ggml_blck_size (context .dst -> type )) %2 == 0 ); 1388 1389auto it = set_rows_pipelines .find (key ); 1390if (it != set_rows_pipelines .end ()) { 1391return it -> second ; 1392 } 1393 1394 std::vector < std::string > defines ; 1395 std::string variant = "set_rows" ; 1396 1397switch (context .dst -> type ) { 1398case GGML_TYPE_F32 : 1399defines .push_back ("DST_F32" ); 1400variant += "_dstf32" ; 1401break ; 1402case GGML_TYPE_F16 : 1403defines .push_back ("DST_F16" ); 1404variant += "_dstf16" ; 1405break ; 1406case GGML_TYPE_Q8_0 : 1407defines .push_back ("DST_Q8_0" ); 1408variant += "_dstq8_0" ; 1409break ; 1410case GGML_TYPE_Q4_0 : 1411defines .push_back ("DST_Q4_0" ); 1412variant += "_dstq4_0" ; 1413break ; 1414default : 1415GGML_ABORT ("Unsupported dst type for set_rows shader" ); 1416 } 1417 1418if (key .vec4 ) { 1419defines .push_back ("VEC4" ); 1420variant += "_vec4" ; 1421 } 1422if (key .i64_idx ) { 1423defines .push_back ("I64_IDX" ); 1424variant += "_i64idx" ; 1425 } 1426if (key .pair_blocks ) { 1427defines .push_back ("PAIR_BLOCKS" ); 1428variant += "_pair_blocks" ; 1429 } 1430 1431defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 1432 1433const auto & shader_source = quantized ?wgsl_set_rows_quant :wgsl_set_rows ; 1434auto processed = preprocessor .preprocess (shader_source ,defines ); 1435auto decisions = std::make_shared < ggml_webgpu_set_rows_shader_decisions > (); 1436decisions -> vec4 = key .vec4 ; 1437decisions -> i64_idx = key .i64_idx ; 1438decisions -> pair_blocks = key .pair_blocks ; 1439decisions -> wg_size = context .max_wg_size ; 1440set_rows_pipelines [key ]= ggml_webgpu_create_pipeline (device ,processed ,variant ); 1441set_rows_pipelines [key ].context = decisions ; 1442return set_rows_pipelines [key ]; 1443 } 1444 1445webgpu_pipeline get_set_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1446ggml_webgpu_set_pipeline_key key = {}; 1447key .type = context .dst -> type ; 1448key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 1449 1450auto it = set_pipelines .find (key ); 1451if (it != set_pipelines .end ()) { 1452return it -> second ; 1453 } 1454 1455 std::vector < std::string > defines ; 1456 std::string variant = "set" ; 1457 1458switch (key .type ) { 1459case GGML_TYPE_F32 : 1460defines .push_back ("TYPE_F32" ); 1461variant += "_f32" ; 1462break ; 1463case GGML_TYPE_I32 : 1464defines .push_back ("TYPE_I32" ); 1465variant += "_i32" ; 1466break ; 1467default : 1468GGML_ABORT ("Unsupported type for set shader" ); 1469 } 1470 1471if (key .inplace ) { 1472defines .push_back ("INPLACE" ); 1473variant += "_inplace" ; 1474 } 1475 1476defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 1477 1478auto processed = preprocessor .preprocess (wgsl_set ,defines ); 1479auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1480decisions -> wg_size = context .max_wg_size ; 1481decisions -> inplace = key .inplace ; 1482webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1483pipeline .context = decisions ; 1484set_pipelines [key ]= pipeline ; 1485return set_pipelines [key ]; 1486 } 1487 1488webgpu_pipeline get_cumsum_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1489auto it = cumsum_pipelines .find (1 ); 1490if (it != cumsum_pipelines .end ()) { 1491return it -> second ; 1492 } 1493 1494 std::vector < std::string > defines ; 1495defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 1496 1497auto processed = preprocessor .preprocess (wgsl_cumsum ,defines ); 1498cumsum_pipelines [1 ]= ggml_webgpu_create_pipeline (device ,processed ,"cumsum" ); 1499return cumsum_pipelines [1 ]; 1500 } 1501 1502webgpu_pipeline get_argsort_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1503bool is_top_k = context .dst -> op == GGML_OP_TOP_K ; 1504// ascending order is 0, descending order is 1 1505const int32_t order = 1506is_top_k ? (int32_t )GGML_SORT_ORDER_DESC : (int32_t )ggml_get_op_params_i32 (context .dst ,0 ); 1507 1508auto it = argsort_pipelines .find (order ); 1509if (it != argsort_pipelines .end ()) { 1510return it -> second ; 1511 } 1512 1513 std::vector < std::string > defines ; 1514 std::string variant = "argsort" ; 1515defines .push_back (std::string ("ORDER=" )+ std::to_string (order )); 1516variant += std::string ("_order" )+ std::to_string (order ); 1517uint32_t wg_size = 1 ; 1518while (wg_size * 2 <=context .max_wg_size && 1519wg_size * GGML_WEBGPU_I32_SIZE_BYTES <=context .wg_mem_limit_bytes /2 ) { 1520wg_size *=2 ; 1521 } 1522defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 1523auto processed = preprocessor .preprocess (wgsl_argsort ,defines ); 1524auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1525decisions -> wg_size = wg_size ; 1526argsort_pipelines [order ]= ggml_webgpu_create_pipeline (device ,processed ,variant ); 1527argsort_pipelines [order ].context = decisions ; 1528return argsort_pipelines [order ]; 1529 } 1530 1531webgpu_pipeline get_argsort_merge_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1532bool is_top_k = context .dst -> op == GGML_OP_TOP_K ; 1533// ascending order is 0, descending order is 1 1534const int32_t order = 1535is_top_k ? (int32_t )GGML_SORT_ORDER_DESC : (int32_t )ggml_get_op_params_i32 (context .dst ,0 ); 1536 1537auto it = argsort_merge_pipelines .find (order ); 1538if (it != argsort_merge_pipelines .end ()) { 1539return it -> second ; 1540 } 1541 1542 std::vector < std::string > defines ; 1543 std::string variant = "argsort_merge" ; 1544defines .push_back (std::string ("ORDER=" )+ std::to_string (order )); 1545variant += std::string ("_order" )+ std::to_string (order ); 1546uint32_t wg_size = std::min (GGML_WEBGPU_ARGSORT_MERGE_MAX_WG_SIZE ,context .max_wg_size ); 1547defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 1548 1549auto processed = preprocessor .preprocess (wgsl_argsort_merge ,defines ); 1550argsort_merge_pipelines [order ]= ggml_webgpu_create_pipeline (device ,processed ,variant ); 1551return argsort_merge_pipelines [order ]; 1552 } 1553 1554webgpu_pipeline get_get_rows_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1555const bool vectorized = context .src0 -> type == GGML_TYPE_F32 && context .dst -> ne [0 ] %4 == 0 ; 1556ggml_webgpu_get_rows_pipeline_key key = {}; 1557key .src_type = context .src0 -> type ; 1558key .vectorized = (int )vectorized ; 1559 1560auto it = get_rows_pipelines .find (key ); 1561if (it != get_rows_pipelines .end ()) { 1562return it -> second ; 1563 } 1564 1565 std::vector < std::string > defines ; 1566 std::string variant = "get_rows" ; 1567 1568const struct ggml_type_traits * type_traits = ggml_get_type_traits (key .src_type ); 1569const char * type_str = type_traits -> type_name ; 1570 1571switch (key .src_type ) { 1572case GGML_TYPE_F32 : 1573defines .push_back ("FLOAT_PARALLEL" ); 1574if (key .vectorized ) { 1575defines .push_back ("F32_VEC" ); 1576defines .push_back ("SRC_TYPE=vec4<f32>" ); 1577defines .push_back ("DST_TYPE=vec4<f32>" ); 1578defines .push_back ("BLOCK_SIZE=4u" ); 1579 }else { 1580defines .push_back ("F32" ); 1581defines .push_back ("SRC_TYPE=f32" ); 1582defines .push_back ("DST_TYPE=f32" ); 1583defines .push_back ("BLOCK_SIZE=1u" ); 1584 } 1585variant += "_f32" ; 1586break ; 1587case GGML_TYPE_F16 : 1588defines .push_back ("FLOAT_PARALLEL" ); 1589defines .push_back ("F16" ); 1590defines .push_back ("SRC_TYPE=f16" ); 1591defines .push_back ("DST_TYPE=f32" ); 1592defines .push_back ("BLOCK_SIZE=1u" ); 1593variant += "_f16" ; 1594break ; 1595case GGML_TYPE_I32 : 1596defines .push_back ("FLOAT_PARALLEL" ); 1597defines .push_back ("I32" ); 1598defines .push_back ("SRC_TYPE=i32" ); 1599defines .push_back ("DST_TYPE=i32" ); 1600defines .push_back ("BLOCK_SIZE=1u" ); 1601variant += "_i32" ; 1602break ; 1603default : 1604 { 1605 std::string type_upper = type_str ; 1606 std::transform (type_upper .begin (),type_upper .end (),type_upper .begin (), ::toupper ); 1607 1608switch (key .src_type ) { 1609case GGML_TYPE_Q1_0 : 1610case GGML_TYPE_Q4_0 : 1611case GGML_TYPE_Q5_0 : 1612case GGML_TYPE_Q8_0 : 1613case GGML_TYPE_Q3_K : 1614case GGML_TYPE_Q6_K : 1615case GGML_TYPE_IQ2_XXS : 1616case GGML_TYPE_IQ2_XS : 1617case GGML_TYPE_IQ2_S : 1618case GGML_TYPE_IQ3_XXS : 1619case GGML_TYPE_IQ3_S : 1620case GGML_TYPE_IQ1_S : 1621case GGML_TYPE_IQ4_NL : 1622case GGML_TYPE_MXFP4 : 1623case GGML_TYPE_NVFP4 : 1624 { 1625// Quantized types using u32 buffers for portability. 1626defines .push_back ("SRC_TYPE=u32" ); 1627defines .push_back ("U32_DEQUANT_HELPERS" ); 1628break ; 1629 } 1630default : 1631 { 1632defines .push_back (std::string ("SRC_TYPE=" )+ type_str ); 1633 } 1634 } 1635 1636defines .push_back ("BYTE_HELPERS" ); 1637defines .push_back (type_upper + "_T" ); 1638defines .push_back (type_upper ); 1639defines .push_back (type_upper + "_SCALE_MIN" ); 1640defines .push_back (type_upper + "_TABLES" ); 1641defines .push_back (type_upper + "_GRID" ); 1642defines .push_back (type_upper + "_LUT" ); 1643 1644variant += "_" ; 1645variant += type_str ; 1646 1647defines .push_back ("DST_TYPE=f32" ); 1648 1649if (key .src_type == GGML_TYPE_Q1_0 ) { 1650defines .push_back ("BLOCK_SIZE=128u" ); 1651 }else if ((key .src_type >=GGML_TYPE_Q4_0 && key .src_type <=GGML_TYPE_Q8_1 )|| 1652key .src_type == GGML_TYPE_IQ4_NL || key .src_type == GGML_TYPE_MXFP4 ) { 1653defines .push_back ("BLOCK_SIZE=32u" ); 1654 }else if (key .src_type == GGML_TYPE_NVFP4 ) { 1655defines .push_back ("BLOCK_SIZE=64u" ); 1656 }else if (key .src_type >=GGML_TYPE_Q2_K ) { 1657defines .push_back ("BLOCK_SIZE=256u" ); 1658 }else { 1659defines .push_back ("BLOCK_SIZE=1u" ); 1660 } 1661break ; 1662 } 1663 } 1664 1665if (key .vectorized ) { 1666variant += "_vec" ; 1667 } 1668 1669defines .push_back ("WG_SIZE=" + std::to_string (context .max_wg_size )); 1670 1671auto processed = preprocessor .preprocess (wgsl_get_rows ,defines ); 1672auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1673decisions -> wg_size = context .max_wg_size ; 1674webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1675pipeline .context = decisions ; 1676get_rows_pipelines [key ]= pipeline ; 1677return get_rows_pipelines [key ]; 1678 } 1679 1680webgpu_pipeline get_scale_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1681ggml_webgpu_scale_pipeline_key key = {}; 1682key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 1683 1684auto it = scale_pipelines .find (key ); 1685if (it != scale_pipelines .end ()) { 1686return it -> second ; 1687 } 1688 1689 std::vector < std::string > defines ; 1690 std::string variant = "scale" ; 1691 1692if (key .inplace ) { 1693defines .push_back ("INPLACE" ); 1694variant += "_inplace" ; 1695 } 1696 1697defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 1698 1699auto processed = preprocessor .preprocess (wgsl_scale ,defines ); 1700auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1701decisions -> wg_size = context .max_wg_size ; 1702decisions -> inplace = key .inplace ; 1703webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1704pipeline .context = decisions ; 1705scale_pipelines [key ]= pipeline ; 1706return scale_pipelines [key ]; 1707 } 1708 1709webgpu_pipeline get_solve_tri_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1710ggml_webgpu_solve_tri_pipeline_key key = {}; 1711key .type = context .dst -> type ; 1712key .n = (int )context .src0 -> ne [0 ]; 1713key .k = (int )context .src1 -> ne [0 ]; 1714 1715auto it = solve_tri_pipelines .find (key ); 1716if (it != solve_tri_pipelines .end ()) { 1717return it -> second ; 1718 } 1719 1720 std::vector < std::string > defines ; 1721 std::string variant = "solve_tri" ; 1722 1723switch (key .type ) { 1724case GGML_TYPE_F32 : 1725variant += "_f32" ; 1726break ; 1727default : 1728GGML_ABORT ("Unsupported type for solve_tri shader" ); 1729 } 1730 1731const uint32_t wg_size = std::min ((uint32_t )key .n ,context .max_wg_size ); 1732const uint32_t k_tile = wg_size ; 1733const uint32_t bytes_per_row = ((uint32_t )key .n + wg_size )* GGML_WEBGPU_F32_SIZE_BYTES ; 1734const uint32_t batch_n = (uint32_t ) (context .wg_mem_limit_bytes /bytes_per_row ); 1735 1736defines .push_back (std::string ("N=" )+ std::to_string (key .n )); 1737defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 1738defines .push_back (std::string ("K_TILE=" )+ std::to_string (k_tile )); 1739defines .push_back (std::string ("BATCH_N=" )+ std::to_string (batch_n )); 1740 1741auto processed = preprocessor .preprocess (wgsl_solve_tri ,defines ); 1742auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1743decisions -> wg_size = wg_size ; 1744webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1745pipeline .context = decisions ; 1746solve_tri_pipelines [key ]= pipeline ; 1747return solve_tri_pipelines [key ]; 1748 } 1749 1750webgpu_pipeline get_ssm_conv_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1751ggml_webgpu_ssm_conv_pipeline_key key = {}; 1752key .type = context .dst -> type ; 1753key .vectorized = context .src1 -> ne [0 ]== 4 ; 1754 1755auto it = ssm_conv_pipelines .find (key ); 1756if (it != ssm_conv_pipelines .end ()) { 1757return it -> second ; 1758 } 1759 1760 std::vector < std::string > defines ; 1761 std::string variant = "ssm_conv" ; 1762 1763switch (key .type ) { 1764case GGML_TYPE_F32 : 1765variant += "_f32" ; 1766break ; 1767default : 1768GGML_ABORT ("Unsupported type for ssm_conv shader" ); 1769 } 1770 1771if (key .vectorized ) { 1772defines .push_back ("VECTORIZED" ); 1773variant += "_vec4" ; 1774 } 1775 1776constexpr uint32_t block_size = 32u ; 1777constexpr uint32_t tokens_per_wg = 8u ; 1778 1779defines .push_back ("BLOCK_SIZE=" + std::to_string (block_size )+ "u" ); 1780defines .push_back ("TOKENS_PER_WG=" + std::to_string (tokens_per_wg )+ "u" ); 1781 1782auto processed = preprocessor .preprocess (wgsl_ssm_conv ,defines ); 1783auto decisions = std::make_shared < ggml_webgpu_ssm_conv_shader_decisions > (); 1784decisions -> block_size = block_size ; 1785decisions -> tokens_per_wg = tokens_per_wg ; 1786webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1787pipeline .context = decisions ; 1788ssm_conv_pipelines [key ]= pipeline ; 1789return ssm_conv_pipelines [key ]; 1790 } 1791 1792webgpu_pipeline get_ssm_scan_pipeline (const ggml_webgpu_shader_lib_context & context , 1793bool xbc_overlap , 1794bool a_overlap , 1795bool ids_overlap ) { 1796ggml_webgpu_ssm_scan_pipeline_key key = {}; 1797key .type = context .dst -> type ; 1798key .d_state = (int )context .src0 -> ne [0 ]; 1799key .xbc_overlap = xbc_overlap ; 1800key .a_overlap = a_overlap ; 1801key .ids_overlap = ids_overlap ; 1802 1803auto it = ssm_scan_pipelines .find (key ); 1804if (it != ssm_scan_pipelines .end ()) { 1805return it -> second ; 1806 } 1807 1808 std::vector < std::string > defines ; 1809 std::string variant = "ssm_scan" ; 1810 1811switch (key .type ) { 1812case GGML_TYPE_F32 : 1813variant += "_f32" ; 1814break ; 1815default : 1816GGML_ABORT ("Unsupported type for ssm_scan shader" ); 1817 } 1818 1819const uint32_t wg_size = (uint32_t )key .d_state ; 1820 1821constexpr uint32_t tokens_per_tile = 4u ; 1822 1823defines .push_back ("WG_SIZE=" + std::to_string (wg_size )+ "u" ); 1824defines .push_back ("TOKENS_PER_TILE=" + std::to_string (tokens_per_tile )+ "u" ); 1825 1826if (context .supports_subgroups ) { 1827defines .push_back ("USE_SUBGROUP_REDUCTION" ); 1828variant += "_sg_reduce" ; 1829 }else { 1830variant += "_wg_reduce" ; 1831 } 1832 1833if (key .xbc_overlap ) { 1834defines .push_back ("XBC_OVERLAP" ); 1835 } 1836if (key .a_overlap ) { 1837defines .push_back ("A_OVERLAP" ); 1838 } 1839if (key .ids_overlap ) { 1840defines .push_back ("IDS_OVERLAP" ); 1841 } 1842variant += "_d" + std::to_string (key .d_state ); 1843 1844auto processed = preprocessor .preprocess (wgsl_ssm_scan ,defines ); 1845auto decisions = std::make_shared < ggml_webgpu_ssm_scan_shader_decisions > (); 1846decisions -> wg_size = wg_size ; 1847decisions -> tokens_per_tile = tokens_per_tile ; 1848decisions -> xbc_overlap = key .xbc_overlap ; 1849decisions -> a_overlap = key .a_overlap ; 1850decisions -> ids_overlap = key .ids_overlap ; 1851webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1852pipeline .context = decisions ; 1853ssm_scan_pipelines [key ]= pipeline ; 1854return ssm_scan_pipelines [key ]; 1855 } 1856 1857webgpu_pipeline get_gated_delta_net_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1858ggml_webgpu_gated_delta_net_pipeline_key key = {}; 1859key .type = context .dst -> type ; 1860key .s_v = (int )context .src2 -> ne [0 ]; 1861key .kda = context .src3 -> ne [0 ]== context .src2 -> ne [0 ]; 1862 1863auto it = gated_delta_net_pipelines .find (key ); 1864if (it != gated_delta_net_pipelines .end ()) { 1865return it -> second ; 1866 } 1867 1868 std::vector < std::string > defines ; 1869 std::string variant = "gated_delta_net" ; 1870 1871switch (key .type ) { 1872case GGML_TYPE_F32 : 1873variant += "_f32" ; 1874break ; 1875default : 1876GGML_ABORT ("Unsupported type for gated_delta_net shader" ); 1877 } 1878 1879if (key .kda ) { 1880defines .push_back ("KDA" ); 1881variant += "_kda" ; 1882 } 1883 1884defines .push_back ("S_V=" + std::to_string (key .s_v )+ "u" ); 1885defines .push_back ("WG_SIZE=" + std::to_string (key .s_v )+ "u" ); 1886 1887auto processed = preprocessor .preprocess (wgsl_gated_delta_net ,defines ); 1888webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1889gated_delta_net_pipelines [key ]= pipeline ; 1890return gated_delta_net_pipelines [key ]; 1891 } 1892 1893webgpu_pipeline get_pad_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1894ggml_webgpu_pad_pipeline_key key = {}; 1895key .circular = ggml_get_op_params_i32 (context .dst ,8 )!= 0 ; 1896 1897auto it = pad_pipelines .find (key ); 1898if (it != pad_pipelines .end ()) { 1899return it -> second ; 1900 } 1901 1902 std::vector < std::string > defines ; 1903 std::string variant = "pad" ; 1904 1905if (key .circular ) { 1906defines .push_back ("CIRCULAR" ); 1907variant += "_circular" ; 1908 } 1909 1910defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 1911 1912auto processed = preprocessor .preprocess (wgsl_pad ,defines ); 1913auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1914decisions -> wg_size = context .max_wg_size ; 1915webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1916pipeline .context = decisions ; 1917pad_pipelines [key ]= pipeline ; 1918return pad_pipelines [key ]; 1919 } 1920 1921webgpu_pipeline get_quantize_q8_pipeline (const ggml_webgpu_shader_lib_context & context ) { 1922ggml_webgpu_quantize_q8_pipeline_key key = {}; 1923key .src0_type = context .src0 -> type ; 1924 1925auto it = quantize_q8_pipelines .find (key ); 1926if (it != quantize_q8_pipelines .end ()) { 1927return it -> second ; 1928 } 1929const char * shader_src = wgsl_quantize_q8 ; 1930 std::vector < std::string > defines ; 1931 std::string variant = "quantize_q8" ; 1932 1933uint32_t wg_size = WEBGPU_MUL_MAT_VEC_WG_SIZE ; 1934 1935defines .push_back ("SRC1_INNER_TYPE=f32" ); 1936defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 1937 1938const struct ggml_type_traits * src0_traits = ggml_get_type_traits (context .src0 -> type ); 1939 std::string src0_name = src0_traits -> type_name ; 1940 std::string type_upper = src0_name ; 1941variant += "_" + src0_name ; 1942 std::transform (type_upper .begin (),type_upper .end (),type_upper .begin (), ::toupper ); 1943 1944defines .push_back ("MUL_ACC_" + type_upper ); 1945defines .push_back ("Q8_1_T" ); 1946 1947defines .push_back (context .supports_subgroups ?"USE_SUBGROUP_REDUCTION" :"USE_WORKGROUP_REDUCTION" ); 1948variant += context .supports_subgroups ?"_sg_reduce" :"_wg_reduce" ; 1949 1950auto processed = preprocessor .preprocess (shader_src ,defines ); 1951auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 1952decisions -> wg_size = wg_size ; 1953webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 1954pipeline .context = decisions ; 1955quantize_q8_pipelines [key ]= pipeline ; 1956return quantize_q8_pipelines [key ]; 1957 } 1958 1959webgpu_pipeline get_mul_mat_vec_pipeline (const ggml_webgpu_shader_lib_context & context ,bool src_overlap ) { 1960ggml_webgpu_mul_mat_vec_pipeline_key key = {}; 1961key .src0_type = context .src0 -> type ; 1962key .src1_type = context .src1 -> type ; 1963key .vectorized = (context .src0 -> ne [0 ] %4 == 0 && 1964 (context .src0 -> type == GGML_TYPE_F32 || context .src0 -> type == GGML_TYPE_F16 )) ? 19651 : 19660 ; 1967key .num_cols = context .dst -> ne [1 ]; 1968key .use_mmvq = 1969ggml_webgpu_can_use_mmvq (context .src0 ,context .src1 ,context .supports_dot_product ,context .vendor ); 1970key .src_overlap = src_overlap ; 1971 1972auto it = mul_mat_vec_pipelines .find (key ); 1973if (it != mul_mat_vec_pipelines .end ()) { 1974return it -> second ; 1975 } 1976 1977 std::vector < std::string > defines ; 1978 std::string variant = "mul_mat_vec" ; 1979const char * shader_src = wgsl_mul_mat_vec ; 1980 1981// src0 type (matrix row) 1982switch (context .src0 -> type ) { 1983case GGML_TYPE_F32 : 1984defines .push_back ("SRC0_INNER_TYPE=f32" ); 1985defines .push_back ("MUL_ACC_FLOAT" ); 1986variant += "_f32" ; 1987break ; 1988case GGML_TYPE_F16 : 1989defines .push_back ("SRC0_INNER_TYPE=f16" ); 1990defines .push_back ("MUL_ACC_FLOAT" ); 1991variant += "_f16" ; 1992break ; 1993default : 1994 { 1995// Quantized types: use helpers but accumulate in f16 1996const struct ggml_type_traits * src0_traits = ggml_get_type_traits (context .src0 -> type ); 1997 std::string src0_name = src0_traits -> type_name ; 1998 std::string type_upper = src0_name ; 1999variant += "_" + src0_name ; 2000 std::transform (type_upper .begin (),type_upper .end (),type_upper .begin (), ::toupper ); 2001 2002defines .push_back ("BYTE_HELPERS" ); 2003defines .push_back ("MUL_ACC_" + type_upper ); 2004defines .push_back ("U32_DEQUANT_HELPERS" ); 2005defines .push_back ("SRC0_INNER_TYPE=u32" ); 2006switch (context .src0 -> type ) { 2007case GGML_TYPE_Q8_0 : 2008case GGML_TYPE_Q4_0 : 2009case GGML_TYPE_Q4_1 : 2010if (key .use_mmvq ) { 2011defines .push_back ("LEGACY_QUANTS" ); 2012 } 2013break ; 2014case GGML_TYPE_Q2_K : 2015case GGML_TYPE_Q4_K : 2016if (key .use_mmvq ) { 2017defines .push_back ("K_QUANTS" ); 2018 } 2019break ; 2020case GGML_TYPE_IQ1_S : 2021case GGML_TYPE_IQ1_M : 2022case GGML_TYPE_IQ2_S : 2023case GGML_TYPE_IQ3_S : 2024case GGML_TYPE_IQ4_NL : 2025case GGML_TYPE_IQ4_XS : 2026defines .push_back (type_upper + "_GRID" ); 2027break ; 2028case GGML_TYPE_IQ2_XXS : 2029case GGML_TYPE_IQ2_XS : 2030case GGML_TYPE_IQ3_XXS : 2031defines .push_back (type_upper + "_GRID" ); 2032defines .push_back (type_upper + "_TABLES" ); 2033break ; 2034case GGML_TYPE_MXFP4 : 2035case GGML_TYPE_NVFP4 : 2036defines .push_back (type_upper + "_LUT" ); 2037break ; 2038default : 2039break ; 2040 } 2041break ; 2042 } 2043 } 2044 2045// src1 type (vector) 2046switch (context .src1 -> type ) { 2047case GGML_TYPE_F32 : 2048defines .push_back ("SRC1_INNER_TYPE=f32" ); 2049variant += "_f32" ; 2050break ; 2051case GGML_TYPE_F16 : 2052defines .push_back ("SRC1_INNER_TYPE=f16" ); 2053variant += "_f16" ; 2054break ; 2055default : 2056GGML_ABORT ("Unsupported src1 type for mul_mat_vec shader" ); 2057 } 2058 2059// VEC/SCALAR controls 2060defines .push_back (key .vectorized ?"VEC" :"SCALAR" ); 2061 2062uint32_t wg_size = WEBGPU_MUL_MAT_VEC_WG_SIZE ; 2063uint32_t outputs_per_wg = WEBGPU_MUL_MAT_VEC_FLOAT_OUTPUTS_PER_WG ; 2064 2065if (key .src0_type == GGML_TYPE_Q1_0 ) { 2066outputs_per_wg = WEBGPU_MUL_MAT_VEC_LEGACY_Q_OUTPUTS_PER_WG ; 2067 }else if (key .src0_type >=GGML_TYPE_Q2_K ) { 2068outputs_per_wg = WEBGPU_MUL_MAT_VEC_K_Q_OUTPUTS_PER_WG ; 2069 }else if (key .src0_type >=GGML_TYPE_Q4_0 ) { 2070outputs_per_wg = WEBGPU_MUL_MAT_VEC_LEGACY_Q_OUTPUTS_PER_WG ; 2071 } 2072 2073if (key .use_mmvq ) { 2074defines .push_back ("MMVQ" ); 2075defines .push_back ("Q8_1_T" ); 2076 } 2077 2078if (key .src_overlap ) { 2079defines .push_back ("SRC_OVERLAP" ); 2080variant += "_src_overlap" ; 2081 } 2082 2083defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 2084defines .push_back (std::string ("OUTPUTS_PER_WG=" )+ std::to_string (outputs_per_wg )); 2085defines .push_back (context .supports_subgroups ?"USE_SUBGROUP_REDUCTION" :"USE_WORKGROUP_REDUCTION" ); 2086variant += context .supports_subgroups ?"_sg_reduce" :"_wg_reduce" ; 2087if (key .vectorized ) { 2088variant += "_vectorized" ; 2089 } 2090defines .push_back (std::string ("NUM_COLS=" )+ std::to_string (key .num_cols )); 2091 2092auto processed = preprocessor .preprocess (shader_src ,defines ); 2093auto decisions = std::make_shared < ggml_webgpu_mul_mat_vec_shader_decisions > (); 2094decisions -> wg_size = wg_size ; 2095decisions -> outputs_per_wg = outputs_per_wg ; 2096decisions -> vec_size = key .vectorized ?4 :1 ; 2097 2098webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2099pipeline .context = decisions ; 2100mul_mat_vec_pipelines [key ]= pipeline ; 2101return mul_mat_vec_pipelines [key ]; 2102 } 2103 2104webgpu_pipeline get_mul_mat_fast_pipeline (const ggml_webgpu_shader_lib_context & context ,bool src_overlap ) { 2105ggml_webgpu_mul_mat_pipeline_key key = {}; 2106key .src0_type = context .src0 -> type ; 2107key .src1_type = context .src1 -> type ; 2108key .vectorized = (context .src0 -> ne [0 ] %4 == 0 && context .dst -> ne [0 ] %4 == 0 && 2109 (context .src0 -> type == GGML_TYPE_F32 || context .src0 -> type == GGML_TYPE_F16 )) ? 21101 : 21110 ; 2112key .use_subgroup_matrix = context .supports_subgroup_matrix ; 2113key .src_overlap = src_overlap ; 2114 2115auto it = mul_mat_fast_pipelines .find (key ); 2116if (it != mul_mat_fast_pipelines .end ()) { 2117return it -> second ; 2118 } 2119 2120const char * shader_src = key .use_subgroup_matrix ?wgsl_mul_mat_subgroup_matrix :wgsl_mul_mat_reg_tile ; 2121 std::vector < std::string > defines ; 2122 std::string variant = key .use_subgroup_matrix ?"mul_mat_subgroup_matrix" :"mul_mat_reg_tile" ; 2123 2124// src1 type 2125switch (context .src1 -> type ) { 2126case GGML_TYPE_F32 : 2127defines .push_back ("SRC1_INNER_TYPE=f32" ); 2128break ; 2129case GGML_TYPE_F16 : 2130defines .push_back ("SRC1_INNER_TYPE=f16" ); 2131break ; 2132default : 2133GGML_ABORT ("Unsupported src1 type for mul_mat fast shader" ); 2134 } 2135 2136// src0 type 2137const struct ggml_type_traits * src0_traits = ggml_get_type_traits (context .src0 -> type ); 2138const char * src0_name = src0_traits -> type_name ; 2139 2140switch (context .src0 -> type ) { 2141case GGML_TYPE_F32 : 2142defines .push_back ("SRC0_INNER_TYPE=f32" ); 2143defines .push_back ("FLOAT" ); 2144defines .push_back ("MUL_ACC_FLOAT" ); 2145defines .push_back ("INIT_SRC0_SHMEM_FLOAT" ); 2146defines .push_back ("INIT_SRC1_SHMEM_FLOAT" ); 2147variant += "_f32" ; 2148break ; 2149case GGML_TYPE_F16 : 2150defines .push_back ("SRC0_INNER_TYPE=f16" ); 2151defines .push_back ("FLOAT" ); 2152defines .push_back ("MUL_ACC_FLOAT" ); 2153defines .push_back ("INIT_SRC0_SHMEM_FLOAT" ); 2154defines .push_back ("INIT_SRC1_SHMEM_FLOAT" ); 2155variant += "_f16" ; 2156break ; 2157default : 2158 { 2159 std::string type_upper = src0_name ; 2160 std::transform (type_upper .begin (),type_upper .end (),type_upper .begin (), ::toupper ); 2161 2162defines .push_back ("BYTE_HELPERS" ); 2163defines .push_back ("MUL_ACC_" + type_upper ); 2164defines .push_back ("INIT_SRC0_SHMEM_" + type_upper ); 2165defines .push_back ("INIT_SRC1_SHMEM_FLOAT" ); 2166defines .push_back ("U32_DEQUANT_HELPERS" ); 2167defines .push_back ("SRC0_INNER_TYPE=u32" ); 2168 2169switch (context .src0 -> type ) { 2170case GGML_TYPE_IQ1_S : 2171case GGML_TYPE_IQ1_M : 2172case GGML_TYPE_IQ4_NL : 2173case GGML_TYPE_IQ4_XS : 2174defines .push_back (type_upper + "_GRID" ); 2175break ; 2176case GGML_TYPE_IQ2_XXS : 2177case GGML_TYPE_IQ2_XS : 2178case GGML_TYPE_IQ2_S : 2179case GGML_TYPE_IQ3_XXS : 2180case GGML_TYPE_IQ3_S : 2181defines .push_back (type_upper + "_GRID" ); 2182defines .push_back (type_upper + "_TABLES" ); 2183break ; 2184case GGML_TYPE_MXFP4 : 2185case GGML_TYPE_NVFP4 : 2186defines .push_back (type_upper + "_LUT" ); 2187break ; 2188default : 2189break ; 2190 } 2191 2192variant += std::string ("_" )+ src0_name ; 2193break ; 2194 } 2195 } 2196 2197// VEC/SCALAR controls 2198defines .push_back (key .vectorized ?"VEC" :"SCALAR" ); 2199 2200const bool is_quant = ggml_is_quantized (context .src0 -> type ); 2201 2202uint32_t tile_k ; 2203if (key .use_subgroup_matrix ) { 2204tile_k = is_quant ?WEBGPU_MUL_MAT_SUBGROUP_TILE_K_QUANT :WEBGPU_MUL_MAT_SUBGROUP_TILE_K_FLOAT ; 2205 }else { 2206tile_k = is_quant ?WEBGPU_MUL_MAT_REG_TILE_K_QUANT :WEBGPU_MUL_MAT_REG_TILE_K_FLOAT ; 2207 } 2208 2209// Tiles 2210defines .push_back ("TILE_M=" + std::to_string (WEBGPU_MUL_MAT_TILE_M )+ "u" ); 2211defines .push_back ("TILE_N=" + std::to_string (WEBGPU_MUL_MAT_TILE_N )+ "u" ); 2212 2213// Subgroup matrix specifics 2214if (key .use_subgroup_matrix ) { 2215defines .push_back ("TILE_K=" + std::to_string (tile_k )+ "u" ); 2216defines .push_back ("MAX_SUBGROUP_SIZE=" + std::to_string (context .max_subgroup_size )+ "u" ); 2217defines .push_back ("SUBGROUP_M=" + std::to_string (WEBGPU_MUL_MAT_SUBGROUP_M )+ "u" ); 2218defines .push_back ("SUBGROUP_N=" + std::to_string (WEBGPU_MUL_MAT_SUBGROUP_N )+ "u" ); 2219defines .push_back ("SUBGROUP_MATRIX_M=" + std::to_string (WEBGPU_MUL_MAT_SUBGROUP_MATRIX_M )+ "u" ); 2220defines .push_back ("SUBGROUP_MATRIX_N=" + std::to_string (WEBGPU_MUL_MAT_SUBGROUP_MATRIX_N )+ "u" ); 2221defines .push_back ("SUBGROUP_MATRIX_M_SIZE=" + std::to_string (context .sg_mat_m )+ "u" ); 2222defines .push_back ("SUBGROUP_MATRIX_N_SIZE=" + std::to_string (context .sg_mat_n )+ "u" ); 2223defines .push_back ("SUBGROUP_MATRIX_K_SIZE=" + std::to_string (context .sg_mat_k )+ "u" ); 2224 } 2225 2226// variant suffix for src1 type 2227variant += std::string ("_" )+ (context .src1 -> type == GGML_TYPE_F32 ?"f32" :"f16" ); 2228if (key .vectorized ) { 2229variant += "_vectorized" ; 2230 } 2231 2232if (key .src_overlap ) { 2233defines .push_back ("SRC_OVERLAP" ); 2234variant += "_src_overlap" ; 2235 } 2236 2237if (!key .use_subgroup_matrix ) { 2238defines .push_back ("WORKGROUP_SIZE_M=" + std::to_string (WEBGPU_MUL_MAT_WG_SIZE_M )+ "u" ); 2239defines .push_back ("WORKGROUP_SIZE_N=" + std::to_string (WEBGPU_MUL_MAT_WG_SIZE_N )+ "u" ); 2240defines .push_back ("TILE_K=" + std::to_string (tile_k )+ "u" ); 2241 } 2242 2243auto processed = preprocessor .preprocess (shader_src ,defines ); 2244 2245auto decisions = std::make_shared < ggml_webgpu_mul_mat_shader_decisions > (); 2246decisions -> tile_k = tile_k ; 2247decisions -> tile_m = WEBGPU_MUL_MAT_TILE_M ; 2248decisions -> tile_n = WEBGPU_MUL_MAT_TILE_N ; 2249decisions -> use_subgroup_matrix = key .use_subgroup_matrix ; 2250if (key .use_subgroup_matrix ) { 2251decisions -> subgroup_m = WEBGPU_MUL_MAT_SUBGROUP_M ; 2252decisions -> subgroup_n = WEBGPU_MUL_MAT_SUBGROUP_N ; 2253decisions -> subgroup_matrix_m = WEBGPU_MUL_MAT_SUBGROUP_MATRIX_M ; 2254decisions -> subgroup_matrix_n = WEBGPU_MUL_MAT_SUBGROUP_MATRIX_N ; 2255decisions -> wg_size = context .max_subgroup_size ; 2256 }else { 2257decisions -> wg_size_m = WEBGPU_MUL_MAT_WG_SIZE_M ; 2258decisions -> wg_size_n = WEBGPU_MUL_MAT_WG_SIZE_N ; 2259decisions -> wg_size = WEBGPU_MUL_MAT_WG_SIZE_M * WEBGPU_MUL_MAT_WG_SIZE_N ; 2260decisions -> mul_mat_wg_size = WEBGPU_MUL_MAT_WG_SIZE ; 2261 } 2262 2263webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2264pipeline .context = decisions ; 2265mul_mat_fast_pipelines [key ]= pipeline ; 2266return mul_mat_fast_pipelines [key ]; 2267 } 2268 2269webgpu_pipeline get_mul_mat_id_gather_pipeline (const ggml_webgpu_shader_lib_context & context ) { 2270auto it = mul_mat_id_gather_pipelines .find (1 ); 2271if (it != mul_mat_id_gather_pipelines .end ()) { 2272return it -> second ; 2273 } 2274 std::vector < std::string > defines ; 2275defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2276 2277auto processed = preprocessor .preprocess (wgsl_mul_mat_id_gather ,defines ); 2278auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 2279decisions -> wg_size = context .max_wg_size ; 2280 2281webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,"mul_mat_id_gather" ); 2282pipeline .context = decisions ; 2283mul_mat_id_gather_pipelines [1 ]= pipeline ; 2284return pipeline ; 2285 } 2286 2287webgpu_pipeline get_mul_mat_id_pipeline (const ggml_webgpu_shader_lib_context & context ) { 2288ggml_webgpu_mul_mat_id_pipeline_key key = {}; 2289key .src0_type = context .src0 -> type ; 2290key .src1_type = context .src1 -> type ; 2291key .n_experts = context .src0 -> ne [2 ]; 2292key .vectorized = (context .src0 -> ne [0 ] %4 == 0 && context .src0 -> ne [1 ] %4 == 0 && 2293 (context .src0 -> type == GGML_TYPE_F32 || context .src0 -> type == GGML_TYPE_F16 )) ? 22941 : 22950 ; 2296 2297auto it = mul_mat_id_pipelines .find (key ); 2298if (it != mul_mat_id_pipelines .end ()) { 2299return it -> second ; 2300 } 2301 2302 std::vector < std::string > defines ; 2303 std::string variant = "mul_mat_id" ; 2304defines .push_back ("MUL_MAT_ID" ); 2305 2306// src1 type 2307switch (context .src1 -> type ) { 2308case GGML_TYPE_F32 : 2309defines .push_back ("SRC1_INNER_TYPE=f32" ); 2310break ; 2311case GGML_TYPE_F16 : 2312defines .push_back ("SRC1_INNER_TYPE=f16" ); 2313break ; 2314default : 2315GGML_ABORT ("Unsupported src1 type for mul_mat fast shader" ); 2316 } 2317 2318// src0 type 2319const struct ggml_type_traits * src0_traits = ggml_get_type_traits (context .src0 -> type ); 2320const char * src0_name = src0_traits -> type_name ; 2321 2322switch (context .src0 -> type ) { 2323case GGML_TYPE_F32 : 2324defines .push_back ("SRC0_INNER_TYPE=f32" ); 2325defines .push_back ("INIT_SRC0_SHMEM_FLOAT" ); 2326defines .push_back ("INIT_SRC1_SHMEM_FLOAT" ); 2327variant += "_f32" ; 2328break ; 2329case GGML_TYPE_F16 : 2330defines .push_back ("SRC0_INNER_TYPE=f16" ); 2331defines .push_back ("INIT_SRC0_SHMEM_FLOAT" ); 2332defines .push_back ("INIT_SRC1_SHMEM_FLOAT" ); 2333variant += "_f16" ; 2334break ; 2335default : 2336 { 2337 std::string type_upper = src0_name ; 2338 std::transform (type_upper .begin (),type_upper .end (),type_upper .begin (), ::toupper ); 2339 2340defines .push_back ("BYTE_HELPERS" ); 2341defines .push_back ("INIT_SRC0_SHMEM_" + type_upper ); 2342defines .push_back ("INIT_SRC1_SHMEM_FLOAT" ); 2343defines .push_back ("U32_DEQUANT_HELPERS" ); 2344defines .push_back ("SRC0_INNER_TYPE=u32" ); 2345 2346switch (context .src0 -> type ) { 2347case GGML_TYPE_IQ1_S : 2348case GGML_TYPE_IQ1_M : 2349case GGML_TYPE_IQ4_NL : 2350case GGML_TYPE_IQ4_XS : 2351defines .push_back (type_upper + "_GRID" ); 2352break ; 2353case GGML_TYPE_IQ2_XXS : 2354case GGML_TYPE_IQ2_XS : 2355case GGML_TYPE_IQ2_S : 2356case GGML_TYPE_IQ3_XXS : 2357case GGML_TYPE_IQ3_S : 2358defines .push_back (type_upper + "_GRID" ); 2359defines .push_back (type_upper + "_TABLES" ); 2360break ; 2361case GGML_TYPE_MXFP4 : 2362case GGML_TYPE_NVFP4 : 2363defines .push_back (type_upper + "_LUT" ); 2364break ; 2365default : 2366break ; 2367 } 2368 2369variant += std::string ("_" )+ src0_name ; 2370break ; 2371 } 2372 } 2373 2374// VEC/SCALAR controls 2375defines .push_back (key .vectorized ?"VEC" :"SCALAR" ); 2376 2377// mul_mat_id is register-tile only. 2378const uint32_t tile_k = 2379ggml_is_quantized (context .src0 -> type ) ?WEBGPU_MUL_MAT_REG_TILE_K_QUANT :WEBGPU_MUL_MAT_REG_TILE_K_FLOAT ; 2380 2381// Tiles 2382defines .push_back ("TILE_M=" + std::to_string (WEBGPU_MUL_MAT_TILE_M )+ "u" ); 2383defines .push_back ("TILE_N=" + std::to_string (WEBGPU_MUL_MAT_TILE_N )+ "u" ); 2384defines .push_back ("TILE_K=" + std::to_string (tile_k )+ "u" ); 2385 2386defines .push_back ("WORKGROUP_SIZE_M=" + std::to_string (WEBGPU_MUL_MAT_WG_SIZE_M )+ "u" ); 2387defines .push_back ("WORKGROUP_SIZE_N=" + std::to_string (WEBGPU_MUL_MAT_WG_SIZE_N )+ "u" ); 2388 2389// variant suffix for src1 type 2390variant += std::string ("_" )+ (context .src1 -> type == GGML_TYPE_F32 ?"f32" :"f16" ); 2391if (key .vectorized ) { 2392variant += "_vectorized" ; 2393 } 2394 2395auto processed = preprocessor .preprocess (wgsl_mul_mat_id ,defines ); 2396 2397auto decisions = std::make_shared < ggml_webgpu_mul_mat_shader_decisions > (); 2398decisions -> tile_k = tile_k ; 2399decisions -> tile_m = WEBGPU_MUL_MAT_TILE_M ; 2400decisions -> tile_n = WEBGPU_MUL_MAT_TILE_N ; 2401decisions -> wg_size_m = WEBGPU_MUL_MAT_WG_SIZE_M ; 2402decisions -> wg_size_n = WEBGPU_MUL_MAT_WG_SIZE_N ; 2403decisions -> wg_size = WEBGPU_MUL_MAT_WG_SIZE_M * WEBGPU_MUL_MAT_WG_SIZE_N ; 2404 2405webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2406pipeline .context = decisions ; 2407mul_mat_id_pipelines [key ]= pipeline ; 2408return mul_mat_id_pipelines [key ]; 2409 } 2410 2411webgpu_pipeline get_mul_mat_id_vec_pipeline (const ggml_webgpu_shader_lib_context & context ) { 2412ggml_webgpu_mul_mat_id_pipeline_key key = {}; 2413key .src0_type = context .src0 -> type ; 2414key .src1_type = context .src1 -> type ; 2415key .n_experts = context .src0 -> ne [2 ]; 2416key .vectorized = (context .src0 -> ne [0 ] %4 == 0 && 2417 (context .src0 -> type == GGML_TYPE_F32 || context .src0 -> type == GGML_TYPE_F16 )) ? 24181 : 24190 ; 2420 2421auto it = mul_mat_id_vec_pipelines .find (key ); 2422if (it != mul_mat_id_vec_pipelines .end ()) { 2423return it -> second ; 2424 } 2425 2426 std::vector < std::string > defines ; 2427 std::string variant = "mul_mat_id_vec" ; 2428const char * shader_src = wgsl_mul_mat_id_vec ; 2429 2430// src1 type 2431switch (context .src1 -> type ) { 2432case GGML_TYPE_F32 : 2433defines .push_back ("SRC1_INNER_TYPE=f32" ); 2434break ; 2435case GGML_TYPE_F16 : 2436defines .push_back ("SRC1_INNER_TYPE=f16" ); 2437break ; 2438default : 2439GGML_ABORT ("Unsupported src1 type for mul_mat fast shader" ); 2440 } 2441 2442// src0 type 2443switch (context .src0 -> type ) { 2444case GGML_TYPE_F32 : 2445defines .push_back ("SRC0_INNER_TYPE=f32" ); 2446defines .push_back ("MUL_ACC_FLOAT" ); 2447variant += "_f32" ; 2448break ; 2449case GGML_TYPE_F16 : 2450defines .push_back ("SRC0_INNER_TYPE=f16" ); 2451defines .push_back ("MUL_ACC_FLOAT" ); 2452variant += "_f16" ; 2453break ; 2454default : 2455 { 2456// Quantized types: use helpers but accumulate in f16 2457const struct ggml_type_traits * src0_traits = ggml_get_type_traits (context .src0 -> type ); 2458 std::string src0_name = src0_traits -> type_name ; 2459 std::string type_upper = src0_name ; 2460variant += "_" + src0_name ; 2461 std::transform (type_upper .begin (),type_upper .end (),type_upper .begin (), ::toupper ); 2462 2463defines .push_back ("BYTE_HELPERS" ); 2464defines .push_back ("MUL_ACC_" + type_upper ); 2465defines .push_back ("U32_DEQUANT_HELPERS" ); 2466defines .push_back ("SRC0_INNER_TYPE=u32" ); 2467switch (context .src0 -> type ) { 2468case GGML_TYPE_IQ1_S : 2469case GGML_TYPE_IQ1_M : 2470case GGML_TYPE_IQ2_S : 2471case GGML_TYPE_IQ3_S : 2472case GGML_TYPE_IQ4_NL : 2473case GGML_TYPE_IQ4_XS : 2474defines .push_back (type_upper + "_GRID" ); 2475break ; 2476case GGML_TYPE_IQ2_XXS : 2477case GGML_TYPE_IQ2_XS : 2478case GGML_TYPE_IQ3_XXS : 2479defines .push_back (type_upper + "_GRID" ); 2480defines .push_back (type_upper + "_TABLES" ); 2481break ; 2482case GGML_TYPE_MXFP4 : 2483case GGML_TYPE_NVFP4 : 2484defines .push_back (type_upper + "_LUT" ); 2485break ; 2486default : 2487break ; 2488 } 2489break ; 2490 } 2491 } 2492 2493// VEC/SCALAR controls 2494defines .push_back (key .vectorized ?"VEC" :"SCALAR" ); 2495 2496uint32_t wg_size = WEBGPU_MUL_MAT_VEC_WG_SIZE ; 2497uint32_t outputs_per_wg = WEBGPU_MUL_MAT_VEC_FLOAT_OUTPUTS_PER_WG ; 2498 2499if (key .src0_type == GGML_TYPE_Q1_0 ) { 2500outputs_per_wg = WEBGPU_MUL_MAT_VEC_LEGACY_Q_OUTPUTS_PER_WG ; 2501 }else if (key .src0_type >=GGML_TYPE_Q2_K ) { 2502outputs_per_wg = WEBGPU_MUL_MAT_VEC_K_Q_OUTPUTS_PER_WG ; 2503 }else if (key .src0_type >=GGML_TYPE_Q4_0 ) { 2504outputs_per_wg = WEBGPU_MUL_MAT_VEC_LEGACY_Q_OUTPUTS_PER_WG ; 2505 } 2506 2507// variant suffix for src1 type 2508variant += std::string ("_" )+ (context .src1 -> type == GGML_TYPE_F32 ?"f32" :"f16" ); 2509 2510defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 2511defines .push_back (std::string ("OUTPUTS_PER_WG=" )+ std::to_string (outputs_per_wg )); 2512defines .push_back (context .supports_subgroups ?"USE_SUBGROUP_REDUCTION" :"USE_WORKGROUP_REDUCTION" ); 2513variant += context .supports_subgroups ?"_sg_reduce" :"_wg_reduce" ; 2514if (key .vectorized ) { 2515variant += "_vectorized" ; 2516 } 2517defines .push_back (std::string ("NUM_COLS=1" )); 2518 2519defines .push_back (std::string ("N_EXPERTS=" )+ std::to_string (key .n_experts )); 2520 2521auto processed = preprocessor .preprocess (shader_src ,defines ); 2522 2523auto decisions = std::make_shared < ggml_webgpu_mul_mat_vec_shader_decisions > (); 2524decisions -> wg_size = wg_size ; 2525decisions -> outputs_per_wg = outputs_per_wg ; 2526 2527webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2528pipeline .context = decisions ; 2529mul_mat_id_vec_pipelines [key ]= pipeline ; 2530return mul_mat_id_vec_pipelines [key ]; 2531 } 2532 2533webgpu_pipeline get_unary_pipeline (const ggml_webgpu_shader_lib_context & context ) { 2534const bool is_unary = context .dst -> op == GGML_OP_UNARY ; 2535const int op = is_unary ? (int )ggml_get_unary_op (context .dst ) :context .dst -> op ; 2536ggml_webgpu_unary_pipeline_key key = {}; 2537key .type = context .dst -> type ; 2538key .op = op ; 2539key .is_unary = is_unary ; 2540key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst )|| context .dst -> op == GGML_OP_FILL ; 2541key .ttype = (ggml_tri_type )ggml_get_op_params_i32 (context .dst ,0 ); 2542 2543auto it = unary_pipelines .find (key ); 2544if (it != unary_pipelines .end ()) { 2545return it -> second ; 2546 } 2547 2548 std::vector < std::string > defines ; 2549 std::string variant = 2550key .is_unary ?ggml_unary_op_name ((ggml_unary_op )key .op ) :ggml_op_name ((ggml_op )key .op ); 2551defines .push_back (variant ); 2552 2553switch (key .type ) { 2554case GGML_TYPE_F32 : 2555defines .push_back ("TYPE_F32" ); 2556variant += "_f32" ; 2557break ; 2558case GGML_TYPE_F16 : 2559defines .push_back ("TYPE_F16" ); 2560variant += "_f16" ; 2561break ; 2562default : 2563GGML_ABORT ("Unsupported type for unary shader" ); 2564 } 2565 2566if (key .inplace ) { 2567defines .push_back ("INPLACE" ); 2568variant += "_inplace" ; 2569 } 2570 2571if (op == GGML_OP_TRI ) { 2572switch (key .ttype ) { 2573case GGML_TRI_TYPE_LOWER : 2574defines .push_back ("TRI_TYPE_LOWER" ); 2575variant += "_tri_type_lower" ; 2576break ; 2577case GGML_TRI_TYPE_LOWER_DIAG : 2578defines .push_back ("TRI_TYPE_LOWER_DIAG" ); 2579variant += "_tri_type_lower_diag" ; 2580break ; 2581case GGML_TRI_TYPE_UPPER : 2582defines .push_back ("TRI_TYPE_UPPER" ); 2583variant += "_tri_type_upper" ; 2584break ; 2585case GGML_TRI_TYPE_UPPER_DIAG : 2586defines .push_back ("TRI_TYPE_UPPER_DIAG" ); 2587variant += "_tri_upper_diag" ; 2588break ; 2589default : 2590GGML_ABORT ("Unsupported ggml_tri_type for unary shader" ); 2591 } 2592 } 2593 2594defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2595 2596auto processed = preprocessor .preprocess (wgsl_unary ,defines ); 2597auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 2598decisions -> wg_size = context .max_wg_size ; 2599decisions -> inplace = key .inplace ; 2600webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2601pipeline .context = decisions ; 2602unary_pipelines [key ]= pipeline ; 2603return unary_pipelines [key ]; 2604 } 2605 2606webgpu_pipeline get_rms_norm_mul_pipeline (const ggml_webgpu_shader_lib_context & context ,bool src_overlap ) { 2607ggml_webgpu_rms_norm_mul_pipeline_key key = {}; 2608key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 2609key .overlap = ggml_webgpu_tensor_equal (context .src1 ,context .dst ); 2610key .src_overlap = src_overlap ; 2611 2612auto it = rms_norm_mul_pipelines .find (key ); 2613if (it != rms_norm_mul_pipelines .end ()) { 2614return it -> second ; 2615 } 2616 2617 std::vector < std::string > defines ; 2618 std::string op_name = "RMS_NORM_MUL" ; 2619 std::string variant = op_name ; 2620 2621if (key .inplace ) { 2622defines .push_back ("INPLACE" ); 2623variant += "_inplace" ; 2624 }else if (key .overlap ) { 2625defines .push_back ("OVERLAP" ); 2626variant += "_overlap" ; 2627 }else if (key .src_overlap ) { 2628defines .push_back ("SRC_OVERLAP" ); 2629variant += "_src_overlap" ; 2630 } 2631 2632defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2633 2634auto processed = preprocessor .preprocess (wgsl_rms_norm_mul ,defines ); 2635auto pipeline_decisions = std::make_shared < ggml_webgpu_rms_norm_mul_shader_decisions > (); 2636pipeline_decisions -> wg_size = context .max_wg_size ; 2637pipeline_decisions -> inplace = key .inplace ; 2638pipeline_decisions -> overlap = key .overlap ; 2639pipeline_decisions -> src_overlap = key .src_overlap ; 2640webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2641pipeline .context = pipeline_decisions ; 2642rms_norm_mul_pipelines [key ]= pipeline ; 2643return rms_norm_mul_pipelines [key ]; 2644 } 2645 2646webgpu_pipeline get_binary_pipeline (const ggml_webgpu_shader_lib_context & context ,bool src_overlap ) { 2647ggml_webgpu_binary_pipeline_key key = {}; 2648key .type = context .dst -> type ; 2649key .op = context .dst -> op ; 2650key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 2651key .overlap = ggml_webgpu_tensor_equal (context .src1 ,context .dst ); 2652key .src_overlap = src_overlap ; 2653 2654auto it = binary_pipelines .find (key ); 2655if (it != binary_pipelines .end ()) { 2656return it -> second ; 2657 } 2658 2659 std::vector < std::string > defines ; 2660 std::string op_name = ggml_op_name ((ggml_op )key .op ); 2661 std::string variant = op_name ; 2662 2663defines .push_back (std::string ("OP_" )+ op_name ); 2664 2665switch (key .type ) { 2666case GGML_TYPE_F32 : 2667defines .push_back ("TYPE_F32" ); 2668variant += "_f32" ; 2669break ; 2670case GGML_TYPE_F16 : 2671defines .push_back ("TYPE_F16" ); 2672variant += "_f16" ; 2673break ; 2674default : 2675GGML_ABORT ("Unsupported type for binary shader" ); 2676 } 2677 2678if (key .inplace ) { 2679defines .push_back ("INPLACE" ); 2680variant += "_inplace" ; 2681 }else if (key .overlap ) { 2682defines .push_back ("OVERLAP" ); 2683variant += "_overlap" ; 2684 }else if (key .src_overlap ) { 2685defines .push_back ("SRC_OVERLAP" ); 2686variant += "_src_overlap" ; 2687 } 2688 2689defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2690 2691auto processed = preprocessor .preprocess (wgsl_binary ,defines ); 2692auto pipeline_decisions = std::make_shared < ggml_webgpu_binary_shader_decisions > (); 2693pipeline_decisions -> wg_size = context .max_wg_size ; 2694pipeline_decisions -> inplace = key .inplace ; 2695pipeline_decisions -> overlap = key .overlap ; 2696pipeline_decisions -> src_overlap = key .src_overlap ; 2697 2698webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2699pipeline .context = pipeline_decisions ; 2700binary_pipelines [key ]= pipeline ; 2701return binary_pipelines [key ]; 2702 } 2703 2704webgpu_pipeline get_add_id_pipeline (const ggml_webgpu_shader_lib_context & context ) { 2705ggml_webgpu_add_id_pipeline_key key = {}; 2706key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 2707 2708auto it = add_id_pipelines .find (key ); 2709if (it != add_id_pipelines .end ()) { 2710return it -> second ; 2711 } 2712 2713 std::vector < std::string > defines ; 2714 std::string variant = "add_id" ; 2715const char * shader_src = wgsl_add_id ; 2716 2717if (key .inplace ) { 2718defines .push_back ("INPLACE" ); 2719variant += "_inplace" ; 2720 } 2721 2722defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2723 2724auto processed = preprocessor .preprocess (shader_src ,defines ); 2725auto pipeline_decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 2726pipeline_decisions -> wg_size = context .max_wg_size ; 2727pipeline_decisions -> inplace = key .inplace ; 2728 2729webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2730pipeline .context = pipeline_decisions ; 2731add_id_pipelines [key ]= pipeline ; 2732return pipeline ; 2733 } 2734 2735webgpu_pipeline get_concat_pipeline (const ggml_webgpu_shader_lib_context & context ,bool src_overlap ) { 2736ggml_webgpu_concat_pipeline_key key = {}; 2737key .type = context .dst -> type ; 2738key .src_overlap = src_overlap ; 2739 2740auto it = concat_pipelines .find (key ); 2741if (it != concat_pipelines .end ()) { 2742return it -> second ; 2743 } 2744 2745 std::vector < std::string > defines ; 2746 std::string variant = "concat" ; 2747 2748switch (key .type ) { 2749case GGML_TYPE_F32 : 2750defines .push_back ("TYPE_F32" ); 2751variant += "_f32" ; 2752break ; 2753case GGML_TYPE_I32 : 2754defines .push_back ("TYPE_I32" ); 2755variant += "_i32" ; 2756break ; 2757default : 2758GGML_ABORT ("Unsupported type for concat shader" ); 2759 } 2760 2761if (key .src_overlap ) { 2762defines .push_back ("SRC_OVERLAP" ); 2763variant += "_src_overlap" ; 2764 } 2765 2766defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2767 2768auto processed = preprocessor .preprocess (wgsl_concat ,defines ); 2769auto decisions = std::make_shared < ggml_webgpu_binary_shader_decisions > (); 2770decisions -> wg_size = context .max_wg_size ; 2771decisions -> src_overlap = key .src_overlap ; 2772webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2773pipeline .context = decisions ; 2774concat_pipelines [key ]= pipeline ; 2775return concat_pipelines [key ]; 2776 } 2777 2778webgpu_pipeline get_repeat_pipeline (const ggml_webgpu_shader_lib_context & context ) { 2779ggml_webgpu_repeat_pipeline_key key = {}; 2780key .type = context .dst -> type ; 2781 2782auto it = repeat_pipelines .find (key ); 2783if (it != repeat_pipelines .end ()) { 2784return it -> second ; 2785 } 2786 2787 std::vector < std::string > defines ; 2788 std::string variant = "repeat" ; 2789 2790switch (key .type ) { 2791case GGML_TYPE_F32 : 2792defines .push_back ("TYPE_F32" ); 2793variant += "_f32" ; 2794break ; 2795case GGML_TYPE_F16 : 2796defines .push_back ("TYPE_F16" ); 2797variant += "_f16" ; 2798break ; 2799case GGML_TYPE_I32 : 2800defines .push_back ("TYPE_I32" ); 2801variant += "_i32" ; 2802break ; 2803case GGML_TYPE_I16 : 2804defines .push_back ("TYPE_I16" ); 2805variant += "_i16" ; 2806break ; 2807default : 2808GGML_ABORT ("Unsupported type for repeat shader" ); 2809 } 2810 2811defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2812 2813auto processed = preprocessor .preprocess (wgsl_repeat ,defines ); 2814auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 2815decisions -> wg_size = context .max_wg_size ; 2816webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 2817pipeline .context = decisions ; 2818repeat_pipelines [key ]= pipeline ; 2819return repeat_pipelines [key ]; 2820 } 2821 2822webgpu_pipeline get_flash_attn_pipeline (const ggml_webgpu_shader_lib_context & context ,bool kv_overlap ) { 2823const bool can_use_subgroup_matrix = ggml_webgpu_flash_attn_can_use_subgroup_matrix_path ( 2824context .supports_subgroup_matrix ,context .sg_mat_k ,context .sg_mat_n ,context .src0 ,context .src2 ); 2825ggml_webgpu_flash_attn_decisions decisions = {}; 2826decisions .use_sg_matrix = can_use_subgroup_matrix ; 2827decisions .q_tile = decisions .use_sg_matrix ?context .sg_mat_m :GGML_WEBGPU_FLASH_ATTN_TILE_Q_TILE ; 2828 2829ggml_webgpu_flash_attn_pipeline_key key = {}; 2830key .common = ggml_webgpu_flash_attn_make_common_pipeline_key ( 2831context ,decisions .use_sg_matrix ?context .sg_mat_k :1u ,kv_overlap ); 2832key .common .k_direct &=decisions .use_sg_matrix && key .common .k_type == GGML_TYPE_F16 ; 2833key .common .v_direct &=decisions .use_sg_matrix && key .common .v_type == GGML_TYPE_F16 ; 2834key .use_sg_matrix = decisions .use_sg_matrix ; 2835 2836uint32_t max_kv_tile = ggml_webgpu_flash_attn_max_kv_tile ( 2837context .wg_mem_limit_bytes ,decisions .q_tile ,decisions .use_sg_matrix ?context .sg_mat_n :1u , 2838key .common .head_dim_qk ,key .common .head_dim_v ,key .common .has_mask , 2839key .common .k_direct || key .common .v_direct ); 2840 2841// WorkGroup storage size isn't enough for some params with subgroup matrices path (ref. https://github.com/ggml-org/llama.cpp/pull/26566) 2842if (max_kv_tile == 0 ) { 2843GGML_ASSERT (decisions .use_sg_matrix ); 2844// switch to flash_attn_reg_tile path 2845decisions .use_sg_matrix = false; 2846decisions .q_tile = GGML_WEBGPU_FLASH_ATTN_TILE_Q_TILE ; 2847key .common .k_direct = false; 2848key .common .v_direct = false; 2849key .use_sg_matrix = false; 2850max_kv_tile = ggml_webgpu_flash_attn_max_kv_tile ( 2851context .wg_mem_limit_bytes ,decisions .q_tile ,1u ,key .common .head_dim_qk ,key .common .head_dim_v , 2852key .common .has_mask ,key .common .k_direct || key .common .v_direct ); 2853GGML_ASSERT (max_kv_tile > 0 ); 2854 } 2855 2856decisions .kv_tile = decisions .use_sg_matrix ? 2857 std::min (max_kv_tile ,context .sg_mat_n * GGML_WEBGPU_FLASH_ATTN_PREFERRED_KV_SG_TILES ) : 2858 std::min (GGML_WEBGPU_FLASH_ATTN_TILE_MAX_KV_TILE ,max_kv_tile ); 2859decisions .wg_size = 2860decisions .use_sg_matrix ? 2861 std::max (context .max_subgroup_size ,GGML_WEBGPU_FLASH_ATTN_PREFERRED_WG_SIZE ) : 2862 std::min (context .max_wg_size , std::max (GGML_WEBGPU_FLASH_ATTN_PREFERRED_WG_SIZE , 2863GGML_WEBGPU_FLASH_ATTN_TILE_Q_TILE * context .max_subgroup_size )); 2864 2865if (key .common .k_direct || key .common .v_direct ) { 2866decisions .kv_tile = std::min (decisions .kv_tile ,GGML_WEBGPU_KV_SEQ_PAD ); 2867while (GGML_WEBGPU_KV_SEQ_PAD %decisions .kv_tile != 0 ) { 2868decisions .kv_tile -= decisions .use_sg_matrix ?context .sg_mat_n :context .min_subgroup_size ; 2869 } 2870 } 2871 2872auto it = flash_attn_pipelines .find (key ); 2873if (it != flash_attn_pipelines .end ()) { 2874return it -> second ; 2875 } 2876 2877 std::string variant = decisions .use_sg_matrix ?"flash_attn" :"flash_attn_tile" ; 2878 std::vector < std::string > defines = ggml_webgpu_flash_attn_common_defines (key .common ,variant ,decisions .q_tile , 2879decisions .kv_tile ,decisions .wg_size ); 2880const char * shader_src = nullptr ; 2881if (!key .use_sg_matrix ) { 2882shader_src = wgsl_flash_attn_tile ; 2883defines .push_back ("MIN_SUBGROUP_SIZE=" + std::to_string (context .min_subgroup_size )+ "u" ); 2884defines .push_back ("MAX_SUBGROUP_SIZE=" + std::to_string (context .max_subgroup_size )+ "u" ); 2885variant += "_tile_sg" + std::to_string (context .min_subgroup_size )+ "_" + 2886 std::to_string (context .max_subgroup_size ); 2887 }else { 2888shader_src = wgsl_flash_attn ; 2889defines .push_back (std::string ("SG_MAT_M=" )+ std::to_string (context .sg_mat_m )); 2890defines .push_back (std::string ("SG_MAT_N=" )+ std::to_string (context .sg_mat_n )); 2891defines .push_back (std::string ("SG_MAT_K=" )+ std::to_string (context .sg_mat_k )); 2892 } 2893auto pipeline_decisions = std::make_shared < ggml_webgpu_flash_attn_decisions > (decisions ); 2894webgpu_pipeline pipeline = 2895ggml_webgpu_create_pipeline (device ,preprocessor .preprocess (shader_src ,defines ),variant ); 2896pipeline .context = pipeline_decisions ; 2897flash_attn_pipelines [key ]= pipeline ; 2898return flash_attn_pipelines [key ]; 2899 } 2900 2901webgpu_pipeline get_flash_attn_vec_pipeline (const ggml_webgpu_shader_lib_context & context ,bool kv_overlap ) { 2902ggml_webgpu_flash_attn_vec_pipeline_key key = {}; 2903key .common = ggml_webgpu_flash_attn_make_common_pipeline_key (context ,GGML_WEBGPU_FLASH_ATTN_TILE_KV_VEC_WIDTH , 2904kv_overlap ); 2905 2906auto it = flash_attn_vec_pipelines .find (key ); 2907if (it != flash_attn_vec_pipelines .end ()) { 2908return it -> second ; 2909 } 2910 2911ggml_webgpu_flash_attn_vec_decisions decisions = {}; 2912decisions .kv_tile = ggml_webgpu_flash_attn_get_vec_kv_tile (context .wg_mem_limit_bytes ,key .common .head_dim_qk , 2913key .common .head_dim_v ,key .common .has_mask , 2914key .common .k_direct || key .common .v_direct ); 2915decisions .wg_size = context .max_subgroup_size ; 2916 2917 std::string variant = "flash_attn_vec" ; 2918 std::vector < std::string > defines = 2919ggml_webgpu_flash_attn_common_defines (key .common ,variant ,1u ,decisions .kv_tile ,decisions .wg_size ); 2920if (key .common .has_mask ) { 2921defines .push_back ("BLK" ); 2922variant .resize (variant .size ()- (sizeof ("_mask" )- 1 )); 2923variant += "_mask_blk" ; 2924 } 2925 2926uint32_t d_split = context .min_subgroup_size ; 2927const uint32_t D = key .common .head_dim_qk |key .common .head_dim_v ; 2928const uint32_t D_lsb = D & (~(D - 1u )); 2929d_split = std::min (std::min (context .min_subgroup_size ,4u ), std::max (D_lsb /4u ,1u )); 2930 2931defines .push_back (std::string ("D_SPLIT=" )+ std::to_string (d_split )); 2932variant += "_dsplit" + std::to_string (d_split ); 2933 2934auto pipeline_decisions = std::make_shared < ggml_webgpu_flash_attn_vec_decisions > (decisions ); 2935webgpu_pipeline pipeline = 2936ggml_webgpu_create_pipeline (device ,preprocessor .preprocess (wgsl_flash_attn_vec_split ,defines ),variant ); 2937pipeline .context = pipeline_decisions ; 2938flash_attn_vec_pipelines [key ]= pipeline ; 2939return flash_attn_vec_pipelines [key ]; 2940 } 2941 2942webgpu_pipeline get_flash_attn_blk_pipeline (const ggml_webgpu_shader_lib_context & context ,uint32_t kv_tile ) { 2943ggml_webgpu_flash_attn_blk_pipeline_key key = {}; 2944key .kv_tile = kv_tile ; 2945auto it = flash_attn_blk_pipelines .find (key ); 2946if (it != flash_attn_blk_pipelines .end ()) { 2947return it -> second ; 2948 } 2949 2950 std::vector < std::string > defines ; 2951 std::string variant = "flash_attn_vec_blk" ; 2952 2953defines .push_back (std::string ("KV_TILE=" )+ std::to_string (key .kv_tile )); 2954variant += std::string ("_kvt" )+ std::to_string (key .kv_tile ); 2955 2956uint32_t wg_size = 1 ; 2957while ((wg_size <<1 ) <=context .max_wg_size ) { 2958wg_size <<=1 ; 2959 } 2960defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (wg_size )); 2961variant += std::string ("_wg" )+ std::to_string (wg_size ); 2962 2963webgpu_pipeline pipeline = 2964ggml_webgpu_create_pipeline (device ,preprocessor .preprocess (wgsl_flash_attn_vec_blk ,defines ),variant ); 2965flash_attn_blk_pipelines [key ]= pipeline ; 2966return flash_attn_blk_pipelines [key ]; 2967 } 2968 2969webgpu_pipeline get_flash_attn_vec_reduce_pipeline (const ggml_webgpu_shader_lib_context & context ) { 2970ggml_webgpu_flash_attn_vec_reduce_pipeline_key key = {}; 2971key .head_dim_v = (uint32_t )context .src2 -> ne [0 ]; 2972key .dst_type = context .dst -> type ; 2973key .wg_size = context .max_wg_size ; 2974auto it = flash_attn_vec_reduce_pipelines .find (key ); 2975if (it != flash_attn_vec_reduce_pipelines .end ()) { 2976return it -> second ; 2977 } 2978 2979 std::vector < std::string > defines ; 2980 std::string variant = "flash_attn_vec_reduce" ; 2981 2982switch (key .dst_type ) { 2983case GGML_TYPE_F32 : 2984defines .push_back ("DST_F32" ); 2985break ; 2986case GGML_TYPE_F16 : 2987defines .push_back ("DST_F16" ); 2988break ; 2989default : 2990GGML_ABORT ("Unsupported dst type for flash attention vec reduce shader" ); 2991 } 2992variant += std::string ("_dst" )+ ggml_type_name (key .dst_type ); 2993 2994defines .push_back (std::string ("HEAD_DIM_V=" )+ std::to_string (key .head_dim_v )); 2995variant += std::string ("_hsv" )+ std::to_string (key .head_dim_v ); 2996 2997defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 2998variant += std::string ("_wg" )+ std::to_string (context .max_wg_size ); 2999 3000webgpu_pipeline pipeline = 3001ggml_webgpu_create_pipeline (device ,preprocessor .preprocess (wgsl_flash_attn_vec_reduce ,defines ),variant ); 3002flash_attn_vec_reduce_pipelines [key ]= pipeline ; 3003return flash_attn_vec_reduce_pipelines [key ]; 3004 } 3005 3006webgpu_pipeline get_cpy_pipeline (const ggml_webgpu_shader_lib_context & context ) { 3007ggml_webgpu_cpy_pipeline_key key = {}; 3008key .src_type = context .src0 -> type ; 3009key .dst_type = context .dst -> type ; 3010 3011auto it = cpy_pipelines .find (key ); 3012if (it != cpy_pipelines .end ()) { 3013return it -> second ; 3014 } 3015 3016 std::vector < std::string > defines ; 3017 std::string variant = "cpy" ; 3018 3019switch (key .src_type ) { 3020case GGML_TYPE_F32 : 3021defines .push_back ("SRC_F32" ); 3022variant += "_f32" ; 3023break ; 3024case GGML_TYPE_F16 : 3025defines .push_back ("SRC_F16" ); 3026variant += "_f16" ; 3027break ; 3028case GGML_TYPE_I32 : 3029defines .push_back ("SRC_I32" ); 3030variant += "_i32" ; 3031break ; 3032default : 3033GGML_ABORT ("Unsupported src type for cpy shader" ); 3034 } 3035 3036switch (key .dst_type ) { 3037case GGML_TYPE_F32 : 3038defines .push_back ("DST_F32" ); 3039variant += "_f32" ; 3040break ; 3041case GGML_TYPE_F16 : 3042defines .push_back ("DST_F16" ); 3043variant += "_f16" ; 3044break ; 3045case GGML_TYPE_I32 : 3046defines .push_back ("DST_I32" ); 3047variant += "_i32" ; 3048break ; 3049default : 3050GGML_ABORT ("Unsupported dst type for cpy shader" ); 3051 } 3052 3053defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3054 3055auto processed = preprocessor .preprocess (wgsl_cpy ,defines ); 3056auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 3057decisions -> wg_size = context .max_wg_size ; 3058webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3059pipeline .context = decisions ; 3060cpy_pipelines [key ]= pipeline ; 3061return cpy_pipelines [key ]; 3062 } 3063 3064webgpu_pipeline get_glu_pipeline (const ggml_webgpu_shader_lib_context & context ,bool src_overlap ) { 3065ggml_webgpu_glu_pipeline_key key = {}; 3066key .glu_op = ggml_get_glu_op (context .dst ); 3067key .type = context .dst -> type ; 3068key .split = (context .src1 != nullptr ); 3069key .src_overlap = src_overlap ; 3070 3071auto it = glu_pipelines .find (key ); 3072if (it != glu_pipelines .end ()) { 3073return it -> second ; 3074 } 3075 3076 std::vector < std::string > defines ; 3077 std::string variant = "glu" ; 3078 3079switch (key .glu_op ) { 3080case GGML_GLU_OP_REGLU : 3081defines .push_back ("OP_REGLU" ); 3082variant += "_reglu" ; 3083break ; 3084case GGML_GLU_OP_GEGLU : 3085defines .push_back ("OP_GEGLU" ); 3086variant += "_geglu" ; 3087break ; 3088case GGML_GLU_OP_SWIGLU : 3089defines .push_back ("OP_SWIGLU" ); 3090variant += "_swiglu" ; 3091break ; 3092case GGML_GLU_OP_SWIGLU_OAI : 3093defines .push_back ("OP_SWIGLU_OAI" ); 3094variant += "_swiglu_oai" ; 3095break ; 3096case GGML_GLU_OP_GEGLU_ERF : 3097defines .push_back ("OP_GEGLU_ERF" ); 3098variant += "_geglu_erf" ; 3099break ; 3100case GGML_GLU_OP_GEGLU_QUICK : 3101defines .push_back ("OP_GEGLU_QUICK" ); 3102variant += "_geglu_quick" ; 3103break ; 3104case GGML_GLU_OP_SWIGLU_CLAMP : 3105defines .push_back ("OP_SWIGLU_CLAMP" ); 3106variant += "_swiglu_clamp" ; 3107break ; 3108default : 3109GGML_ABORT ("Unsupported GLU op" ); 3110 } 3111switch (key .type ) { 3112case GGML_TYPE_F32 : 3113defines .push_back ("TYPE_F32" ); 3114variant += "_f32" ; 3115break ; 3116case GGML_TYPE_F16 : 3117defines .push_back ("TYPE_F16" ); 3118variant += "_f16" ; 3119break ; 3120default : 3121GGML_ABORT ("Unsupported type for GLU shader" ); 3122 } 3123 3124if (key .src_overlap ) { 3125defines .push_back ("SRC_OVERLAP" ); 3126variant += "_src_overlap" ; 3127 }else if (key .split ) { 3128variant += "_split" ; 3129 }else { 3130defines .push_back ("NO_SPLIT" ); 3131 } 3132 3133defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3134 3135auto processed = preprocessor .preprocess (wgsl_glu ,defines ); 3136auto decisions = std::make_shared < ggml_webgpu_glu_shader_decisions > (); 3137decisions -> wg_size = context .max_wg_size ; 3138decisions -> src_overlap = key .src_overlap ; 3139webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3140pipeline .context = decisions ; 3141glu_pipelines [key ]= pipeline ; 3142return glu_pipelines [key ]; 3143 } 3144 3145webgpu_pipeline get_rope_pipeline (const ggml_webgpu_shader_lib_context & context ) { 3146ggml_webgpu_rope_pipeline_key key = {}; 3147key .type = context .dst -> type ; 3148key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 3149key .has_ff = (context .src2 != nullptr ); 3150 3151auto it = rope_pipelines .find (key ); 3152if (it != rope_pipelines .end ()) { 3153return it -> second ; 3154 } 3155 3156 std::vector < std::string > defines ; 3157 std::string variant = "rope" ; 3158 3159switch (key .type ) { 3160case GGML_TYPE_F32 : 3161defines .push_back ("TYPE_F32" ); 3162variant += "_f32" ; 3163break ; 3164case GGML_TYPE_F16 : 3165defines .push_back ("TYPE_F16" ); 3166variant += "_f16" ; 3167break ; 3168default : 3169GGML_ABORT ("Unsupported type for ROPE shader" ); 3170 } 3171 3172if (key .inplace ) { 3173defines .push_back ("INPLACE" ); 3174variant += "_inplace" ; 3175 } 3176 3177if (key .has_ff ) { 3178defines .push_back ("FF_FUNC" ); 3179variant += "_ff" ; 3180 } 3181 3182defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3183 3184auto processed = preprocessor .preprocess (wgsl_rope ,defines ); 3185auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 3186decisions -> wg_size = context .max_wg_size ; 3187decisions -> inplace = key .inplace ; 3188webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3189pipeline .context = decisions ; 3190rope_pipelines [key ]= pipeline ; 3191return rope_pipelines [key ]; 3192 } 3193 3194webgpu_pipeline get_soft_max_pipeline (const ggml_webgpu_shader_lib_context & context ) { 3195ggml_webgpu_soft_max_pipeline_key key = {}; 3196key .mask_type = context .src1 ?context .src1 -> type :GGML_TYPE_F32 ; 3197key .has_mask = (context .src1 != nullptr ); 3198key .has_sink = (context .src2 != nullptr ); 3199key .inplace = ggml_webgpu_tensor_equal (context .src0 ,context .dst ); 3200 3201auto it = soft_max_pipelines .find (key ); 3202if (it != soft_max_pipelines .end ()) { 3203return it -> second ; 3204 } 3205 3206 std::vector < std::string > defines ; 3207 std::string variant = "soft_max" ; 3208 3209if (key .has_mask ) { 3210defines .push_back ("HAS_MASK" ); 3211switch (key .mask_type ) { 3212case GGML_TYPE_F32 : 3213defines .push_back ("MASK_F32" ); 3214variant += "_mask_f32" ; 3215break ; 3216case GGML_TYPE_F16 : 3217defines .push_back ("MASK_F16" ); 3218variant += "_mask_f16" ; 3219break ; 3220default : 3221GGML_ABORT ("Unsupported type for SOFT_MAX shader" ); 3222 } 3223 } 3224 3225if (key .has_sink ) { 3226defines .push_back ("HAS_SINK" ); 3227variant += "_sink" ; 3228 } 3229 3230if (key .inplace ) { 3231defines .push_back ("INPLACE" ); 3232variant += "_inplace" ; 3233 } 3234 3235defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3236 3237auto processed = preprocessor .preprocess (wgsl_soft_max ,defines ); 3238auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 3239decisions -> wg_size = context .max_wg_size ; 3240decisions -> inplace = key .inplace ; 3241webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3242pipeline .context = decisions ; 3243soft_max_pipelines [key ]= pipeline ; 3244return soft_max_pipelines [key ]; 3245 } 3246 3247webgpu_pipeline get_conv2d_pipeline (const ggml_webgpu_shader_lib_context & context ) { 3248ggml_webgpu_conv2d_pipeline_key key = {}; 3249key .weight_type = context .src0 -> type ; 3250key .input_type = context .src1 -> type ; 3251key .output_type = context .dst -> type ; 3252 3253auto it = conv2d_pipelines .find (key ); 3254if (it != conv2d_pipelines .end ()) { 3255return it -> second ; 3256 } 3257 3258 std::vector < std::string > defines ; 3259 std::string variant = "conv_2d" ; 3260 3261auto push_type_defines = [& ](const char * prefix ,ggml_type type ) { 3262 std::string s_prefix = prefix ; 3263if (type == GGML_TYPE_F32 ) { 3264defines .push_back (s_prefix + "=f32" ); 3265 }else if (type == GGML_TYPE_F16 ) { 3266defines .push_back (s_prefix + "=f16" ); 3267 }else { 3268GGML_ABORT ("Unsupported type for CONV_2D shader" ); 3269 } 3270 }; 3271 3272push_type_defines ("WEIGHT_TYPE" ,key .weight_type ); 3273push_type_defines ("INPUT_TYPE" ,key .input_type ); 3274push_type_defines ("OUTPUT_TYPE" ,key .output_type ); 3275 3276defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3277 3278auto processed = preprocessor .preprocess (wgsl_conv2d ,defines ); 3279auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 3280decisions -> wg_size = context .max_wg_size ; 3281webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3282pipeline .context = decisions ; 3283conv2d_pipelines [key ]= pipeline ; 3284return conv2d_pipelines [key ]; 3285 } 3286 3287// whcn selects the input layout: contiguous WHCN vs contiguous-channels CWHN 3288webgpu_pipeline get_conv2d_dw_pipeline (const ggml_webgpu_shader_lib_context & context ,bool whcn ) { 3289ggml_webgpu_conv2d_dw_pipeline_key key = {}; 3290key .weight_type = context .src0 -> type ; 3291key .input_type = context .src1 -> type ; 3292key .output_type = context .dst -> type ; 3293key .whcn = whcn ; 3294 3295auto it = conv2d_dw_pipelines .find (key ); 3296if (it != conv2d_dw_pipelines .end ()) { 3297return it -> second ; 3298 } 3299 3300 std::vector < std::string > defines ; 3301 std::string variant = whcn ?"conv_2d_dw_whcn" :"conv_2d_dw_cwhn" ; 3302 3303auto push_type_defines = [& ](const char * prefix ,ggml_type type ) { 3304 std::string s_prefix = prefix ; 3305if (type == GGML_TYPE_F32 ) { 3306defines .push_back (s_prefix + "=f32" ); 3307 }else if (type == GGML_TYPE_F16 ) { 3308defines .push_back (s_prefix + "=f16" ); 3309 }else { 3310GGML_ABORT ("Unsupported type for CONV_2D shader" ); 3311 } 3312 }; 3313 3314push_type_defines ("WEIGHT_TYPE" ,key .weight_type ); 3315push_type_defines ("INPUT_TYPE" ,key .input_type ); 3316push_type_defines ("OUTPUT_TYPE" ,key .output_type ); 3317 3318if (whcn ) { 3319defines .push_back ("WHCN" ); 3320 } 3321defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3322 3323auto processed = preprocessor .preprocess (wgsl_conv2d_dw ,defines ); 3324auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 3325decisions -> wg_size = context .max_wg_size ; 3326webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3327pipeline .context = decisions ; 3328conv2d_dw_pipelines [key ]= pipeline ; 3329return conv2d_dw_pipelines [key ]; 3330 } 3331 3332webgpu_pipeline get_im2col_pipeline (const ggml_webgpu_shader_lib_context & context ) { 3333ggml_webgpu_im2col_pipeline_key key = {}; 3334key .input_type = context .src1 -> type ; 3335key .output_type = context .dst -> type ; 3336 3337auto it = im2col_pipelines .find (key ); 3338if (it != im2col_pipelines .end ()) { 3339return it -> second ; 3340 } 3341 3342 std::vector < std::string > defines ; 3343 std::string variant = "im2col" ; 3344 3345auto push_type_defines = [& ](const char * prefix ,ggml_type type ) { 3346 std::string s_prefix = prefix ; 3347if (type == GGML_TYPE_F32 ) { 3348defines .push_back (s_prefix + "=f32" ); 3349 }else if (type == GGML_TYPE_F16 ) { 3350defines .push_back (s_prefix + "=f16" ); 3351 }else { 3352GGML_ABORT ("Unsupported type for IM2COL shader" ); 3353 } 3354 }; 3355 3356push_type_defines ("INPUT_TYPE" ,key .input_type ); 3357push_type_defines ("OUTPUT_TYPE" ,key .output_type ); 3358 3359defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3360 3361auto processed = preprocessor .preprocess (wgsl_im2col ,defines ); 3362auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 3363decisions -> wg_size = context .max_wg_size ; 3364webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3365pipeline .context = decisions ; 3366im2col_pipelines [key ]= pipeline ; 3367return im2col_pipelines [key ]; 3368 } 3369 3370webgpu_pipeline get_upscale_pipeline (const ggml_webgpu_shader_lib_context & context ) { 3371const uint32_t mode_flags = (uint32_t )ggml_get_op_params_i32 (context .dst ,0 ); 3372const uint32_t base_mode = mode_flags & 0xFFu ; 3373const bool antialias = (mode_flags & GGML_SCALE_FLAG_ANTIALIAS )!= 0u ; 3374 3375ggml_webgpu_upscale_pipeline_key key = {}; 3376key .input_type = context .src0 -> type ; 3377key .output_type = context .dst -> type ; 3378key .base_mode = base_mode ; 3379key .antialias = antialias ; 3380 3381auto it = upscale_pipelines .find (key ); 3382if (it != upscale_pipelines .end ()) { 3383return it -> second ; 3384 } 3385 3386 std::vector < std::string > defines ; 3387 std::string variant = "upscale" ; 3388 3389if (key .input_type == GGML_TYPE_F16 ) { 3390defines .push_back ("SRC_F16" ); 3391variant += "_src_f16" ; 3392 }else { 3393variant += "_src_f32" ; 3394 } 3395 3396if (key .output_type == GGML_TYPE_F16 ) { 3397defines .push_back ("DST_F16" ); 3398variant += "_dst_f16" ; 3399 }else { 3400variant += "_dst_f32" ; 3401 } 3402 3403switch (base_mode ) { 3404case GGML_SCALE_MODE_NEAREST : 3405defines .push_back ("NEAREST" ); 3406variant += "_nearest" ; 3407break ; 3408case GGML_SCALE_MODE_BILINEAR : 3409defines .push_back ("BILINEAR" ); 3410variant += "_bilinear" ; 3411break ; 3412case GGML_SCALE_MODE_BICUBIC : 3413defines .push_back ("BICUBIC" ); 3414variant += "_bicubic" ; 3415break ; 3416default : 3417GGML_ABORT ("Unsupported upscale mode" ); 3418 } 3419 3420if (antialias ) { 3421defines .push_back ("ANTIALIAS" ); 3422variant += "_aa" ; 3423 } 3424 3425defines .push_back (std::string ("WG_SIZE=" )+ std::to_string (context .max_wg_size )); 3426 3427auto processed = preprocessor .preprocess (wgsl_upscale ,defines ); 3428auto decisions = std::make_shared < ggml_webgpu_generic_shader_decisions > (); 3429decisions -> wg_size = context .max_wg_size ; 3430webgpu_pipeline pipeline = ggml_webgpu_create_pipeline (device ,processed ,variant ); 3431pipeline .context = decisions ; 3432upscale_pipelines [key ]= pipeline ; 3433return upscale_pipelines [key ]; 3434 } 3435 3436private : 3437static webgpu_pipeline ggml_webgpu_create_pipeline (wgpu::Device & device , 3438 std::string shader_code , 3439 std::string label ) { 3440 wgpu::ShaderSourceWGSL shader_source ; 3441shader_source .code = shader_code .c_str (); 3442 3443 wgpu::ShaderModuleDescriptor shader_desc ; 3444shader_desc .nextInChain = & shader_source ; 3445 3446 wgpu::ShaderModule shader_module = device .CreateShaderModule (& shader_desc ); 3447 3448 wgpu::ComputePipelineDescriptor pipeline_desc ; 3449pipeline_desc .label = label .c_str (); 3450pipeline_desc .compute .module = shader_module ; 3451pipeline_desc .compute .entryPoint = "main" ;// Entry point in the WGSL code 3452pipeline_desc .layout = nullptr ;// nullptr means auto layout 3453return {device .CreateComputePipeline (& pipeline_desc ),label }; 3454 } 3455}; 3456 3457#endif // GGML_WEBGPU_SHADER_LIB_HPP