use alloc::vec::Vec;
use super::{
ast::StructLayout,
error::{Error, ErrorKind},
Span,
};
use crate::{proc::Alignment, Handle, Scalar, Type, TypeInner, UniqueArena};
#[derive(Debug)]
pub struct TypeAlignSpan {
pub ty: Handle<Type>,
pub align: Alignment,
pub span: u32,
}
pub fn calculate_offset(
mut ty: Handle<Type>,
meta: Span,
layout: StructLayout,
types: &mut UniqueArena<Type>,
errors: &mut Vec<Error>,
) -> TypeAlignSpan {
let (align, span) = match types[ty].inner {
TypeInner::Scalar(Scalar { width, .. }) => (Alignment::from_width(width), width as u32),
TypeInner::Vector {
size,
scalar: Scalar { width, .. },
} => (
Alignment::from(size) * Alignment::from_width(width),
size as u32 * width as u32,
),
TypeInner::Array { base, size, .. } => {
let info = calculate_offset(base, meta, layout, types, errors);
let name = types[ty].name.clone();
let (align, stride) = if StructLayout::Std430 == layout {
(info.align, info.align.round_up(info.span))
} else {
let align = info.align.max(Alignment::MIN_UNIFORM);
(align, align.round_up(info.span))
};
let span = match size {
crate::ArraySize::Constant(size) => size.get() * stride,
crate::ArraySize::Pending(_) => unreachable!(),
crate::ArraySize::Dynamic => stride,
};
let ty_span = types.get_span(ty);
ty = types.insert(
Type {
name,
inner: TypeInner::Array {
base: info.ty,
size,
stride,
},
},
ty_span,
);
(align, span)
}
TypeInner::Matrix {
columns,
rows,
scalar,
} => {
let mut align = Alignment::from(rows) * Alignment::from_width(scalar.width);
if StructLayout::Std430 != layout {
align = align.max(Alignment::MIN_UNIFORM);
}
if StructLayout::Std140 == layout {
if scalar == Scalar::F16 {
errors.push(Error {
kind: ErrorKind::UnsupportedF16MatrixInStd140 {
columns: columns as u8,
rows: rows as u8,
},
meta,
});
}
if rows == crate::VectorSize::Bi {
errors.push(Error {
kind: ErrorKind::UnsupportedMatrixWithTwoRowsInStd140 {
columns: columns as u8,
},
meta,
});
}
}
(align, align * columns as u32)
}
TypeInner::Struct { ref members, .. } => {
let mut span = 0;
let mut align = Alignment::ONE;
let mut members = members.clone();
let name = types[ty].name.clone();
for member in members.iter_mut() {
let info = calculate_offset(member.ty, meta, layout, types, errors);
let member_alignment = info.align;
span = member_alignment.round_up(span);
align = member_alignment.max(align);
member.ty = info.ty;
member.offset = span;
span += info.span;
}
span = align.round_up(span);
let ty_span = types.get_span(ty);
ty = types.insert(
Type {
name,
inner: TypeInner::Struct { members, span },
},
ty_span,
);
(align, span)
}
_ => {
errors.push(Error {
kind: ErrorKind::SemanticError("Invalid struct member type".into()),
meta,
});
(Alignment::ONE, 0)
}
};
TypeAlignSpan { ty, align, span }
}