use super::{DFLASH_THETA, RESIDUAL_RESCALE};
use crate::families::qwen::dflash::{DflashState, DFLASH_RESIDUAL_EPS, DFLASH_WINDOW};
use crate::families::qwen::RMS_EPS;
use crate::real_forward::RealForwardError;
use crate::real_forward_dispatch::encode_gemm_any;
use crate::real_forward_utils::norm_view;
use model_io::ResidentIndex;
#[allow(clippy::too_many_arguments)]
pub(crate) fn encode_dflash_layer(
context: &mut gpu::MetalContext,
pass: &gpu::PassEncoder,
weights: &gpu::ResidentGpuWeights,
index: &ResidentIndex,
dflash: &DflashState,
layer: usize,
base: usize,
rows: usize,
kv_spans: &[(usize, usize)],
use_silu: bool,
) -> Result<(), RealForwardError> {
let s = &dflash.shape;
let hidden = s.hidden;
let q_dim = s.num_heads * s.head_dim;
let kv_dim = s.num_kv_heads * s.head_dim;
let row_bytes = hidden as u64 * 2;
let base_kernel_elems = 2 * 2 * hidden;
let gpu_err = RealForwardError::Gpu;
let name = |sfx: &str| format!("dflash.layers.{layer}.{sfx}");
let input_norm = norm_view(weights, index, &name("input_layernorm.weight"), hidden)?;
let post_norm = norm_view(
weights,
index,
&name("post_attention_layernorm.weight"),
hidden,
)?;
let q_norm = norm_view(weights, index, &name("self_attn.q_norm.weight"), s.head_dim)?;
let k_norm = norm_view(weights, index, &name("self_attn.k_norm.weight"), s.head_dim)?;
let attn_base = norm_view(
weights,
index,
&name("attention_conv.base_kernel"),
base_kernel_elems,
)?;
let mlp_base = norm_view(
weights,
index,
&name("mlp_conv.base_kernel"),
base_kernel_elems,
)?;
for r in 0..rows {
let row = r as u64 * row_bytes;
gpu::encode_rms_norm_bf16w(
context,
pass,
(&dflash.x, row),
input_norm,
(&dflash.normed, row),
hidden as u32,
DFLASH_RESIDUAL_EPS,
)
.map_err(gpu_err)?;
}
encode_gemm_any(
context,
pass,
weights,
index,
&name("attention_conv.kernel_projection.weight"),
s.conv_rows,
hidden,
(&dflash.normed, 0),
(&dflash.coeffs, 0),
rows,
)?;
gpu::encode_dflash_grouped_conv(
context,
pass,
(&dflash.normed, 0),
(&dflash.coeffs, 0),
attn_base,
(&dflash.conv_p, 0),
rows as u32,
hidden as u32,
0,
1.0,
)
.map_err(gpu_err)?;
encode_gemm_any(
context,
pass,
weights,
index,
&name("self_attn.q_proj.weight"),
q_dim,
hidden,
(&dflash.conv_p, 0),
(&dflash.q, 0),
rows,
)?;
for is_k in [true, false] {
let suffix = if is_k {
"self_attn.k_proj.weight"
} else {
"self_attn.v_proj.weight"
};
for &(row0, count) in kv_spans.iter().filter(|s| s.1 > 0) {
let (buf, off) = if is_k {
dflash.kv.k_slot(layer, base + row0)
} else {
dflash.kv.v_slot(layer, base + row0)
};
encode_gemm_any(
context,
pass,
weights,
index,
&name(suffix),
kv_dim,
hidden,
(&dflash.conv_p, (row0 * hidden) as u64 * 2),
(buf, off as u64),
count,
)?;
}
}
for r in 0..rows {
let position = base + r;
let q_row = (r * q_dim) as u64 * 2;
let (k_buf, k_off) = dflash.kv.k_slot(layer, position);
let k_row = k_off as u64;
gpu::encode_rms_norm_bf16w_perhead(
context,
pass,
(&dflash.q, q_row),
q_norm,
(&dflash.q, q_row),
s.num_heads as u32,
s.head_dim as u32,
RMS_EPS,
)
.map_err(gpu_err)?;
gpu::encode_rms_norm_bf16w_perhead(
context,
pass,
(k_buf, k_row),
k_norm,
(k_buf, k_row),
s.num_kv_heads as u32,
s.head_dim as u32,
RMS_EPS,
)
.map_err(gpu_err)?;
for (data, heads) in [
((&dflash.q, q_row), s.num_heads as u32),
((k_buf, k_row), s.num_kv_heads as u32),
] {
gpu::encode_rope_proportional_neox(
context,
pass,
data,
position as u32,
heads,
s.head_dim as u32,
(s.head_dim / 2) as u32,
DFLASH_THETA,
)
.map_err(gpu_err)?;
}
}
let seq_len = (base + rows) as u32;
let kv_start = seq_len.saturating_sub(DFLASH_WINDOW as u32);
let ring = dflash.kv.ring_capacity(layer) as u32;
let active_ring = if ring > 0 && seq_len > ring { ring } else { 0 };
let k_buf = dflash.kv.k_slot(layer, base).0;
let v_buf = dflash.kv.v_slot(layer, base).0;
for r in 0..rows {
let q_row = (r * q_dim) as u64 * 2;
gpu::encode_attention_decode(
context,
pass,
(&dflash.q, q_row),
k_buf,
v_buf,
&dflash.attn,
(&dflash.attn_out, q_row),
s.head_dim as u32,
s.num_heads as u32,
s.num_kv_heads as u32,
seq_len,
kv_start,
active_ring,
(s.head_dim as f32).sqrt().recip(),
None,
)
.map_err(gpu_err)?;
}
encode_gemm_any(
context,
pass,
weights,
index,
&name("self_attn.o_proj.weight"),
hidden,
q_dim,
(&dflash.attn_out, 0),
(&dflash.sub_out, 0),
rows,
)?;
gpu::encode_dflash_grouped_conv(
context,
pass,
(&dflash.sub_out, 0),
(&dflash.coeffs, 0),
attn_base,
(&dflash.conv_f, 0),
rows as u32,
hidden as u32,
1,
RESIDUAL_RESCALE,
)
.map_err(gpu_err)?;
for r in 0..rows {
let row = r as u64 * row_bytes;
gpu::encode_residual_add(
context,
pass,
(&dflash.x, row),
(&dflash.conv_f, row),
hidden as u32,
)
.map_err(gpu_err)?;
gpu::encode_rms_norm_bf16w(
context,
pass,
(&dflash.x, row),
post_norm,
(&dflash.normed, row),
hidden as u32,
DFLASH_RESIDUAL_EPS,
)
.map_err(gpu_err)?;
}
encode_gemm_any(
context,
pass,
weights,
index,
&name("mlp_conv.kernel_projection.weight"),
s.conv_rows,
hidden,
(&dflash.normed, 0),
(&dflash.coeffs, 0),
rows,
)?;
gpu::encode_dflash_grouped_conv(
context,
pass,
(&dflash.normed, 0),
(&dflash.coeffs, 0),
mlp_base,
(&dflash.conv_p, 0),
rows as u32,
hidden as u32,
0,
1.0,
)
.map_err(gpu_err)?;
for (suffix, out) in [
("mlp.gate_proj.weight", &dflash.ffn_gate),
("mlp.up_proj.weight", &dflash.ffn_up),
] {
encode_gemm_any(
context,
pass,
weights,
index,
&name(suffix),
s.inter,
hidden,
(&dflash.conv_p, 0),
(out, 0),
rows,
)?;
}
let act = if use_silu {
gpu::encode_silu_mul
} else {
gpu::encode_gelu_mul
};
for r in 0..rows {
let row = (r * s.inter) as u64 * 2;
act(
context,
pass,
(&dflash.ffn_gate, row),
(&dflash.ffn_up, row),
(&dflash.ffn_act, row),
s.inter as u32,
)
.map_err(gpu_err)?;
}
encode_gemm_any(
context,
pass,
weights,
index,
&name("mlp.down_proj.weight"),
hidden,
s.inter,
(&dflash.ffn_act, 0),
(&dflash.sub_out, 0),
rows,
)?;
gpu::encode_dflash_grouped_conv(
context,
pass,
(&dflash.sub_out, 0),
(&dflash.coeffs, 0),
mlp_base,
(&dflash.conv_f, 0),
rows as u32,
hidden as u32,
1,
RESIDUAL_RESCALE,
)
.map_err(gpu_err)?;
for r in 0..rows {
let row = r as u64 * row_bytes;
gpu::encode_residual_add(
context,
pass,
(&dflash.x, row),
(&dflash.conv_f, row),
hidden as u32,
)
.map_err(gpu_err)?;
}
Ok(())
}