hlsl: storage writes

This commit is contained in:
Dzmitry Malyshau
2021-07-25 01:36:38 -04:00
committed by Dzmitry Malyshau
parent 4b6846d5da
commit 284cfcce47
12 changed files with 553 additions and 97 deletions

View File

@@ -10,6 +10,7 @@ use crate::{
use std::{fmt, mem};
const LOCATION_SEMANTIC: &str = "LOC";
const STORE_TEMP_NAME: &str = "_value";
/// Shorthand result used internally by the backend
pub(super) type BackendResult = Result<(), Error>;
@@ -28,6 +29,20 @@ enum SubAccess {
},
}
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 {
@@ -521,11 +536,7 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
let size = module.constants[const_handle].to_array_length().unwrap();
write!(self.out, "{}", size)?;
}
crate::ArraySize::Dynamic => {
//TODO: https://github.com/gfx-rs/naga/issues/1127
log::warn!("Dynamically sized arrays are not properly supported yet");
write!(self.out, "1")?;
}
crate::ArraySize::Dynamic => unreachable!(),
}
write!(self.out, "]")?;
@@ -965,7 +976,14 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
.pointer_class()
== Some(crate::StorageClass::Storage)
{
return Err(Error::Unimplemented("Storage stores".to_string()));
let var_handle = self.fill_access_chain(module, pointer, func_ctx)?;
self.write_storage_store(
module,
var_handle,
StoreValue::Expression(value),
func_ctx,
indent,
)?;
} else if let Some((const_handle, base_ty)) = array_info {
let size = module.constants[const_handle].to_array_length().unwrap();
writeln!(self.out, "{}{{", INDENT.repeat(indent))?;
@@ -1813,7 +1831,7 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
Ok(())
}
/// Helper function to write down the load operation on a `ByteAddressBuffer`.
/// Helper function to write down the Load operation on a `ByteAddressBuffer`.
fn write_storage_load(
&mut self,
module: &Module,
@@ -1895,6 +1913,203 @@ impl<'a, W: fmt::Write> Writer<'a, W> {
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,