mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-02-20 02:42:43 +00:00
HLSL: rewrite handling of interface matching rules (#1276)
* [hlsl-out] flatten the entry point inputs Previously, the logic was re-ordering the inputs according to the binding. This breaks if one of the inputs is a struct. With this change, the struct fields are also flattened into the fake entry point struct. We also construct the original arguments at the beginning of the function. * hlsl-out: completely separate the flattened IO structs from the original IR structs Previously, we had heuristics to detect if a particular struct needs the fields to be re-ordered. We'd re-order interface structs without layout, and the detection was very fragile and easily wrong. The new logic is spawning separate struct types if we need any re-ordering to happen. It's solid, there are no heuristics.
This commit is contained in:
parent
63e58f2022
commit
81f4ff032f
@ -164,8 +164,8 @@ pub struct Writer<'a, W> {
|
||||
namer: proc::Namer,
|
||||
/// HLSL backend options
|
||||
options: &'a Options,
|
||||
/// Information about entry point arguments wrapped into structure
|
||||
ep_inputs: Vec<Option<writer::EntryPointBinding>>,
|
||||
/// Information about entry point arguments and result types.
|
||||
entry_point_io: Vec<writer::EntryPointInterface>,
|
||||
/// Set of expressions that have associated temporary variables
|
||||
named_expressions: crate::NamedExpressions,
|
||||
wrapped_array_lengths: crate::FastHashSet<help::WrappedArrayLength>,
|
||||
|
@ -17,20 +17,36 @@ const SPECIAL_BASE_VERTEX: &str = "base_vertex";
|
||||
const SPECIAL_BASE_INSTANCE: &str = "base_instance";
|
||||
const SPECIAL_OTHER: &str = "other";
|
||||
|
||||
struct EpStructMember {
|
||||
name: String,
|
||||
ty: Handle<crate::Type>,
|
||||
// technically, this should always be `Some`
|
||||
binding: Option<crate::Binding>,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
/// Structure contains information required for generating
|
||||
/// wrapped structure of all entry points arguments
|
||||
pub(super) struct EntryPointBinding {
|
||||
struct EntryPointBinding {
|
||||
/// Name of the fake EP argument that contains the struct
|
||||
/// with all the flattened input data.
|
||||
arg_name: String,
|
||||
/// Generated structure name
|
||||
name: String,
|
||||
ty_name: String,
|
||||
/// Members of generated structure
|
||||
members: Vec<EpStructMember>,
|
||||
}
|
||||
|
||||
struct EpStructMember {
|
||||
name: String,
|
||||
ty: Handle<crate::Type>,
|
||||
binding: Option<crate::Binding>,
|
||||
index: usize,
|
||||
pub(super) struct EntryPointInterface {
|
||||
/// If `Some`, the input of an entry point is gathered in a special
|
||||
/// struct with members sorted by binding.
|
||||
/// The `EntryPointBinding::members` array is sorted by index,
|
||||
/// so that we can walk it in `write_ep_arguments_initialization`.
|
||||
input: Option<EntryPointBinding>,
|
||||
/// If `Some`, the output of an entry point is flattened.
|
||||
/// The `EntryPointBinding::members` array is sorted by binding,
|
||||
/// So that we can walk it in `Statement::Return` handler.
|
||||
output: Option<EntryPointBinding>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -50,19 +66,6 @@ impl InterfaceKey {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true for structures that need their members permuted,
|
||||
// so that first come the user-defined varyings
|
||||
// in ascending locations, and then built-ins. This allows VS and FS
|
||||
// interfaces to match with regards to order.
|
||||
fn needs_permutation(members: &[crate::StructMember]) -> bool {
|
||||
//Note: this is a bit of a hack. We need to re-order the output fields, but we can only do this
|
||||
// for non-layouted structures. It may be possible for an WGSL program can use the same struct
|
||||
// for both host sharing and the interface. This case isn't supported here.
|
||||
let has_layout = members.iter().any(|m| m.offset != 0);
|
||||
let has_binding = members.iter().any(|m| m.binding.is_some());
|
||||
has_binding && !has_layout
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum Io {
|
||||
Input,
|
||||
@ -76,7 +79,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
names: crate::FastHashMap::default(),
|
||||
namer: proc::Namer::default(),
|
||||
options,
|
||||
ep_inputs: Vec::new(),
|
||||
entry_point_io: Vec::new(),
|
||||
named_expressions: crate::NamedExpressions::default(),
|
||||
wrapped_array_lengths: crate::FastHashSet::default(),
|
||||
wrapped_image_queries: crate::FastHashSet::default(),
|
||||
@ -88,7 +91,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
self.names.clear();
|
||||
self.namer
|
||||
.reset(module, super::keywords::RESERVED, &[], &mut self.names);
|
||||
self.ep_inputs.clear();
|
||||
self.entry_point_io.clear();
|
||||
self.named_expressions.clear();
|
||||
self.wrapped_array_lengths.clear();
|
||||
self.wrapped_image_queries.clear();
|
||||
@ -199,8 +202,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
|
||||
// Write all entry points wrapped structs
|
||||
for ep in module.entry_points.iter() {
|
||||
let ep_input = self.write_ep_input_struct(module, &ep.function, ep.stage, &ep.name)?;
|
||||
self.ep_inputs.push(ep_input);
|
||||
let ep_io = self.write_ep_interface(module, &ep.function, ep.stage, &ep.name)?;
|
||||
self.entry_point_io.push(ep_io);
|
||||
}
|
||||
|
||||
// Write all regular functions
|
||||
@ -306,6 +309,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
Ok(super::ReflectionInfo { entry_point_names })
|
||||
}
|
||||
|
||||
//TODO: we could force fragment outputs to always go through `entry_point_io.output` path
|
||||
// if they are struct, so that the `stage` argument here could be omitted.
|
||||
fn write_semantic(
|
||||
&mut self,
|
||||
binding: &crate::Binding,
|
||||
@ -328,67 +333,209 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_interface_struct(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
shader_stage: (ShaderStage, Io),
|
||||
struct_name: String,
|
||||
mut members: Vec<EpStructMember>,
|
||||
) -> Result<EntryPointBinding, Error> {
|
||||
// Sort the members so that first come the user-defined varyings
|
||||
// in ascending locations, and then built-ins. This allows VS and FS
|
||||
// interfaces to match with regards to order.
|
||||
members.sort_by_key(|m| InterfaceKey::new(m.binding.as_ref()));
|
||||
|
||||
write!(self.out, "struct {}", struct_name)?;
|
||||
writeln!(self.out, " {{")?;
|
||||
for m in members.iter() {
|
||||
write!(self.out, "{}", back::INDENT)?;
|
||||
self.write_type(module, m.ty)?;
|
||||
write!(self.out, " {}", &m.name)?;
|
||||
if let Some(ref binding) = m.binding {
|
||||
self.write_semantic(binding, Some(shader_stage))?;
|
||||
}
|
||||
writeln!(self.out, ";")?;
|
||||
}
|
||||
writeln!(self.out, "}};")?;
|
||||
writeln!(self.out)?;
|
||||
|
||||
match shader_stage.1 {
|
||||
Io::Input => {
|
||||
// bring back the original order
|
||||
members.sort_by_key(|m| m.index);
|
||||
}
|
||||
Io::Output => {
|
||||
// keep it sorted by binding
|
||||
}
|
||||
}
|
||||
|
||||
Ok(EntryPointBinding {
|
||||
arg_name: self.namer.call_unique(struct_name.to_lowercase().as_str()),
|
||||
ty_name: struct_name,
|
||||
members,
|
||||
})
|
||||
}
|
||||
|
||||
/// Flatten all entry point arguments into a single struct.
|
||||
/// This is needed since we need to re-order them: first placing user locations,
|
||||
/// then built-ins.
|
||||
fn write_ep_input_struct(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
func: &crate::Function,
|
||||
stage: ShaderStage,
|
||||
entry_point_name: &str,
|
||||
) -> Result<Option<EntryPointBinding>, Error> {
|
||||
Ok(if !func.arguments.is_empty() {
|
||||
let struct_name_prefix = match stage {
|
||||
ShaderStage::Vertex => "VertexInput",
|
||||
ShaderStage::Fragment => "FragmentInput",
|
||||
ShaderStage::Compute => "ComputeInput",
|
||||
};
|
||||
let struct_name = format!("{}_{}", struct_name_prefix, entry_point_name);
|
||||
) -> Result<EntryPointBinding, Error> {
|
||||
let struct_name = format!("{:?}Input_{}", stage, entry_point_name);
|
||||
|
||||
let mut members = Vec::with_capacity(func.arguments.len());
|
||||
for (index, arg) in func.arguments.iter().enumerate() {
|
||||
let member_name = if let Some(ref name) = arg.name {
|
||||
name
|
||||
} else {
|
||||
"member"
|
||||
};
|
||||
members.push(EpStructMember {
|
||||
name: self.namer.call_unique(member_name),
|
||||
ty: arg.ty,
|
||||
binding: arg.binding.clone(),
|
||||
index,
|
||||
});
|
||||
}
|
||||
|
||||
// Sort the members so that first come the user-defined varyings
|
||||
// in ascending locations, and then built-ins. This allows VS and FS
|
||||
// interfaces to match with regards to order.
|
||||
members.sort_by_key(|m| InterfaceKey::new(m.binding.as_ref()));
|
||||
|
||||
write!(self.out, "struct {}", &struct_name)?;
|
||||
writeln!(self.out, " {{")?;
|
||||
for m in members.iter() {
|
||||
write!(self.out, "{}", back::INDENT)?;
|
||||
self.write_type(module, m.ty)?;
|
||||
write!(self.out, " {}", &m.name)?;
|
||||
if let Some(ref binding) = m.binding {
|
||||
self.write_semantic(binding, Some((stage, Io::Input)))?;
|
||||
let mut fake_members = Vec::new();
|
||||
for arg in func.arguments.iter() {
|
||||
match module.types[arg.ty].inner {
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
for member in members.iter() {
|
||||
let member_name = if let Some(ref name) = member.name {
|
||||
name
|
||||
} else {
|
||||
"member"
|
||||
};
|
||||
let index = fake_members.len() as u32;
|
||||
fake_members.push(EpStructMember {
|
||||
name: self.namer.call_unique(member_name),
|
||||
ty: member.ty,
|
||||
binding: member.binding.clone(),
|
||||
index,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let member_name = if let Some(ref name) = arg.name {
|
||||
name
|
||||
} else {
|
||||
"member"
|
||||
};
|
||||
let index = fake_members.len() as u32;
|
||||
fake_members.push(EpStructMember {
|
||||
name: self.namer.call_unique(member_name),
|
||||
ty: arg.ty,
|
||||
binding: arg.binding.clone(),
|
||||
index,
|
||||
});
|
||||
}
|
||||
writeln!(self.out, ";")?;
|
||||
}
|
||||
writeln!(self.out, "}};")?;
|
||||
writeln!(self.out)?;
|
||||
}
|
||||
|
||||
// now bring back the old order
|
||||
members.sort_by_key(|m| m.index);
|
||||
self.write_interface_struct(module, (stage, Io::Input), struct_name, fake_members)
|
||||
}
|
||||
|
||||
Some(EntryPointBinding {
|
||||
name: struct_name,
|
||||
members,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
/// Flatten all entry point results into a single struct.
|
||||
/// This is needed since we need to re-order them: first placing user locations,
|
||||
/// then built-ins.
|
||||
fn write_ep_output_struct(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
result: &crate::FunctionResult,
|
||||
stage: ShaderStage,
|
||||
entry_point_name: &str,
|
||||
) -> Result<EntryPointBinding, Error> {
|
||||
let struct_name = format!("{:?}Output_{}", stage, entry_point_name);
|
||||
|
||||
let mut fake_members = Vec::new();
|
||||
let empty = [];
|
||||
let members = match module.types[result.ty].inner {
|
||||
TypeInner::Struct { ref members, .. } => members,
|
||||
ref other => {
|
||||
log::error!("Unexpected {:?} output type without a binding", other);
|
||||
&empty[..]
|
||||
}
|
||||
};
|
||||
|
||||
for member in members.iter() {
|
||||
let member_name = if let Some(ref name) = member.name {
|
||||
name
|
||||
} else {
|
||||
"member"
|
||||
};
|
||||
let index = fake_members.len() as u32;
|
||||
fake_members.push(EpStructMember {
|
||||
name: self.namer.call_unique(member_name),
|
||||
ty: member.ty,
|
||||
binding: member.binding.clone(),
|
||||
index,
|
||||
});
|
||||
}
|
||||
|
||||
self.write_interface_struct(module, (stage, Io::Output), struct_name, fake_members)
|
||||
}
|
||||
|
||||
/// Writes special interface structures for an entry point. The special structures have
|
||||
/// all the fields flattened into them and sorted by binding. They are only needed for
|
||||
/// VS outputs and FS inputs, so that these interfaces match.
|
||||
fn write_ep_interface(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
func: &crate::Function,
|
||||
stage: ShaderStage,
|
||||
ep_name: &str,
|
||||
) -> Result<EntryPointInterface, Error> {
|
||||
Ok(EntryPointInterface {
|
||||
input: if !func.arguments.is_empty() && stage == ShaderStage::Fragment {
|
||||
Some(self.write_ep_input_struct(module, func, stage, ep_name)?)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
output: match func.result {
|
||||
Some(ref fr) if fr.binding.is_none() && stage == ShaderStage::Vertex => {
|
||||
Some(self.write_ep_output_struct(module, fr, stage, ep_name)?)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Write an entry point preface that initializes the arguments as specified in IR.
|
||||
fn write_ep_arguments_initialization(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
func: &crate::Function,
|
||||
ep_index: u16,
|
||||
) -> BackendResult {
|
||||
let ep_input = match self.entry_point_io[ep_index as usize].input.take() {
|
||||
Some(ep_input) => ep_input,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let mut fake_iter = ep_input.members.iter();
|
||||
for (arg_index, arg) in func.arguments.iter().enumerate() {
|
||||
write!(self.out, "{}", back::INDENT)?;
|
||||
self.write_type(module, arg.ty)?;
|
||||
let arg_name = &self.names[&NameKey::EntryPointArgument(ep_index, arg_index as u32)];
|
||||
write!(self.out, " {}", arg_name)?;
|
||||
match module.types[arg.ty].inner {
|
||||
TypeInner::Array { size, .. } => {
|
||||
self.write_array_size(module, size)?;
|
||||
let fake_member = fake_iter.next().unwrap();
|
||||
writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?;
|
||||
}
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
write!(self.out, " = {{ ")?;
|
||||
for index in 0..members.len() {
|
||||
if index != 0 {
|
||||
write!(self.out, ", ")?;
|
||||
}
|
||||
let fake_member = fake_iter.next().unwrap();
|
||||
write!(self.out, "{}.{}", ep_input.arg_name, fake_member.name)?;
|
||||
}
|
||||
writeln!(self.out, " }};")?;
|
||||
}
|
||||
_ => {
|
||||
let fake_member = fake_iter.next().unwrap();
|
||||
writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(fake_iter.next().is_none());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper method used to write global variables
|
||||
/// # Notes
|
||||
/// Always adds a newline
|
||||
@ -571,28 +718,18 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
module: &Module,
|
||||
handle: Handle<crate::Type>,
|
||||
_block: bool,
|
||||
original_members: &[crate::StructMember],
|
||||
members: &[crate::StructMember],
|
||||
shader_stage: Option<(ShaderStage, Io)>,
|
||||
) -> BackendResult {
|
||||
// Write struct name
|
||||
write!(self.out, "struct {}", self.names[&NameKey::Type(handle)])?;
|
||||
writeln!(self.out, " {{")?;
|
||||
let struct_name = &self.names[&NameKey::Type(handle)];
|
||||
writeln!(self.out, "struct {} {{", struct_name)?;
|
||||
|
||||
//TODO: avoid heap allocation
|
||||
let mut members = original_members
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, m)| (index, m.ty, m.binding.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
if needs_permutation(original_members) {
|
||||
members.sort_by_key(|&(_, _, ref binding)| InterfaceKey::new(binding.as_ref()));
|
||||
}
|
||||
|
||||
for (index, ty, binding) in members {
|
||||
for (index, member) in members.iter().enumerate() {
|
||||
// The indentation is only for readability
|
||||
write!(self.out, "{}", back::INDENT)?;
|
||||
|
||||
match module.types[ty].inner {
|
||||
match module.types[member.ty].inner {
|
||||
TypeInner::Array {
|
||||
base,
|
||||
size,
|
||||
@ -629,7 +766,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
interpolation,
|
||||
sampling,
|
||||
..
|
||||
}) = binding
|
||||
}) = member.binding
|
||||
{
|
||||
if let Some(interpolation) = interpolation {
|
||||
write!(self.out, "{} ", interpolation.to_hlsl_str())?
|
||||
@ -642,12 +779,12 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
}
|
||||
}
|
||||
|
||||
if let TypeInner::Matrix { .. } = module.types[ty].inner {
|
||||
if let TypeInner::Matrix { .. } = module.types[member.ty].inner {
|
||||
write!(self.out, "row_major ")?;
|
||||
}
|
||||
|
||||
// Write the member type and name
|
||||
self.write_type(module, ty)?;
|
||||
self.write_type(module, member.ty)?;
|
||||
write!(
|
||||
self.out,
|
||||
" {}",
|
||||
@ -656,7 +793,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref binding) = binding {
|
||||
if let Some(ref binding) = member.binding {
|
||||
self.write_semantic(binding, shader_stage)?;
|
||||
};
|
||||
writeln!(self.out, ";")?;
|
||||
@ -760,7 +897,18 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
) -> BackendResult {
|
||||
// Function Declaration Syntax - https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-function-syntax
|
||||
if let Some(ref result) = func.result {
|
||||
self.write_type(module, result.ty)?;
|
||||
match func_ctx.ty {
|
||||
back::FunctionType::Function(_) => {
|
||||
self.write_type(module, result.ty)?;
|
||||
}
|
||||
back::FunctionType::EntryPoint(index) => {
|
||||
if let Some(ref ep_output) = self.entry_point_io[index as usize].output {
|
||||
write!(self.out, "{}", ep_output.ty_name)?;
|
||||
} else {
|
||||
self.write_type(module, result.ty)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
write!(self.out, "void")?;
|
||||
}
|
||||
@ -772,6 +920,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
match func_ctx.ty {
|
||||
back::FunctionType::Function(handle) => {
|
||||
for (index, arg) in func.arguments.iter().enumerate() {
|
||||
if index != 0 {
|
||||
write!(self.out, ", ")?;
|
||||
}
|
||||
// Write argument type
|
||||
let arg_ty = match module.types[arg.ty].inner {
|
||||
// pointers in function arguments are expected and resolve to `inout`
|
||||
@ -792,31 +943,30 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
if let TypeInner::Array { size, .. } = module.types[arg.ty].inner {
|
||||
self.write_array_size(module, size)?;
|
||||
}
|
||||
if index < func.arguments.len() - 1 {
|
||||
// Add a separator between args
|
||||
write!(self.out, ", ")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
back::FunctionType::EntryPoint(index) => {
|
||||
// EntryPoint arguments wrapped into structure
|
||||
// We need to ensure that entry points have arguments too.
|
||||
// For the case when we working with multiple entry points
|
||||
// for example vertex shader with arguments and fragment shader without arguments.
|
||||
if !self.ep_inputs.is_empty()
|
||||
&& !module.entry_points[index as usize]
|
||||
.function
|
||||
.arguments
|
||||
.is_empty()
|
||||
{
|
||||
if let Some(ref ep_input) = self.ep_inputs[index as usize] {
|
||||
write!(
|
||||
self.out,
|
||||
"{} {}",
|
||||
ep_input.name,
|
||||
self.namer
|
||||
.call_unique(ep_input.name.to_lowercase().as_str())
|
||||
)?;
|
||||
back::FunctionType::EntryPoint(ep_index) => {
|
||||
if let Some(ref ep_input) = self.entry_point_io[ep_index as usize].input {
|
||||
write!(self.out, "{} {}", ep_input.ty_name, ep_input.arg_name,)?;
|
||||
} else {
|
||||
let stage = module.entry_points[ep_index as usize].stage;
|
||||
for (index, arg) in func.arguments.iter().enumerate() {
|
||||
if index != 0 {
|
||||
write!(self.out, ", ")?;
|
||||
}
|
||||
self.write_type(module, arg.ty)?;
|
||||
|
||||
let argument_name =
|
||||
&self.names[&NameKey::EntryPointArgument(ep_index, index as u32)];
|
||||
|
||||
write!(self.out, " {}", argument_name)?;
|
||||
if let TypeInner::Array { size, .. } = module.types[arg.ty].inner {
|
||||
self.write_array_size(module, size)?;
|
||||
}
|
||||
|
||||
if let Some(ref binding) = arg.binding {
|
||||
self.write_semantic(binding, Some((stage, Io::Input)))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -825,21 +975,25 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
write!(self.out, ")")?;
|
||||
|
||||
// Write semantic if it present
|
||||
let stage = match func_ctx.ty {
|
||||
back::FunctionType::EntryPoint(index) => {
|
||||
Some(module.entry_points[index as usize].stage)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(ref result) = func.result {
|
||||
if let Some(ref binding) = result.binding {
|
||||
self.write_semantic(binding, stage.map(|s| (s, Io::Output)))?;
|
||||
if let back::FunctionType::EntryPoint(index) = func_ctx.ty {
|
||||
let stage = module.entry_points[index as usize].stage;
|
||||
if let Some(crate::FunctionResult {
|
||||
binding: Some(ref binding),
|
||||
..
|
||||
}) = func.result
|
||||
{
|
||||
self.write_semantic(binding, Some((stage, Io::Output)))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Function body start
|
||||
writeln!(self.out)?;
|
||||
writeln!(self.out, "{{")?;
|
||||
|
||||
if let back::FunctionType::EntryPoint(index) = func_ctx.ty {
|
||||
self.write_ep_arguments_initialization(module, func, index)?;
|
||||
}
|
||||
|
||||
// Write function local variables
|
||||
for (handle, local) in func.local_variables.iter() {
|
||||
// Write indentation (only for readability)
|
||||
@ -982,22 +1136,47 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
// We can safery unwrap here, since we now we working with struct
|
||||
let ty = base_ty_res.handle().unwrap();
|
||||
let struct_name = &self.names[&NameKey::Type(ty)];
|
||||
let variable_name = self.namer.call_unique(struct_name.as_str()).to_lowercase();
|
||||
let variable_name = self.namer.call(&struct_name.to_lowercase());
|
||||
write!(
|
||||
self.out,
|
||||
"{}const {} {} = ",
|
||||
INDENT.repeat(indent),
|
||||
struct_name,
|
||||
variable_name
|
||||
variable_name,
|
||||
)?;
|
||||
self.write_expr(module, expr, func_ctx)?;
|
||||
writeln!(self.out, ";")?;
|
||||
writeln!(
|
||||
self.out,
|
||||
"{}return {};",
|
||||
INDENT.repeat(indent),
|
||||
variable_name
|
||||
)?;
|
||||
|
||||
// for entry point returns, we may need to reshuffle the outputs into a different struct
|
||||
let ep_output = match func_ctx.ty {
|
||||
back::FunctionType::Function(_) => None,
|
||||
back::FunctionType::EntryPoint(index) => {
|
||||
self.entry_point_io[index as usize].output.as_ref()
|
||||
}
|
||||
};
|
||||
let final_name = match ep_output {
|
||||
Some(ep_output) => {
|
||||
let final_name = self.namer.call_unique(&variable_name);
|
||||
write!(
|
||||
self.out,
|
||||
"{}const {} {} = {{ ",
|
||||
INDENT.repeat(indent),
|
||||
ep_output.ty_name,
|
||||
final_name,
|
||||
)?;
|
||||
for (index, m) in ep_output.members.iter().enumerate() {
|
||||
if index != 0 {
|
||||
write!(self.out, ", ")?;
|
||||
}
|
||||
let member_name = &self.names[&NameKey::StructMember(ty, m.index)];
|
||||
write!(self.out, "{}.{}", variable_name, member_name)?;
|
||||
}
|
||||
writeln!(self.out, " }};")?;
|
||||
final_name
|
||||
}
|
||||
None => variable_name,
|
||||
};
|
||||
writeln!(self.out, "{}return {};", INDENT.repeat(indent), final_name)?;
|
||||
} else {
|
||||
write!(self.out, "{}return ", INDENT.repeat(indent))?;
|
||||
self.write_expr(module, expr, func_ctx)?;
|
||||
@ -1325,24 +1504,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
match *expression {
|
||||
Expression::Constant(constant) => self.write_constant(module, constant)?,
|
||||
Expression::Compose { ty, ref components } => {
|
||||
let (braces_init, permutation) = match module.types[ty].inner {
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
let permutation = if needs_permutation(members) {
|
||||
//TODO: avoid heap allocation. We can pre-compute this at the module leve.
|
||||
let mut permutation = members
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, m)| (index, InterfaceKey::new(m.binding.as_ref())))
|
||||
.collect::<Vec<_>>();
|
||||
permutation.sort_by_key(|&(_, ref key)| key.clone());
|
||||
Some(permutation)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(true, permutation)
|
||||
}
|
||||
TypeInner::Array { .. } => (true, None),
|
||||
_ => (false, None),
|
||||
let braces_init = match module.types[ty].inner {
|
||||
TypeInner::Struct { .. } | TypeInner::Array { .. } => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if braces_init {
|
||||
@ -1352,16 +1516,12 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
write!(self.out, "(")?;
|
||||
}
|
||||
|
||||
for index in 0..components.len() {
|
||||
for (index, &component) in components.iter().enumerate() {
|
||||
if index != 0 {
|
||||
// The leading space is for readability only
|
||||
write!(self.out, ", ")?;
|
||||
}
|
||||
let comp_index = match permutation {
|
||||
Some(ref perm) => perm[index].0,
|
||||
None => index,
|
||||
};
|
||||
self.write_expr(module, components[comp_index], func_ctx)?;
|
||||
self.write_expr(module, component, func_ctx)?;
|
||||
}
|
||||
|
||||
if braces_init {
|
||||
@ -1456,24 +1616,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
}
|
||||
}
|
||||
Expression::FunctionArgument(pos) => {
|
||||
match func_ctx.ty {
|
||||
back::FunctionType::Function(handle) => {
|
||||
let name = &self.names[&NameKey::FunctionArgument(handle, pos)];
|
||||
write!(self.out, "{}", name)?;
|
||||
}
|
||||
let key = match func_ctx.ty {
|
||||
back::FunctionType::Function(handle) => NameKey::FunctionArgument(handle, pos),
|
||||
back::FunctionType::EntryPoint(index) => {
|
||||
// EntryPoint arguments wrapped into structure
|
||||
// We can safery unwrap here, because if we write function arguments it means, that ep_input struct already exists
|
||||
let ep_input = self.ep_inputs[index as usize].as_ref().unwrap();
|
||||
let member_name = &ep_input.members[pos as usize].name;
|
||||
write!(
|
||||
self.out,
|
||||
"{}.{}",
|
||||
&ep_input.name.to_lowercase(),
|
||||
member_name
|
||||
)?
|
||||
NameKey::EntryPointArgument(index, pos)
|
||||
}
|
||||
};
|
||||
let name = &self.names[&key];
|
||||
write!(self.out, "{}", name)?;
|
||||
}
|
||||
Expression::ImageSample {
|
||||
image,
|
||||
|
@ -1,10 +1,6 @@
|
||||
|
||||
RWByteAddressBuffer bar : register(u0);
|
||||
|
||||
struct VertexInput_foo {
|
||||
uint vi1 : SV_VertexID;
|
||||
};
|
||||
|
||||
uint NagaBufferLengthRW(RWByteAddressBuffer buffer)
|
||||
{
|
||||
uint ret;
|
||||
@ -12,7 +8,7 @@ uint NagaBufferLengthRW(RWByteAddressBuffer buffer)
|
||||
return ret;
|
||||
}
|
||||
|
||||
float4 foo(VertexInput_foo vertexinput_foo) : SV_Position
|
||||
float4 foo(uint vi : SV_VertexID) : SV_Position
|
||||
{
|
||||
float foo1 = 0.0;
|
||||
int c[5] = {(int)0,(int)0,(int)0,(int)0,(int)0};
|
||||
@ -41,8 +37,8 @@ float4 foo(VertexInput_foo vertexinput_foo) : SV_Position
|
||||
int _result[5]={ a, int(b), 3, 4, 5 };
|
||||
for(int _i=0; _i<5; ++_i) c[_i] = _result[_i];
|
||||
}
|
||||
c[(vertexinput_foo.vi1 + 1u)] = 42;
|
||||
int value = c[vertexinput_foo.vi1];
|
||||
c[(vi + 1u)] = 42;
|
||||
int value = c[vi];
|
||||
return mul(float4(int4(value.xxxx)), matrix1);
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,8 @@ cbuffer params : register(b0) { SimParams params; }
|
||||
ByteAddressBuffer particlesSrc : register(t1);
|
||||
RWByteAddressBuffer particlesDst : register(u2);
|
||||
|
||||
struct ComputeInput_main {
|
||||
uint3 global_invocation_id1 : SV_DispatchThreadID;
|
||||
};
|
||||
|
||||
[numthreads(64, 1, 1)]
|
||||
void main(ComputeInput_main computeinput_main)
|
||||
void main(uint3 global_invocation_id : SV_DispatchThreadID)
|
||||
{
|
||||
float2 vPos = (float2)0;
|
||||
float2 vVel = (float2)0;
|
||||
@ -37,7 +33,7 @@ void main(ComputeInput_main computeinput_main)
|
||||
float2 vel = (float2)0;
|
||||
uint i = 0u;
|
||||
|
||||
uint index = computeinput_main.global_invocation_id1.x;
|
||||
uint index = global_invocation_id.x;
|
||||
if ((index >= NUM_PARTICLES)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,10 +1,6 @@
|
||||
|
||||
RWByteAddressBuffer v_indices : register(u0);
|
||||
|
||||
struct ComputeInput_main {
|
||||
uint3 global_id1 : SV_DispatchThreadID;
|
||||
};
|
||||
|
||||
uint collatz_iterations(uint n_base)
|
||||
{
|
||||
uint n = (uint)0;
|
||||
@ -32,10 +28,10 @@ uint collatz_iterations(uint n_base)
|
||||
}
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
void main(ComputeInput_main computeinput_main)
|
||||
void main(uint3 global_id : SV_DispatchThreadID)
|
||||
{
|
||||
uint _expr8 = asuint(v_indices.Load(computeinput_main.global_id1.x*4+0));
|
||||
uint _expr8 = asuint(v_indices.Load(global_id.x*4+0));
|
||||
const uint _e9 = collatz_iterations(_expr8);
|
||||
v_indices.Store(computeinput_main.global_id1.x*4+0, asuint(_e9));
|
||||
v_indices.Store(global_id.x*4+0, asuint(_e9));
|
||||
return;
|
||||
}
|
||||
|
@ -1,10 +1,6 @@
|
||||
|
||||
struct ComputeInput_main {
|
||||
uint3 global_id1 : SV_DispatchThreadID;
|
||||
};
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
void main(ComputeInput_main computeinput_main)
|
||||
void main(uint3 global_id : SV_DispatchThreadID)
|
||||
{
|
||||
int pos = (int)0;
|
||||
|
||||
|
@ -16,10 +16,6 @@ SamplerState sampler_reg : register(s0, space1);
|
||||
SamplerComparisonState sampler_cmp : register(s1, space1);
|
||||
Texture2D<float> image_2d_depth : register(t2, space1);
|
||||
|
||||
struct ComputeInput_main {
|
||||
uint3 local_id1 : SV_GroupThreadID;
|
||||
};
|
||||
|
||||
int2 NagaRWDimensions2D(RWTexture2D<uint4> texture)
|
||||
{
|
||||
uint4 ret;
|
||||
@ -28,15 +24,15 @@ int2 NagaRWDimensions2D(RWTexture2D<uint4> texture)
|
||||
}
|
||||
|
||||
[numthreads(16, 1, 1)]
|
||||
void main(ComputeInput_main computeinput_main)
|
||||
void main(uint3 local_id : SV_GroupThreadID)
|
||||
{
|
||||
int2 dim = NagaRWDimensions2D(image_storage_src);
|
||||
int2 itc = ((dim * int2(computeinput_main.local_id1.xy)) % int2(10, 20));
|
||||
uint4 value1_ = image_mipmapped_src.Load(int3(itc, int(computeinput_main.local_id1.z)));
|
||||
uint4 value2_ = image_multisampled_src.Load(itc, int(computeinput_main.local_id1.z));
|
||||
float value3_ = image_depth_multisampled_src.Load(itc, int(computeinput_main.local_id1.z)).x;
|
||||
int2 itc = ((dim * int2(local_id.xy)) % int2(10, 20));
|
||||
uint4 value1_ = image_mipmapped_src.Load(int3(itc, int(local_id.z)));
|
||||
uint4 value2_ = image_multisampled_src.Load(itc, int(local_id.z));
|
||||
float value3_ = image_depth_multisampled_src.Load(itc, int(local_id.z)).x;
|
||||
uint4 value4_ = image_storage_src.Load(itc);
|
||||
uint4 value5_ = image_array_src.Load(int4(itc, int(computeinput_main.local_id1.z), (int(computeinput_main.local_id1.z) + 1)));
|
||||
uint4 value5_ = image_array_src.Load(int4(itc, int(local_id.z), (int(local_id.z) + 1)));
|
||||
image_dst[itc.x] = ((((value1_ + value2_) + uint4(uint(value3_).xxxx)) + value4_) + value5_);
|
||||
return;
|
||||
}
|
||||
|
@ -18,45 +18,42 @@ struct FragmentOutput {
|
||||
|
||||
groupshared uint output[1];
|
||||
|
||||
struct VertexInput_vertex {
|
||||
uint color1 : LOC10;
|
||||
uint instance_index1 : SV_InstanceID;
|
||||
uint vertex_index1 : SV_VertexID;
|
||||
struct VertexOutput_vertex {
|
||||
float varying : LOC1;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
struct FragmentInput_fragment {
|
||||
float varying : LOC1;
|
||||
float4 position : SV_Position;
|
||||
bool front_facing1 : SV_IsFrontFace;
|
||||
uint sample_index1 : SV_SampleIndex;
|
||||
uint sample_mask1 : SV_Coverage;
|
||||
VertexOutput in2;
|
||||
};
|
||||
|
||||
struct ComputeInput_compute {
|
||||
uint3 global_id1 : SV_DispatchThreadID;
|
||||
uint3 local_id1 : SV_GroupThreadID;
|
||||
uint local_index1 : SV_GroupIndex;
|
||||
uint3 wg_id1 : SV_GroupID;
|
||||
uint3 num_wgs1 : SV_GroupID;
|
||||
};
|
||||
|
||||
VertexOutput vertex(VertexInput_vertex vertexinput_vertex)
|
||||
VertexOutput_vertex vertex(uint vertex_index : SV_VertexID, uint instance_index : SV_InstanceID, uint color : LOC10)
|
||||
{
|
||||
uint tmp = (((_NagaConstants.base_vertex + vertexinput_vertex.vertex_index1) + (_NagaConstants.base_instance + vertexinput_vertex.instance_index1)) + vertexinput_vertex.color1);
|
||||
const VertexOutput vertexoutput1 = { float4(1.0.xxxx), float(tmp) };
|
||||
uint tmp = (((_NagaConstants.base_vertex + vertex_index) + (_NagaConstants.base_instance + instance_index)) + color);
|
||||
const VertexOutput vertexoutput = { float4(1.0.xxxx), float(tmp) };
|
||||
const VertexOutput_vertex vertexoutput1 = { vertexoutput.varying, vertexoutput.position };
|
||||
return vertexoutput1;
|
||||
}
|
||||
|
||||
FragmentOutput fragment(FragmentInput_fragment fragmentinput_fragment)
|
||||
{
|
||||
uint mask = (fragmentinput_fragment.sample_mask1 & (1u << fragmentinput_fragment.sample_index1));
|
||||
float color2 = (fragmentinput_fragment.front_facing1 ? 1.0 : 0.0);
|
||||
const FragmentOutput fragmentoutput1 = { fragmentinput_fragment.in2.varying, mask, color2 };
|
||||
return fragmentoutput1;
|
||||
VertexOutput in1 = { fragmentinput_fragment.position, fragmentinput_fragment.varying };
|
||||
bool front_facing = fragmentinput_fragment.front_facing1;
|
||||
uint sample_index = fragmentinput_fragment.sample_index1;
|
||||
uint sample_mask = fragmentinput_fragment.sample_mask1;
|
||||
uint mask = (sample_mask & (1u << sample_index));
|
||||
float color1 = (front_facing ? 1.0 : 0.0);
|
||||
const FragmentOutput fragmentoutput = { in1.varying, mask, color1 };
|
||||
return fragmentoutput;
|
||||
}
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
void compute(ComputeInput_compute computeinput_compute)
|
||||
void compute(uint3 global_id : SV_DispatchThreadID, uint3 local_id : SV_GroupThreadID, uint local_index : SV_GroupIndex, uint3 wg_id : SV_GroupID, uint3 num_wgs : SV_GroupID)
|
||||
{
|
||||
output[0] = ((((computeinput_compute.global_id1.x + computeinput_compute.local_id1.x) + computeinput_compute.local_index1) + computeinput_compute.wg_id1.x) + uint3(_NagaConstants.base_vertex, _NagaConstants.base_instance, _NagaConstants.other).x);
|
||||
output[0] = ((((global_id.x + local_id.x) + local_index) + wg_id.x) + uint3(_NagaConstants.base_vertex, _NagaConstants.base_instance, _NagaConstants.other).x);
|
||||
return;
|
||||
}
|
||||
|
@ -10,11 +10,29 @@ struct FragmentInput {
|
||||
linear sample float perspective_sample : LOC6;
|
||||
};
|
||||
|
||||
struct FragmentInput_main {
|
||||
FragmentInput val1;
|
||||
struct VertexOutput_main {
|
||||
uint flat : LOC0;
|
||||
float linear1 : LOC1;
|
||||
float2 linear_centroid : LOC2;
|
||||
float3 linear_sample : LOC3;
|
||||
float4 perspective : LOC4;
|
||||
float perspective_centroid : LOC5;
|
||||
float perspective_sample : LOC6;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
FragmentInput main()
|
||||
struct FragmentInput_main {
|
||||
uint flat : LOC0;
|
||||
float linear2 : LOC1;
|
||||
float2 linear_centroid : LOC2;
|
||||
float3 linear_sample : LOC3;
|
||||
float4 perspective : LOC4;
|
||||
float perspective_centroid : LOC5;
|
||||
float perspective_sample : LOC6;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
VertexOutput_main main()
|
||||
{
|
||||
FragmentInput out1 = (FragmentInput)0;
|
||||
|
||||
@ -27,11 +45,13 @@ FragmentInput main()
|
||||
out1.perspective_centroid = 2197.0;
|
||||
out1.perspective_sample = 2744.0;
|
||||
FragmentInput _expr30 = out1;
|
||||
const FragmentInput fragmentinput1 = _expr30;
|
||||
const FragmentInput fragmentinput = _expr30;
|
||||
const VertexOutput_main fragmentinput1 = { fragmentinput.flat, fragmentinput.linear1, fragmentinput.linear_centroid, fragmentinput.linear_sample, fragmentinput.perspective, fragmentinput.perspective_centroid, fragmentinput.perspective_sample, fragmentinput.position };
|
||||
return fragmentinput1;
|
||||
}
|
||||
|
||||
void main1(FragmentInput_main fragmentinput_main)
|
||||
{
|
||||
FragmentInput val = { fragmentinput_main.position, fragmentinput_main.flat, fragmentinput_main.linear2, fragmentinput_main.linear_centroid, fragmentinput_main.linear_sample, fragmentinput_main.perspective, fragmentinput_main.perspective_centroid, fragmentinput_main.perspective_sample };
|
||||
return;
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
|
||||
struct gl_PerVertex {
|
||||
float4 gl_Position : SV_Position;
|
||||
float gl_PointSize : PSIZE;
|
||||
float gl_ClipDistance[1] : SV_ClipDistance;
|
||||
float gl_CullDistance[1] : SV_CullDistance;
|
||||
float gl_PointSize : PSIZE;
|
||||
};
|
||||
|
||||
struct type10 {
|
||||
linear float2 member : LOC0;
|
||||
float4 gl_Position : SV_Position;
|
||||
float gl_PointSize : PSIZE;
|
||||
float gl_ClipDistance[1] : SV_ClipDistance;
|
||||
float gl_CullDistance[1] : SV_CullDistance;
|
||||
float gl_PointSize : PSIZE;
|
||||
};
|
||||
|
||||
static float2 v_uv = (float2)0;
|
||||
@ -19,9 +19,12 @@ static float2 a_uv1 = (float2)0;
|
||||
static gl_PerVertex perVertexStruct = { float4(0.0, 0.0, 0.0, 1.0), 1.0, { 0.0 }, { 0.0 } };
|
||||
static float2 a_pos1 = (float2)0;
|
||||
|
||||
struct VertexInput_main {
|
||||
float2 a_pos2 : LOC0;
|
||||
float2 a_uv2 : LOC1;
|
||||
struct VertexOutput_main {
|
||||
float2 member : LOC0;
|
||||
float4 gl_Position : SV_Position;
|
||||
float gl_ClipDistance : SV_ClipDistance;
|
||||
float gl_CullDistance : SV_CullDistance;
|
||||
float gl_PointSize : PSIZE;
|
||||
};
|
||||
|
||||
void main1()
|
||||
@ -33,16 +36,17 @@ void main1()
|
||||
return;
|
||||
}
|
||||
|
||||
type10 main(VertexInput_main vertexinput_main)
|
||||
VertexOutput_main main(float2 a_uv : LOC1, float2 a_pos : LOC0)
|
||||
{
|
||||
a_uv1 = vertexinput_main.a_uv2;
|
||||
a_pos1 = vertexinput_main.a_pos2;
|
||||
a_uv1 = a_uv;
|
||||
a_pos1 = a_pos;
|
||||
main1();
|
||||
float2 _expr10 = v_uv;
|
||||
float4 _expr11 = perVertexStruct.gl_Position;
|
||||
float _expr12 = perVertexStruct.gl_PointSize;
|
||||
float _expr13[1] = perVertexStruct.gl_ClipDistance;
|
||||
float _expr14[1] = perVertexStruct.gl_CullDistance;
|
||||
const type10 type10_ = { _expr10, _expr11, _expr13, _expr14, _expr12 };
|
||||
return type10_;
|
||||
const type10 type10_ = { _expr10, _expr11, _expr12, _expr13, _expr14 };
|
||||
const VertexOutput_main type10_1 = { type10_.member, type10_.gl_Position, type10_.gl_ClipDistance, type10_.gl_CullDistance, type10_.gl_PointSize };
|
||||
return type10_1;
|
||||
}
|
||||
|
@ -8,24 +8,26 @@ struct VertexOutput {
|
||||
Texture2D<float4> u_texture : register(t0);
|
||||
SamplerState u_sampler : register(s1);
|
||||
|
||||
struct VertexInput_main {
|
||||
float2 pos1 : LOC0;
|
||||
float2 uv2 : LOC1;
|
||||
struct VertexOutput_main {
|
||||
float2 uv2 : LOC0;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
struct FragmentInput_main {
|
||||
float2 uv3 : LOC0;
|
||||
};
|
||||
|
||||
VertexOutput main(VertexInput_main vertexinput_main)
|
||||
VertexOutput_main main(float2 pos : LOC0, float2 uv : LOC1)
|
||||
{
|
||||
const VertexOutput vertexoutput1 = { vertexinput_main.uv2, float4((c_scale * vertexinput_main.pos1), 0.0, 1.0) };
|
||||
const VertexOutput vertexoutput = { uv, float4((c_scale * pos), 0.0, 1.0) };
|
||||
const VertexOutput_main vertexoutput1 = { vertexoutput.uv, vertexoutput.position };
|
||||
return vertexoutput1;
|
||||
}
|
||||
|
||||
float4 main1(FragmentInput_main fragmentinput_main) : SV_Target0
|
||||
{
|
||||
float4 color = u_texture.Sample(u_sampler, fragmentinput_main.uv3);
|
||||
float2 uv1 = fragmentinput_main.uv3;
|
||||
float4 color = u_texture.Sample(u_sampler, uv1);
|
||||
if ((color.w == 0.0)) {
|
||||
discard;
|
||||
}
|
||||
|
@ -34,10 +34,12 @@ float fetch_shadow(uint light_id, float4 homogeneous_coords)
|
||||
|
||||
float4 fs_main(FragmentInput_fs_main fragmentinput_fs_main) : SV_Target0
|
||||
{
|
||||
float3 raw_normal = fragmentinput_fs_main.raw_normal1;
|
||||
float4 position = fragmentinput_fs_main.position1;
|
||||
float3 color = float3(0.05, 0.05, 0.05);
|
||||
uint i = 0u;
|
||||
|
||||
float3 normal = normalize(fragmentinput_fs_main.raw_normal1);
|
||||
float3 normal = normalize(raw_normal);
|
||||
bool loop_init = true;
|
||||
while(true) {
|
||||
if (!loop_init) {
|
||||
@ -53,8 +55,8 @@ float4 fs_main(FragmentInput_fs_main fragmentinput_fs_main) : SV_Target0
|
||||
uint _expr19 = i;
|
||||
Light light = {float4x4(asfloat(s_lights.Load4(_expr19*96+0+0+0)), asfloat(s_lights.Load4(_expr19*96+0+0+16)), asfloat(s_lights.Load4(_expr19*96+0+0+32)), asfloat(s_lights.Load4(_expr19*96+0+0+48))), asfloat(s_lights.Load4(_expr19*96+0+64)), asfloat(s_lights.Load4(_expr19*96+0+80))};
|
||||
uint _expr22 = i;
|
||||
const float _e25 = fetch_shadow(_expr22, mul(fragmentinput_fs_main.position1, light.proj));
|
||||
float3 light_dir = normalize((light.pos.xyz - fragmentinput_fs_main.position1.xyz));
|
||||
const float _e25 = fetch_shadow(_expr22, mul(position, light.proj));
|
||||
float3 light_dir = normalize((light.pos.xyz - position.xyz));
|
||||
float diffuse = max(0.0, dot(normal, light_dir));
|
||||
float3 _expr34 = color;
|
||||
color = (_expr34 + ((_e25 * diffuse) * light.color.xyz));
|
||||
|
@ -19,21 +19,23 @@ cbuffer r_data : register(b0) { Data r_data; }
|
||||
TextureCube<float4> r_texture : register(t0);
|
||||
SamplerState r_sampler : register(s0, space1);
|
||||
|
||||
struct VertexInput_vs_main {
|
||||
uint vertex_index1 : SV_VertexID;
|
||||
struct VertexOutput_vs_main {
|
||||
float3 uv : LOC0;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
struct FragmentInput_fs_main {
|
||||
VertexOutput in2;
|
||||
float3 uv : LOC0;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
VertexOutput vs_main(VertexInput_vs_main vertexinput_vs_main)
|
||||
VertexOutput_vs_main vs_main(uint vertex_index : SV_VertexID)
|
||||
{
|
||||
int tmp1_ = (int)0;
|
||||
int tmp2_ = (int)0;
|
||||
|
||||
tmp1_ = (int((_NagaConstants.base_vertex + vertexinput_vs_main.vertex_index1)) / 2);
|
||||
tmp2_ = (int((_NagaConstants.base_vertex + vertexinput_vs_main.vertex_index1)) & 1);
|
||||
tmp1_ = (int((_NagaConstants.base_vertex + vertex_index)) / 2);
|
||||
tmp2_ = (int((_NagaConstants.base_vertex + vertex_index)) & 1);
|
||||
int _expr10 = tmp1_;
|
||||
int _expr16 = tmp2_;
|
||||
float4 pos = float4(((float(_expr10) * 4.0) - 1.0), ((float(_expr16) * 4.0) - 1.0), 0.0, 1.0);
|
||||
@ -43,12 +45,14 @@ VertexOutput vs_main(VertexInput_vs_main vertexinput_vs_main)
|
||||
float3x3 inv_model_view = transpose(float3x3(_expr27.xyz, _expr31.xyz, _expr35.xyz));
|
||||
float4x4 _expr40 = r_data.proj_inv;
|
||||
float4 unprojected = mul(pos, _expr40);
|
||||
const VertexOutput vertexoutput1 = { pos, mul(unprojected.xyz, inv_model_view) };
|
||||
const VertexOutput vertexoutput = { pos, mul(unprojected.xyz, inv_model_view) };
|
||||
const VertexOutput_vs_main vertexoutput1 = { vertexoutput.uv, vertexoutput.position };
|
||||
return vertexoutput1;
|
||||
}
|
||||
|
||||
float4 fs_main(FragmentInput_fs_main fragmentinput_fs_main) : SV_Target0
|
||||
{
|
||||
float4 _expr5 = r_texture.Sample(r_sampler, fragmentinput_fs_main.in2.uv);
|
||||
VertexOutput in1 = { fragmentinput_fs_main.position, fragmentinput_fs_main.uv };
|
||||
float4 _expr5 = r_texture.Sample(r_sampler, in1.uv);
|
||||
return _expr5;
|
||||
}
|
||||
|
@ -5,8 +5,9 @@ struct FragmentInput_derivatives {
|
||||
|
||||
float4 derivatives(FragmentInput_derivatives fragmentinput_derivatives) : SV_Target0
|
||||
{
|
||||
float4 x = ddx(fragmentinput_derivatives.foo1);
|
||||
float4 y = ddy(fragmentinput_derivatives.foo1);
|
||||
float4 z = fwidth(fragmentinput_derivatives.foo1);
|
||||
float4 foo = fragmentinput_derivatives.foo1;
|
||||
float4 x = ddx(foo);
|
||||
float4 y = ddy(foo);
|
||||
float4 z = fwidth(foo);
|
||||
return ((x + y) * z);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user