use crate::real_forward_types::RealForwardError;
use crate::vision::scratch::VisionScratch;
use crate::vision::shape::{VisionShape, VISION_LAYER_NORM_EPS};
use crate::vision::weights::{BlockRoles, Role};
#[allow(clippy::too_many_arguments)]
pub(crate) fn encode_block(
context: &mut gpu::MetalContext,
pass: &gpu::PassEncoder,
slot: &gpu::MetalBuffer,
base: u64,
roles: &BlockRoles,
s: &VisionScratch,
shape: &VisionShape,
tile_rows: usize,
) -> Result<(), RealForwardError> {
let seq = s.seq as u32;
let hidden = shape.hidden as u32;
let inter = shape.intermediate as u32;
let wide = (s.seq * shape.hidden) as u32;
let gpu_err = RealForwardError::Gpu;
gpu::encode_vision_layer_norm(
context,
pass,
(&s.x, 0),
(slot, base + roles.at(Role::Ln1W)),
(slot, base + roles.at(Role::Ln1B)),
(&s.normed, 0),
seq,
hidden,
VISION_LAYER_NORM_EPS,
)
.map_err(gpu_err)?;
let row_bytes = (shape.hidden * shape.hidden * 2) as u64;
let bias_bytes = (shape.hidden * 2) as u64;
for (i, out) in [&s.q, &s.k, &s.v].into_iter().enumerate() {
gpu::encode_vision_matmul(
context,
pass,
(&s.normed, 0),
(slot, base + roles.at(Role::QkvW) + i as u64 * row_bytes),
Some((slot, base + roles.at(Role::QkvB) + i as u64 * bias_bytes)),
(out, 0),
seq,
hidden,
hidden,
)
.map_err(gpu_err)?;
}
for target in [&s.q, &s.k] {
gpu::encode_vision_rope_2d(
context,
pass,
(target, 0),
(&s.freqs, 0),
seq,
shape.heads as u32,
shape.head_dim as u32,
)
.map_err(gpu_err)?;
}
gpu::encode_vision_attention(
context,
pass,
(&s.q, 0),
(&s.k, 0),
(&s.v, 0),
(&s.attn, 0),
seq,
shape.heads as u32,
shape.head_dim as u32,
shape.attention_scale(),
)
.map_err(gpu_err)?;
gpu::encode_vision_matmul(
context,
pass,
(&s.attn, 0),
(slot, base + roles.at(Role::ProjW)),
Some((slot, base + roles.at(Role::ProjB))),
(&s.proj, 0),
seq,
hidden,
hidden,
)
.map_err(gpu_err)?;
gpu::encode_vision_residual_add(context, pass, (&s.x, 0), (&s.proj, 0), wide)
.map_err(gpu_err)?;
gpu::encode_vision_layer_norm(
context,
pass,
(&s.x, 0),
(slot, base + roles.at(Role::Ln2W)),
(slot, base + roles.at(Role::Ln2B)),
(&s.normed, 0),
seq,
hidden,
VISION_LAYER_NORM_EPS,
)
.map_err(gpu_err)?;
let tile = tile_rows.max(1);
let mut t0 = 0usize;
while t0 < s.seq {
let rows = tile.min(s.seq - t0);
let row_off = (t0 * shape.hidden * 2) as u64;
gpu::encode_vision_matmul(
context,
pass,
(&s.normed, row_off),
(slot, base + roles.at(Role::Fc1W)),
Some((slot, base + roles.at(Role::Fc1B))),
(&s.h1, 0),
rows as u32,
hidden,
inter,
)
.map_err(gpu_err)?;
gpu::encode_vision_gelu(
context,
pass,
(&s.h1, 0),
(rows * shape.intermediate) as u32,
gpu::GeluKind::Tanh,
)
.map_err(gpu_err)?;
gpu::encode_vision_matmul(
context,
pass,
(&s.h1, 0),
(slot, base + roles.at(Role::Fc2W)),
Some((slot, base + roles.at(Role::Fc2B))),
(&s.proj, row_off),
rows as u32,
inter,
hidden,
)
.map_err(gpu_err)?;
t0 += rows;
}
gpu::encode_vision_residual_add(context, pass, (&s.x, 0), (&s.proj, 0), wide)
.map_err(gpu_err)?;
Ok(())
}