mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
hlsl: factor storage logic into a separate module
This commit is contained in:
committed by
Dzmitry Malyshau
parent
284cfcce47
commit
e7502d0a9b
@@ -21,7 +21,7 @@
|
||||
// int dim_1d = NagaDimensions1D(image_1d);
|
||||
// ```
|
||||
|
||||
use super::{super::FunctionCtx, writer::BackendResult};
|
||||
use super::{super::FunctionCtx, BackendResult};
|
||||
use crate::arena::Handle;
|
||||
use std::fmt::Write;
|
||||
|
||||
|
||||
@@ -9,12 +9,13 @@
|
||||
mod conv;
|
||||
mod help;
|
||||
mod keywords;
|
||||
mod storage;
|
||||
mod writer;
|
||||
|
||||
use std::fmt::Error as FmtError;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use writer::Writer;
|
||||
use crate::proc;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
@@ -69,6 +70,9 @@ impl crate::ImageDimension {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shorthand result used internally by the backend
|
||||
type BackendResult = Result<(), Error>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
|
||||
@@ -138,3 +142,18 @@ pub enum Error {
|
||||
#[error("{0}")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
pub struct Writer<'a, W> {
|
||||
out: W,
|
||||
names: crate::FastHashMap<proc::NameKey, String>,
|
||||
namer: proc::Namer,
|
||||
/// HLSL backend options
|
||||
options: &'a Options,
|
||||
/// Information about entry point arguments wrapped into structure
|
||||
ep_inputs: Vec<Option<writer::EntryPointBinding>>,
|
||||
/// Set of expressions that have associated temporary variables
|
||||
named_expressions: crate::NamedExpressions,
|
||||
wrapped_array_lengths: crate::FastHashSet<help::WrappedArrayLength>,
|
||||
wrapped_image_queries: crate::FastHashSet<help::WrappedImageQuery>,
|
||||
temp_access_chain: Vec<storage::SubAccess>,
|
||||
}
|
||||
|
||||
395
src/back/hlsl/storage.rs
Normal file
395
src/back/hlsl/storage.rs
Normal file
@@ -0,0 +1,395 @@
|
||||
use super::{
|
||||
super::{FunctionCtx, INDENT},
|
||||
BackendResult, Error,
|
||||
};
|
||||
use crate::{
|
||||
proc::{NameKey, TypeResolution},
|
||||
Handle,
|
||||
};
|
||||
|
||||
use std::{fmt, mem};
|
||||
|
||||
const STORE_TEMP_NAME: &str = "_value";
|
||||
|
||||
pub(super) enum SubAccess {
|
||||
Offset(u32),
|
||||
Index {
|
||||
value: Handle<crate::Expression>,
|
||||
stride: u32,
|
||||
},
|
||||
}
|
||||
|
||||
pub(super) enum StoreValue {
|
||||
Expression(Handle<crate::Expression>),
|
||||
TempIndex {
|
||||
depth: usize,
|
||||
index: u32,
|
||||
ty: TypeResolution,
|
||||
},
|
||||
TempAccess {
|
||||
depth: usize,
|
||||
base: Handle<crate::Type>,
|
||||
member_index: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl<W: fmt::Write> super::Writer<'_, W> {
|
||||
fn write_storage_address(
|
||||
&mut self,
|
||||
module: &crate::Module,
|
||||
chain: &[SubAccess],
|
||||
func_ctx: &FunctionCtx,
|
||||
) -> BackendResult {
|
||||
for (i, access) in chain.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(self.out, "+")?;
|
||||
}
|
||||
match *access {
|
||||
SubAccess::Offset(offset) => {
|
||||
write!(self.out, "{}", offset)?;
|
||||
}
|
||||
SubAccess::Index { value, stride } => {
|
||||
self.write_expr(module, value, func_ctx)?;
|
||||
write!(self.out, "*{}", stride)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_storage_load_sequence<I: Iterator<Item = (TypeResolution, u32)>>(
|
||||
&mut self,
|
||||
module: &crate::Module,
|
||||
var_handle: Handle<crate::GlobalVariable>,
|
||||
sequence: I,
|
||||
func_ctx: &FunctionCtx,
|
||||
) -> BackendResult {
|
||||
for (i, (ty_resolution, offset)) in sequence.enumerate() {
|
||||
// add the index temporarily
|
||||
self.temp_access_chain.push(SubAccess::Offset(offset));
|
||||
if i != 0 {
|
||||
write!(self.out, ", ")?;
|
||||
};
|
||||
self.write_storage_load(module, var_handle, ty_resolution, func_ctx)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper function to write down the Load operation on a `ByteAddressBuffer`.
|
||||
pub(super) fn write_storage_load(
|
||||
&mut self,
|
||||
module: &crate::Module,
|
||||
var_handle: Handle<crate::GlobalVariable>,
|
||||
result_ty: TypeResolution,
|
||||
func_ctx: &FunctionCtx,
|
||||
) -> BackendResult {
|
||||
match *result_ty.inner_with(&module.types) {
|
||||
crate::TypeInner::Scalar { kind, width: _ } => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
let cast = kind.to_hlsl_cast();
|
||||
write!(self.out, "{}({}.Load(", cast, var_name)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, "))")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
crate::TypeInner::Vector {
|
||||
size,
|
||||
kind,
|
||||
width: _,
|
||||
} => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
let cast = kind.to_hlsl_cast();
|
||||
write!(self.out, "{}({}.Load{}(", cast, var_name, size as u8)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, "))")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
crate::TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
write!(
|
||||
self.out,
|
||||
"{}{}x{}(",
|
||||
crate::ScalarKind::Float.to_hlsl_str(width)?,
|
||||
columns as u8,
|
||||
rows as u8,
|
||||
)?;
|
||||
let row_stride = width as u32 * rows as u32;
|
||||
let iter = (0..columns as u32).map(|i| {
|
||||
let ty_inner = crate::TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width,
|
||||
};
|
||||
(TypeResolution::Value(ty_inner), i * row_stride)
|
||||
});
|
||||
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
|
||||
write!(self.out, ")")?;
|
||||
}
|
||||
crate::TypeInner::Array {
|
||||
base,
|
||||
size: crate::ArraySize::Constant(const_handle),
|
||||
..
|
||||
} => {
|
||||
write!(self.out, "{{")?;
|
||||
let count = module.constants[const_handle].to_array_length().unwrap();
|
||||
let stride = module.types[base].inner.span(&module.constants);
|
||||
let iter = (0..count).map(|i| (TypeResolution::Handle(base), stride * i));
|
||||
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
|
||||
write!(self.out, "}}")?;
|
||||
}
|
||||
crate::TypeInner::Struct { ref members, .. } => {
|
||||
write!(self.out, "{{")?;
|
||||
let iter = members
|
||||
.iter()
|
||||
.map(|m| (TypeResolution::Handle(m.ty), m.offset));
|
||||
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
|
||||
write!(self.out, "}}")?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_store_value(
|
||||
&mut self,
|
||||
module: &crate::Module,
|
||||
value: &StoreValue,
|
||||
func_ctx: &FunctionCtx,
|
||||
) -> BackendResult {
|
||||
match *value {
|
||||
StoreValue::Expression(expr) => self.write_expr(module, expr, &func_ctx)?,
|
||||
StoreValue::TempIndex {
|
||||
depth,
|
||||
index,
|
||||
ty: _,
|
||||
} => write!(self.out, "{}{}[{}]", STORE_TEMP_NAME, depth, index)?,
|
||||
StoreValue::TempAccess {
|
||||
depth,
|
||||
base,
|
||||
member_index,
|
||||
} => {
|
||||
let name = &self.names[&NameKey::StructMember(base, member_index)];
|
||||
write!(self.out, "{}{}.{}", STORE_TEMP_NAME, depth, name)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper function to write down the Store operation on a `ByteAddressBuffer`.
|
||||
pub(super) fn write_storage_store(
|
||||
&mut self,
|
||||
module: &crate::Module,
|
||||
var_handle: Handle<crate::GlobalVariable>,
|
||||
value: StoreValue,
|
||||
func_ctx: &FunctionCtx,
|
||||
indent: usize,
|
||||
) -> BackendResult {
|
||||
let temp_resolution;
|
||||
let ty_resolution = match value {
|
||||
StoreValue::Expression(expr) => &func_ctx.info[expr].ty,
|
||||
StoreValue::TempIndex {
|
||||
depth: _,
|
||||
index: _,
|
||||
ref ty,
|
||||
} => ty,
|
||||
StoreValue::TempAccess {
|
||||
depth: _,
|
||||
base,
|
||||
member_index,
|
||||
} => {
|
||||
let ty_handle = match module.types[base].inner {
|
||||
crate::TypeInner::Struct { ref members, .. } => {
|
||||
members[member_index as usize].ty
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
temp_resolution = TypeResolution::Handle(ty_handle);
|
||||
&temp_resolution
|
||||
}
|
||||
};
|
||||
match *ty_resolution.inner_with(&module.types) {
|
||||
crate::TypeInner::Scalar { .. } => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
write!(self.out, "{}{}.Store(", INDENT.repeat(indent), var_name)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, ", asuint(")?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, "));")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
crate::TypeInner::Vector { size, .. } => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
write!(
|
||||
self.out,
|
||||
"{}{}.Store{}(",
|
||||
INDENT.repeat(indent),
|
||||
var_name,
|
||||
size as u8
|
||||
)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, ", asuint(")?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, "));")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
crate::TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
// first, assign the value to a temporary
|
||||
writeln!(self.out, "{}{{", INDENT.repeat(indent))?;
|
||||
let depth = indent + 1;
|
||||
write!(
|
||||
self.out,
|
||||
"{}{}{}x{} {}{} = ",
|
||||
INDENT.repeat(indent + 1),
|
||||
crate::ScalarKind::Float.to_hlsl_str(width)?,
|
||||
columns as u8,
|
||||
rows as u8,
|
||||
STORE_TEMP_NAME,
|
||||
depth,
|
||||
)?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, ";")?;
|
||||
// then iterate the stores
|
||||
let row_stride = width as u32 * rows as u32;
|
||||
for i in 0..columns as u32 {
|
||||
self.temp_access_chain
|
||||
.push(SubAccess::Offset(i * row_stride));
|
||||
let ty_inner = crate::TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width,
|
||||
};
|
||||
let sv = StoreValue::TempIndex {
|
||||
depth,
|
||||
index: i,
|
||||
ty: TypeResolution::Value(ty_inner),
|
||||
};
|
||||
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
// done
|
||||
writeln!(self.out, "{}}}", INDENT.repeat(indent))?;
|
||||
}
|
||||
crate::TypeInner::Array {
|
||||
base,
|
||||
size: crate::ArraySize::Constant(const_handle),
|
||||
..
|
||||
} => {
|
||||
// first, assign the value to a temporary
|
||||
writeln!(self.out, "{}{{", INDENT.repeat(indent))?;
|
||||
write!(self.out, "{}", INDENT.repeat(indent + 1))?;
|
||||
self.write_value_type(module, &module.types[base].inner)?;
|
||||
let depth = indent + 1;
|
||||
write!(self.out, " {}{}", STORE_TEMP_NAME, depth)?;
|
||||
self.write_array_size(module, crate::ArraySize::Constant(const_handle))?;
|
||||
write!(self.out, " = ")?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, ";")?;
|
||||
// then iterate the stores
|
||||
let count = module.constants[const_handle].to_array_length().unwrap();
|
||||
let stride = module.types[base].inner.span(&module.constants);
|
||||
for i in 0..count {
|
||||
self.temp_access_chain.push(SubAccess::Offset(i * stride));
|
||||
let sv = StoreValue::TempIndex {
|
||||
depth,
|
||||
index: i,
|
||||
ty: TypeResolution::Handle(base),
|
||||
};
|
||||
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
// done
|
||||
writeln!(self.out, "{}}}", INDENT.repeat(indent))?;
|
||||
}
|
||||
crate::TypeInner::Struct { ref members, .. } => {
|
||||
// first, assign the value to a temporary
|
||||
writeln!(self.out, "{}{{", INDENT.repeat(indent))?;
|
||||
let depth = indent + 1;
|
||||
let struct_ty = ty_resolution.handle().unwrap();
|
||||
let struct_name = &self.names[&NameKey::Type(struct_ty)];
|
||||
write!(
|
||||
self.out,
|
||||
"{}{} {}{} = ",
|
||||
INDENT.repeat(indent + 1),
|
||||
struct_name,
|
||||
STORE_TEMP_NAME,
|
||||
depth
|
||||
)?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, ";")?;
|
||||
// then iterate the stores
|
||||
for (i, member) in members.iter().enumerate() {
|
||||
self.temp_access_chain
|
||||
.push(SubAccess::Offset(member.offset));
|
||||
let sv = StoreValue::TempAccess {
|
||||
depth,
|
||||
base: struct_ty,
|
||||
member_index: i as u32,
|
||||
};
|
||||
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
// done
|
||||
writeln!(self.out, "{}}}", INDENT.repeat(indent))?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn fill_access_chain(
|
||||
&mut self,
|
||||
module: &crate::Module,
|
||||
mut cur_expr: Handle<crate::Expression>,
|
||||
func_ctx: &FunctionCtx,
|
||||
) -> Result<Handle<crate::GlobalVariable>, Error> {
|
||||
self.temp_access_chain.clear();
|
||||
loop {
|
||||
let stride = func_ctx.info[cur_expr]
|
||||
.ty
|
||||
.inner_with(&module.types)
|
||||
.span(&module.constants);
|
||||
let (next_expr, sub) = match func_ctx.expressions[cur_expr] {
|
||||
crate::Expression::GlobalVariable(handle) => return Ok(handle),
|
||||
crate::Expression::Access { base, index } => (
|
||||
base,
|
||||
SubAccess::Index {
|
||||
value: index,
|
||||
stride,
|
||||
},
|
||||
),
|
||||
crate::Expression::AccessIndex { base, index } => {
|
||||
match *func_ctx.info[base].ty.inner_with(&module.types) {
|
||||
crate::TypeInner::Struct { ref members, .. } => {
|
||||
(base, SubAccess::Offset(members[index as usize].offset))
|
||||
}
|
||||
_ => (base, SubAccess::Offset(index * stride)),
|
||||
}
|
||||
}
|
||||
ref other => {
|
||||
return Err(Error::Unimplemented(format!(
|
||||
"Pointer access of {:?}",
|
||||
other
|
||||
)))
|
||||
}
|
||||
};
|
||||
self.temp_access_chain.push(sub);
|
||||
cur_expr = next_expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,20 @@
|
||||
use super::{
|
||||
help::{MipLevelCoordinate, WrappedArrayLength, WrappedImageQuery},
|
||||
Error, Options,
|
||||
storage::StoreValue,
|
||||
BackendResult, Error, Options,
|
||||
};
|
||||
use crate::{
|
||||
back,
|
||||
proc::{self, NameKey},
|
||||
valid, Handle, Module, ShaderStage, TypeInner,
|
||||
};
|
||||
use std::{fmt, mem};
|
||||
use std::fmt;
|
||||
|
||||
const LOCATION_SEMANTIC: &str = "LOC";
|
||||
const STORE_TEMP_NAME: &str = "_value";
|
||||
|
||||
/// Shorthand result used internally by the backend
|
||||
pub(super) type BackendResult = Result<(), Error>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum Io {
|
||||
Input,
|
||||
Output,
|
||||
}
|
||||
|
||||
enum SubAccess {
|
||||
Offset(u32),
|
||||
Index {
|
||||
value: Handle<crate::Expression>,
|
||||
stride: u32,
|
||||
},
|
||||
}
|
||||
|
||||
enum StoreValue {
|
||||
Expression(Handle<crate::Expression>),
|
||||
TempIndex {
|
||||
depth: usize,
|
||||
index: u32,
|
||||
ty: proc::TypeResolution,
|
||||
},
|
||||
TempAccess {
|
||||
depth: usize,
|
||||
base: Handle<crate::Type>,
|
||||
member_index: u32,
|
||||
},
|
||||
}
|
||||
|
||||
/// Structure contains information required for generating
|
||||
/// wrapped structure of all entry points arguments
|
||||
struct EntryPointBinding {
|
||||
pub(super) struct EntryPointBinding {
|
||||
/// Generated structure name
|
||||
name: String,
|
||||
/// Members of generated structure
|
||||
@@ -53,27 +22,18 @@ struct EntryPointBinding {
|
||||
}
|
||||
|
||||
struct EpStructMember {
|
||||
pub name: String,
|
||||
pub ty: Handle<crate::Type>,
|
||||
pub binding: Option<crate::Binding>,
|
||||
name: String,
|
||||
ty: Handle<crate::Type>,
|
||||
binding: Option<crate::Binding>,
|
||||
}
|
||||
|
||||
pub struct Writer<'a, W> {
|
||||
pub(super) out: W,
|
||||
names: crate::FastHashMap<NameKey, String>,
|
||||
namer: proc::Namer,
|
||||
/// HLSL backend options
|
||||
options: &'a Options,
|
||||
/// Information about entry point arguments wrapped into structure
|
||||
ep_inputs: Vec<Option<EntryPointBinding>>,
|
||||
/// Set of expressions that have associated temporary variables
|
||||
named_expressions: crate::NamedExpressions,
|
||||
pub(super) wrapped_array_lengths: crate::FastHashSet<WrappedArrayLength>,
|
||||
pub(super) wrapped_image_queries: crate::FastHashSet<WrappedImageQuery>,
|
||||
temp_access_chain: Vec<SubAccess>,
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum Io {
|
||||
Input,
|
||||
Output,
|
||||
}
|
||||
|
||||
impl<'a, W: fmt::Write> Writer<'a, W> {
|
||||
impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
pub fn new(out: W, options: &'a Options) -> Self {
|
||||
Self {
|
||||
out,
|
||||
@@ -524,8 +484,11 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// copy-paste from glsl-out
|
||||
fn write_array_size(&mut self, module: &Module, size: crate::ArraySize) -> BackendResult {
|
||||
pub(super) fn write_array_size(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
size: crate::ArraySize,
|
||||
) -> BackendResult {
|
||||
write!(self.out, "[")?;
|
||||
|
||||
// Write the array size
|
||||
@@ -1788,366 +1751,4 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_storage_address(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
chain: &[SubAccess],
|
||||
func_ctx: &back::FunctionCtx<'_>,
|
||||
) -> BackendResult {
|
||||
for (i, access) in chain.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(self.out, "+")?;
|
||||
}
|
||||
match *access {
|
||||
SubAccess::Offset(offset) => {
|
||||
write!(self.out, "{}", offset)?;
|
||||
}
|
||||
SubAccess::Index { value, stride } => {
|
||||
self.write_expr(module, value, func_ctx)?;
|
||||
write!(self.out, "*{}", stride)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_storage_load_sequence<I: Iterator<Item = (proc::TypeResolution, u32)>>(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
var_handle: Handle<crate::GlobalVariable>,
|
||||
sequence: I,
|
||||
func_ctx: &back::FunctionCtx<'_>,
|
||||
) -> BackendResult {
|
||||
for (i, (ty_resolution, offset)) in sequence.enumerate() {
|
||||
// add the index temporarily
|
||||
self.temp_access_chain.push(SubAccess::Offset(offset));
|
||||
if i != 0 {
|
||||
write!(self.out, ", ")?;
|
||||
};
|
||||
self.write_storage_load(module, var_handle, ty_resolution, func_ctx)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper function to write down the Load operation on a `ByteAddressBuffer`.
|
||||
fn write_storage_load(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
var_handle: Handle<crate::GlobalVariable>,
|
||||
result_ty: proc::TypeResolution,
|
||||
func_ctx: &back::FunctionCtx<'_>,
|
||||
) -> BackendResult {
|
||||
match *result_ty.inner_with(&module.types) {
|
||||
TypeInner::Scalar { kind, width: _ } => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
let cast = kind.to_hlsl_cast();
|
||||
write!(self.out, "{}({}.Load(", cast, var_name)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, "))")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
TypeInner::Vector {
|
||||
size,
|
||||
kind,
|
||||
width: _,
|
||||
} => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
let cast = kind.to_hlsl_cast();
|
||||
write!(self.out, "{}({}.Load{}(", cast, var_name, size as u8)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, "))")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
write!(
|
||||
self.out,
|
||||
"{}{}x{}(",
|
||||
crate::ScalarKind::Float.to_hlsl_str(width)?,
|
||||
columns as u8,
|
||||
rows as u8,
|
||||
)?;
|
||||
let row_stride = width as u32 * rows as u32;
|
||||
let iter = (0..columns as u32).map(|i| {
|
||||
let ty_inner = TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width,
|
||||
};
|
||||
(proc::TypeResolution::Value(ty_inner), i * row_stride)
|
||||
});
|
||||
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
|
||||
write!(self.out, ")")?;
|
||||
}
|
||||
TypeInner::Array {
|
||||
base,
|
||||
size: crate::ArraySize::Constant(const_handle),
|
||||
..
|
||||
} => {
|
||||
write!(self.out, "{{")?;
|
||||
let count = module.constants[const_handle].to_array_length().unwrap();
|
||||
let stride = module.types[base].inner.span(&module.constants);
|
||||
let iter = (0..count).map(|i| (proc::TypeResolution::Handle(base), stride * i));
|
||||
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
|
||||
write!(self.out, "}}")?;
|
||||
}
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
write!(self.out, "{{")?;
|
||||
let iter = members
|
||||
.iter()
|
||||
.map(|m| (proc::TypeResolution::Handle(m.ty), m.offset));
|
||||
self.write_storage_load_sequence(module, var_handle, iter, func_ctx)?;
|
||||
write!(self.out, "}}")?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_store_value(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
value: &StoreValue,
|
||||
func_ctx: &back::FunctionCtx,
|
||||
) -> BackendResult {
|
||||
match *value {
|
||||
StoreValue::Expression(expr) => self.write_expr(module, expr, &func_ctx)?,
|
||||
StoreValue::TempIndex {
|
||||
depth,
|
||||
index,
|
||||
ty: _,
|
||||
} => write!(self.out, "{}{}[{}]", STORE_TEMP_NAME, depth, index)?,
|
||||
StoreValue::TempAccess {
|
||||
depth,
|
||||
base,
|
||||
member_index,
|
||||
} => {
|
||||
let name = &self.names[&NameKey::StructMember(base, member_index)];
|
||||
write!(self.out, "{}{}.{}", STORE_TEMP_NAME, depth, name)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper function to write down the Store operation on a `ByteAddressBuffer`.
|
||||
fn write_storage_store(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
var_handle: Handle<crate::GlobalVariable>,
|
||||
value: StoreValue,
|
||||
func_ctx: &back::FunctionCtx<'_>,
|
||||
indent: usize,
|
||||
) -> BackendResult {
|
||||
let temp_resolution;
|
||||
let ty_resolution = match value {
|
||||
StoreValue::Expression(expr) => &func_ctx.info[expr].ty,
|
||||
StoreValue::TempIndex {
|
||||
depth: _,
|
||||
index: _,
|
||||
ref ty,
|
||||
} => ty,
|
||||
StoreValue::TempAccess {
|
||||
depth: _,
|
||||
base,
|
||||
member_index,
|
||||
} => {
|
||||
let ty_handle = match module.types[base].inner {
|
||||
TypeInner::Struct { ref members, .. } => members[member_index as usize].ty,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
temp_resolution = proc::TypeResolution::Handle(ty_handle);
|
||||
&temp_resolution
|
||||
}
|
||||
};
|
||||
match *ty_resolution.inner_with(&module.types) {
|
||||
TypeInner::Scalar { .. } => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
write!(
|
||||
self.out,
|
||||
"{}{}.Store(",
|
||||
back::INDENT.repeat(indent),
|
||||
var_name
|
||||
)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, ", asuint(")?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, "));")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
TypeInner::Vector { size, .. } => {
|
||||
// working around the borrow checker in `self.write_expr`
|
||||
let chain = mem::take(&mut self.temp_access_chain);
|
||||
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
|
||||
write!(
|
||||
self.out,
|
||||
"{}{}.Store{}(",
|
||||
back::INDENT.repeat(indent),
|
||||
var_name,
|
||||
size as u8
|
||||
)?;
|
||||
self.write_storage_address(module, &chain, func_ctx)?;
|
||||
write!(self.out, ", asuint(")?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, "));")?;
|
||||
self.temp_access_chain = chain;
|
||||
}
|
||||
TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
// first, assign the value to a temporary
|
||||
writeln!(self.out, "{}{{", back::INDENT.repeat(indent))?;
|
||||
let depth = indent + 1;
|
||||
write!(
|
||||
self.out,
|
||||
"{}{}{}x{} {}{} = ",
|
||||
back::INDENT.repeat(indent + 1),
|
||||
crate::ScalarKind::Float.to_hlsl_str(width)?,
|
||||
columns as u8,
|
||||
rows as u8,
|
||||
STORE_TEMP_NAME,
|
||||
depth,
|
||||
)?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, ";")?;
|
||||
// then iterate the stores
|
||||
let row_stride = width as u32 * rows as u32;
|
||||
for i in 0..columns as u32 {
|
||||
self.temp_access_chain
|
||||
.push(SubAccess::Offset(i * row_stride));
|
||||
let ty_inner = TypeInner::Vector {
|
||||
size: rows,
|
||||
kind: crate::ScalarKind::Float,
|
||||
width,
|
||||
};
|
||||
let sv = StoreValue::TempIndex {
|
||||
depth,
|
||||
index: i,
|
||||
ty: proc::TypeResolution::Value(ty_inner),
|
||||
};
|
||||
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
// done
|
||||
writeln!(self.out, "{}}}", back::INDENT.repeat(indent))?;
|
||||
}
|
||||
TypeInner::Array {
|
||||
base,
|
||||
size: crate::ArraySize::Constant(const_handle),
|
||||
..
|
||||
} => {
|
||||
// first, assign the value to a temporary
|
||||
writeln!(self.out, "{}{{", back::INDENT.repeat(indent))?;
|
||||
write!(self.out, "{}", back::INDENT.repeat(indent + 1))?;
|
||||
self.write_value_type(module, &module.types[base].inner)?;
|
||||
let depth = indent + 1;
|
||||
write!(self.out, " {}{}", STORE_TEMP_NAME, depth)?;
|
||||
self.write_array_size(module, crate::ArraySize::Constant(const_handle))?;
|
||||
write!(self.out, " = ")?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, ";")?;
|
||||
// then iterate the stores
|
||||
let count = module.constants[const_handle].to_array_length().unwrap();
|
||||
let stride = module.types[base].inner.span(&module.constants);
|
||||
for i in 0..count {
|
||||
self.temp_access_chain.push(SubAccess::Offset(i * stride));
|
||||
let sv = StoreValue::TempIndex {
|
||||
depth,
|
||||
index: i,
|
||||
ty: proc::TypeResolution::Handle(base),
|
||||
};
|
||||
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
// done
|
||||
writeln!(self.out, "{}}}", back::INDENT.repeat(indent))?;
|
||||
}
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
// first, assign the value to a temporary
|
||||
writeln!(self.out, "{}{{", back::INDENT.repeat(indent))?;
|
||||
let depth = indent + 1;
|
||||
let struct_ty = ty_resolution.handle().unwrap();
|
||||
let struct_name = &self.names[&NameKey::Type(struct_ty)];
|
||||
write!(
|
||||
self.out,
|
||||
"{}{} {}{} = ",
|
||||
back::INDENT.repeat(indent + 1),
|
||||
struct_name,
|
||||
STORE_TEMP_NAME,
|
||||
depth
|
||||
)?;
|
||||
self.write_store_value(module, &value, func_ctx)?;
|
||||
writeln!(self.out, ";")?;
|
||||
// then iterate the stores
|
||||
for (i, member) in members.iter().enumerate() {
|
||||
self.temp_access_chain
|
||||
.push(SubAccess::Offset(member.offset));
|
||||
let sv = StoreValue::TempAccess {
|
||||
depth,
|
||||
base: struct_ty,
|
||||
member_index: i as u32,
|
||||
};
|
||||
self.write_storage_store(module, var_handle, sv, func_ctx, indent + 1)?;
|
||||
self.temp_access_chain.pop();
|
||||
}
|
||||
// done
|
||||
writeln!(self.out, "{}}}", back::INDENT.repeat(indent))?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fill_access_chain(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
mut cur_expr: Handle<crate::Expression>,
|
||||
func_ctx: &back::FunctionCtx<'_>,
|
||||
) -> Result<Handle<crate::GlobalVariable>, Error> {
|
||||
self.temp_access_chain.clear();
|
||||
loop {
|
||||
let stride = func_ctx.info[cur_expr]
|
||||
.ty
|
||||
.inner_with(&module.types)
|
||||
.span(&module.constants);
|
||||
let (next_expr, sub) = match func_ctx.expressions[cur_expr] {
|
||||
crate::Expression::GlobalVariable(handle) => return Ok(handle),
|
||||
crate::Expression::Access { base, index } => (
|
||||
base,
|
||||
SubAccess::Index {
|
||||
value: index,
|
||||
stride,
|
||||
},
|
||||
),
|
||||
crate::Expression::AccessIndex { base, index } => {
|
||||
match *func_ctx.info[base].ty.inner_with(&module.types) {
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
(base, SubAccess::Offset(members[index as usize].offset))
|
||||
}
|
||||
_ => (base, SubAccess::Offset(index * stride)),
|
||||
}
|
||||
}
|
||||
ref other => {
|
||||
return Err(Error::Unimplemented(format!(
|
||||
"Pointer access of {:?}",
|
||||
other
|
||||
)))
|
||||
}
|
||||
};
|
||||
self.temp_access_chain.push(sub);
|
||||
cur_expr = next_expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user