use model_io::ResidentIndex;
use crate::families::qwen::{prefixed_layer_tensor, RealQwenState};
use crate::real_forward_dispatch::encode_gemv_any;
use crate::real_forward_types::{DecodeScratch, RealForwardError};
#[allow(clippy::too_many_arguments)]
pub(crate) fn encode_qwen_layer_dense(
context: &mut gpu::MetalContext,
pass: &gpu::PassEncoder,
weights: &gpu::ResidentGpuWeights,
index: &ResidentIndex,
scratch: &DecodeScratch,
qwen: &RealQwenState,
residual: &gpu::MetalBuffer,
x_off: u64,
prefix: &str,
layer: usize,
hidden: usize,
inter: usize,
use_silu: bool,
) -> Result<(), RealForwardError> {
let gpu_err = RealForwardError::Gpu;
let gate_name = prefixed_layer_tensor(prefix, layer, "mlp.gate_proj.weight");
let ffn_input = match qwen.hadamard.as_ref() {
Some(h) if h.is_folded(&gate_name) => (&h.moe_x_h, 0),
_ => (&qwen.moe_x, 0),
};
for (suffix, out) in [
("mlp.gate_proj.weight", &scratch.ffn_gate),
("mlp.up_proj.weight", &scratch.ffn_up),
] {
encode_gemv_any(
context,
pass,
weights,
index,
&prefixed_layer_tensor(prefix, layer, suffix),
inter,
hidden,
ffn_input,
(out, 0),
)?;
}
let act = if use_silu {
gpu::encode_silu_mul
} else {
gpu::encode_gelu_mul
};
act(
context,
pass,
(&scratch.ffn_gate, 0),
(&scratch.ffn_up, 0),
(&scratch.ffn_act, 0),
inter as u32,
)
.map_err(gpu_err)?;
let down_name = prefixed_layer_tensor(prefix, layer, "mlp.down_proj.weight");
let down_input = match qwen.hadamard.as_ref() {
Some(h) if h.is_folded(&down_name) => {
h.transform(
context,
pass,
(&scratch.ffn_act, 0),
(&h.ffn_act_h, 0),
1,
inter as u32,
true,
)?;
(&h.ffn_act_h, 0)
}
_ => (&scratch.ffn_act, 0),
};
encode_gemv_any(
context,
pass,
weights,
index,
&down_name,
hidden,
inter,
down_input,
(&qwen.h2, 0),
)?;
gpu::encode_residual_add(
context,
pass,
(residual, x_off),
(&qwen.h2, 0),
hidden as u32,
)
.map_err(gpu_err)?;
Ok(())
}