|
|
|
|
Quelle lib.rs
Sprache: unbekannt
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate glsl;
mod hir;
use glsl::parser::Parse;
use glsl::syntax;
use glsl::syntax::{TranslationUnit, UnaryOp};
use hir::{Statement, Type};
use std::cell::{Cell, RefCell};
use std::collections::{BTreeMap, HashMap};
use std::io::Read;
use std::mem;
#[derive(PartialEq, Eq)]
enum ShaderKind {
Fragment,
Vertex,
}
type UniformIndices = BTreeMap<String, (i32, hir::TypeKind, hir::StorageClass)>;
fn build_uniform_indices(indices: &mut UniformIndices, state: &hir::State) {
for u in state.used_globals.borrow().iter() {
let sym = state.sym(*u);
match &sym.decl {
hir::SymDecl::Global(storage, _, ty, _) => match storage {
hir::StorageClass::Uniform | hir::StorageClass::Sampler(..) => {
let next_index = indices.len() as i32 + 1;
indices.entry(sym.name.clone()).or_insert((
next_index,
ty.kind.clone(),
*storage,
));
}
_ => {}
},
_ => {}
}
}
}
pub fn translate(args: &mut dyn Iterator<Item = String>) -> String {
let _cmd_name = args.next();
let vertex_file = args.next().unwrap();
let vs_name = std::path::Path::new(&vertex_file)
.file_stem()
.unwrap()
.to_string_lossy()
.to_string();
let frag_file = args.next().unwrap();
let fs_name = std::path::Path::new(&frag_file)
.file_stem()
.unwrap()
.to_string_lossy()
.to_string();
let (vs_state, vs_hir, vs_is_frag) = parse_shader(vertex_file);
let (fs_state, fs_hir, fs_is_frag) = parse_shader(frag_file);
// we use a BTree so that iteration is stable
let mut uniform_indices = BTreeMap::new();
build_uniform_indices(&mut uniform_indices, &vs_state);
build_uniform_indices(&mut uniform_indices, &fs_state);
assert_eq!(fs_name, vs_name);
let mut result = translate_shader(
vs_name,
vs_state,
vs_hir,
vs_is_frag,
&uniform_indices,
);
result += "\n";
result += &translate_shader(
fs_name,
fs_state,
fs_hir,
fs_is_frag,
&uniform_indices,
);
result
}
fn parse_shader(file: String) -> (hir::State, hir::TranslationUnit, bool) {
let mut contents = String::new();
let is_frag = file.contains("frag");
std::fs::File::open(&file)
.unwrap()
.read_to_string(&mut contents)
.unwrap();
let r = TranslationUnit::parse(contents);
//println!("{:#?}", r);
let mut ast_glsl = String::new();
let r = r.unwrap();
glsl::transpiler::glsl::show_translation_unit(&mut ast_glsl, &r);
//let mut fast = std::fs::File::create("ast").unwrap();
//fast.write(ast_glsl.as_bytes());
let mut state = hir::State::new();
let hir = hir::ast_to_hir(&mut state, &r);
(state, hir, is_frag)
}
fn translate_shader(
name: String,
mut state: hir::State,
hir: hir::TranslationUnit,
is_frag: bool,
uniform_indices: &UniformIndices,
) -> String {
//println!("{:#?}", state);
hir::infer_run_class(&mut state, &hir);
let mut uniforms = Vec::new();
let mut inputs = Vec::new();
let mut outputs = Vec::new();
for i in &hir {
match i {
hir::ExternalDeclaration::Declaration(hir::Declaration::InitDeclaratorList(ref d) ) => {
match &state.sym(d.head.name).decl {
hir::SymDecl::Global(storage, ..)
if state.used_globals.borrow().contains(&d.head.name) =>
{
match storage {
hir::StorageClass::Uniform | hir::StorageClass::Sampler(..) => {
uniforms.push(d.head.name);
}
hir::StorageClass::In => {
inputs.push(d.head.name);
}
hir::StorageClass::Out | hir::StorageClass::FragColor(_) => {
outputs.push(d.head.name);
}
_ => {}
}
}
_ => {}
}
}
_ => {}
}
}
//println!("{:#?}", hir);
let mut state = OutputState {
hir: state,
output: String::new(),
buffer: RefCell::new(String::new()),
indent: 0,
should_indent: false,
output_cxx: false,
mask: None,
cond_index: 0,
return_type: None,
return_declared: false,
return_vector: false,
is_scalar: Cell::new(false),
is_lval: Cell::new(false),
name: name.clone(),
kind: if is_frag {
ShaderKind::Fragment
} else {
ShaderKind::Vertex
},
functions: HashMap::new(),
deps: RefCell::new(Vec::new()),
vector_mask: 0,
uses_discard: false,
used_fragcoord: Cell::new(0),
use_perspective: false,
used_globals: RefCell::new(Vec::new()),
texel_fetches: RefCell::new(Vec::new()),
};
show_translation_unit(&mut state, &hir);
let _output_glsl = state.finish_output();
state.should_indent = true;
state.output_cxx = true;
if state.output_cxx {
let part_name = name.to_owned()
+ match state.kind {
ShaderKind::Vertex => "_vert",
ShaderKind::Fragment => "_frag",
};
if state.kind == ShaderKind::Vertex {
write_common_globals(&mut state, &inputs, &outputs, uniform_indices);
write!(state, "struct {0}_vert : VertexShaderImpl, {0}_common {{\nprivate:\n", name);
} else {
write!(state, "struct {0}_frag : FragmentShaderImpl, {0}_vert {{\nprivate:\n", name);
}
write!(state, "typedef {} Self;\n", part_name);
show_translation_unit(&mut state, &hir);
let pruned_inputs: Vec<_> = inputs
.iter()
.filter(|i| state.used_globals.borrow().contains(i))
.cloned()
.collect();
if state.kind == ShaderKind::Vertex {
write_set_uniform_1i(&mut state, uniform_indices);
write_set_uniform_4fv(&mut state, uniform_indices);
write_set_uniform_matrix4fv(&mut state, uniform_indices);
write_load_attribs(&mut state, &pruned_inputs);
write_store_outputs(&mut state, &outputs);
} else {
write_read_inputs(&mut state, &pruned_inputs);
}
write_abi(&mut state);
write!(state, "}};\n\n");
if state.kind == ShaderKind::Fragment {
write!(state, "struct {0}_program : ProgramImpl, {0}_frag {{\n", name);
write_get_uniform_index(&mut state, uniform_indices);
write!(state, "void bind_attrib(const char* name, int index) override {{\n");
write!(state, " attrib_locations.bind_loc(name, index);\n}}\n");
write!(state, "int get_attrib(const char* name) const override {{\n");
write!(state, " return attrib_locations.get_loc(name);\n}}\n");
write!(state, "size_t interpolants_size() const override {{ return sizeof(InterpOutputs); }}\n");
write!(state, "VertexShaderImpl* get_vertex_shader() override {{\n");
write!(state, " return this;\n}}\n");
write!(state, "FragmentShaderImpl* get_fragment_shader() override {{\n");
write!(state, " return this;\n}}\n");
write!(state, "const char* get_name() const override {{ return \"{}\"; }}\n", name);
write!(state, "static ProgramImpl* loader() {{ return new {}_program; }}\n", name);
write!(state, "}};\n\n");
}
define_global_consts(&mut state, &hir, &part_name);
} else {
show_translation_unit(&mut state, &hir);
}
let output_cxx = state.finish_output();
//let mut hir = std::fs::File::create("hir").unwrap();
//hir.write(output_glsl.as_bytes());
output_cxx
}
fn write_get_uniform_index(state: &mut OutputState, uniform_indices: &UniformIndices) {
write!(
state,
"int get_uniform(const char *name) const override {{\n"
);
for (uniform_name, (index, _, _)) in uniform_indices.iter() {
write!(
state,
" if (strcmp(\"{}\", name) == 0) {{ return {}; }}\n",
uniform_name, index
);
}
write!(state, " return -1;\n");
write!(state, "}}\n");
}
fn float4_compatible(ty: hir::TypeKind) -> bool {
match ty {
hir::TypeKind::Vec4 => true,
_ => false,
}
}
fn matrix4_compatible(ty: hir::TypeKind) -> bool {
match ty {
hir::TypeKind::Mat4 => true,
_ => false,
}
}
fn write_program_samplers(state: &mut OutputState, uniform_indices: &UniformIndices) {
write!(state, "struct Samplers {{\n");
for (name, (_, tk, storage)) in uniform_indices.iter() {
match tk {
hir::TypeKind::Sampler2D
| hir::TypeKind::Sampler2DRect
| hir::TypeKind::ISampler2D => {
write!(state, " ");
show_type_kind(state, &tk);
let suffix = if let hir::StorageClass::Sampler(format) = storage {
format.type_suffix()
} else {
None
};
write!(state, "{}_impl {}_impl;\n", suffix.unwrap_or(""), name);
write!(state, " int {}_slot;\n", name);
}
_ => {}
}
}
write!(
state,
" bool set_slot(int index, int value) {{\n"
);
write!(state, " switch (index) {{\n");
for (name, (index, tk, _)) in uniform_indices.iter() {
match tk {
hir::TypeKind::Sampler2D
| hir::TypeKind::Sampler2DRect
| hir::TypeKind::ISampler2D => {
write!(state, " case {}:\n", index);
write!(state, " {}_slot = value;\n", name);
write!(state, " return true;\n");
}
_ => {}
}
}
write!(state, " }}\n");
write!(state, " return false;\n");
write!(state, " }}\n");
write!(state, "}} samplers;\n");
}
fn write_bind_textures(state: &mut OutputState, uniforms: &UniformIndices) {
write!(state, "void bind_textures() {{\n");
for (name, (_, tk, storage)) in uniforms {
match storage {
hir::StorageClass::Sampler(_format) => {
match tk {
hir::TypeKind::Sampler2D
| hir::TypeKind::Sampler2DRect => write!(state,
" {0} = lookup_sampler(&samplers.{0}_impl, samplers.{0}_slot);\n",
name),
hir::TypeKind::ISampler2D => write!(state,
" {0} = lookup_isampler(&samplers.{0}_impl, samplers.{0}_slot);\n",
name),
_ => {}
};
}
_ => {}
}
}
write!(state, "}}\n");
}
fn write_set_uniform_1i(
state: &mut OutputState,
uniforms: &UniformIndices,
) {
write!(
state,
"static void set_uniform_1i(VertexShaderImpl* impl, int index, int value) {{\n"
);
write!(state, " Self* self = (Self*)impl;\n");
write!(state, " if (self->samplers.set_slot(index, value)) return;\n");
write!(state, " switch (index) {{\n");
for (name, (index, tk, _)) in uniforms {
write!(state, " case {}:\n", index);
match tk {
hir::TypeKind::Int => write!(
state,
" self->{} = {}(value);\n",
name,
tk.cxx_primitive_scalar_type_name().unwrap(),
),
_ => write!(state, " assert(0); // {}\n", name),
};
write!(state, " break;\n");
}
write!(state, " }}\n");
write!(state, "}}\n");
}
fn write_set_uniform_4fv(
state: &mut OutputState,
uniforms: &UniformIndices,
) {
write!(
state,
"static void set_uniform_4fv(VertexShaderImpl* impl, int index, const float *value) {{\n"
);
write!(state, " Self* self = (Self*)impl;\n");
write!(state, " switch (index) {{\n");
for (name, (index, tk, _)) in uniforms {
write!(state, " case {}:\n", index);
if float4_compatible(tk.clone()) {
write!(
state,
" self->{} = vec4_scalar::load_from_ptr(value);\n",
name
);
} else {
write!(state, " assert(0); // {}\n", name);
}
write!(state, " break;\n");
}
write!(state, " }}\n");
write!(state, "}}\n");
}
fn write_set_uniform_matrix4fv(
state: &mut OutputState,
uniforms: &UniformIndices,
) {
write!(
state,
"static void set_uniform_matrix4fv(VertexShaderImpl* impl, int index, const float *value) {{\n"
);
write!(state, " Self* self = (Self*)impl;\n");
write!(state, " switch (index) {{\n");
for (name, (index, tk, _)) in uniforms {
write!(state, " case {}:\n", index);
if matrix4_compatible(tk.clone()) {
write!(
state,
" self->{} = mat4_scalar::load_from_ptr(value);\n",
name
);
} else {
write!(state, " assert(0); // {}\n", name);
}
write!(state, " break;\n");
}
write!(state, " }}\n");
write!(state, "}}\n");
}
fn write_bind_attrib_location(state: &mut OutputState, attribs: &[hir::SymRef]) {
write!(state, "struct AttribLocations {{\n");
for i in attribs {
let sym = state.hir.sym(*i);
write!(state, " int {} = NULL_ATTRIB;\n", sym.name.as_str());
}
write!(state, " void bind_loc(const char* name, int index) {{\n");
for i in attribs {
let sym = state.hir.sym(*i);
write!(
state,
" if (strcmp(\"{0}\", name) == 0) {{ {0} = index; return; }}\n",
sym.name.as_str()
);
}
write!(state, " }}\n");
write!(state, " int get_loc(const char* name) const {{\n");
for i in attribs {
let sym = state.hir.sym(*i);
write!(state,
" if (strcmp(\"{0}\", name) == 0) {{ \
return {0} != NULL_ATTRIB ? {0} : -1; \
}}\n",
sym.name.as_str());
}
write!(state, " return -1;\n");
write!(state, " }}\n");
write!(state, "}} attrib_locations;\n");
}
fn write_common_globals(state: &mut OutputState, attribs: &[hir::SymRef],
outputs: &[hir::SymRef], uniforms: &UniformIndices) {
write!(state, "struct {}_common {{\n", state.name);
write_program_samplers(state, uniforms);
write_bind_attrib_location(state, attribs);
let is_scalar = state.is_scalar.replace(true);
for i in outputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(hir::StorageClass::Out, _, ty, hir::RunClass::Scalar) => {
show_type(state, ty);
write!(state, " {};\n", sym.name.as_str());
}
_ => {}
}
}
for (name, (_, tk, storage)) in uniforms {
match storage {
hir::StorageClass::Sampler(format) => {
write!(state,
"{}{} {};\n",
tk.cxx_primitive_type_name().unwrap(),
format.type_suffix().unwrap_or(""),
name,
);
}
_ => {
show_type_kind(state, tk);
write!(state, " {};\n", name);
}
}
}
state.is_scalar.set(is_scalar);
write_bind_textures(state, uniforms);
write!(state, "}};\n");
}
//fn type_name(state: &OutputState, ty: &Type) -> String {
// let buffer = state.push_buffer();
// show_type(state, ty);
// state.pop_buffer(buffer)
//}
fn write_load_attribs(state: &mut OutputState, attribs: &[hir::SymRef]) {
write!(state, "static void load_attribs(\
VertexShaderImpl* impl, VertexAttrib *attribs, \
uint32_t start, int instance, int count) {{\
Self* self = (Self*)impl;\n");
for i in attribs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _interpolation, _ty, run_class) => {
let name = sym.name.as_str();
let func = if *run_class == hir::RunClass::Scalar {
"load_flat_attrib"
} else {
"load_attrib"
};
write!(state,
" {0}(self->{1}, attribs[self->attrib_locations.{1}], start, instance, count);\n",
func, name);
}
_ => panic!(),
}
}
write!(state, "}}\n");
}
fn write_store_outputs(state: &mut OutputState, outputs: &[hir::SymRef]) {
let is_scalar = state.is_scalar.replace(true);
write!(state, "public:\nstruct InterpOutputs {{\n");
if state.hir.used_clip_dist != 0 {
state.write(" Float swgl_ClipDistance;\n");
}
for i in outputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, ty, run_class) => {
if *run_class != hir::RunClass::Scalar {
show_type(state, ty);
write!(state, " {};\n", sym.name.as_str());
}
}
_ => panic!(),
}
}
write!(state, "}};\nprivate:\n");
state.is_scalar.set(is_scalar);
write!(
state,
"ALWAYS_INLINE void store_interp_outputs(char* dest_ptr, size_t stride) {{\n"
);
write!(state, " for(int n = 0; n < 4; n++) {{\n");
write!(
state,
" auto* dest = reinterpret_cast<InterpOutputs*>(dest_ptr);\n"
);
if state.hir.used_clip_dist != 0 {
for (i, comp) in "xyzw".chars().enumerate() {
if (state.hir.used_clip_dist & (1 << i)) != 0 {
write!(state, " dest->swgl_ClipDistance.{} = get_nth(gl_ClipDistance[{}], n);\n", comp, i);
} else {
write!(state, " dest->swgl_ClipDistance.{} = 0.0f;\n", comp);
}
}
}
for i in outputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(state, " dest->{} = get_nth({}, n);\n", name, name);
}
}
_ => panic!(),
}
}
write!(state, " dest_ptr += stride;\n");
write!(state, " }}\n");
write!(state, "}}\n");
}
fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
write!(
state,
"typedef {}_vert::InterpOutputs InterpInputs;\n",
state.name
);
write!(state, "InterpInputs interp_step;\n");
let mut has_varying = false;
for i in inputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, ty, run_class) => {
if *run_class != hir::RunClass::Scalar {
if !has_varying {
has_varying = true;
write!(state, "struct InterpPerspective {{\n");
}
show_type(state, ty);
write!(state, " {};\n", sym.name.as_str());
}
}
_ => panic!(),
}
}
if has_varying {
write!(state, "}};\n");
write!(state, "InterpPerspective interp_perspective;\n");
}
write!(state,
"static void read_interp_inputs(\
FragmentShaderImpl* impl, const void* init_, const void* step_) {{\
Self* self = (Self*)impl;\
const InterpInputs* init = (const InterpInputs*)init_;\
const InterpInputs* step = (const InterpInputs*)step_;\n");
for i in inputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(
state,
" self->{0} = init_interp(init->{0}, step->{0});\n",
name
);
write!(
state,
" self->interp_step.{0} = step->{0} * 4.0f;\n",
name
);
}
}
_ => panic!(),
}
}
write!(state, "}}\n");
let used_fragcoord = state.used_fragcoord.get();
if has_varying || (used_fragcoord & (4 | 8)) != 0 {
state.use_perspective = true;
}
if state.use_perspective {
write!(state,
"static void read_perspective_inputs(\
FragmentShaderImpl* impl, const void* init_, const void* step_) {{\
Self* self = (Self*)impl;\
const InterpInputs* init = (const InterpInputs*)init_;\
const InterpInputs* step = (const InterpInputs*)step_;\n");
if has_varying {
write!(state, " Float w = 1.0f / self->gl_FragCoord.w;\n");
}
for i in inputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(
state,
" self->interp_perspective.{0} = init_interp(init->{0}, step->{0});\n",
name
);
write!(state, " self->{0} = self->interp_perspective.{0} * w;\n", name);
write!(
state,
" self->interp_step.{0} = step->{0} * 4.0f;\n",
name
);
}
}
_ => panic!(),
}
}
write!(state, "}}\n");
}
write!(state, "ALWAYS_INLINE void step_interp_inputs(int steps = 4) {{\n");
if (used_fragcoord & 1) != 0 {
write!(state, " step_fragcoord(steps);\n");
}
if !inputs.is_empty() {
write!(state, " float chunks = steps * 0.25f;\n");
}
for i in inputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(state, " {0} += interp_step.{0} * chunks;\n", name);
}
}
_ => panic!(),
}
}
write!(state, "}}\n");
if state.use_perspective {
write!(state, "ALWAYS_INLINE void step_perspective_inputs(int steps = 4) {{\n");
if (used_fragcoord & 1) != 0 {
write!(state, " step_fragcoord(steps);\n");
}
write!(state, " step_perspective(steps);\n");
if !inputs.is_empty() {
write!(state, " float chunks = steps * 0.25f;\n");
}
if has_varying {
write!(state, " Float w = 1.0f / gl_FragCoord.w;\n");
}
for i in inputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(state, " interp_perspective.{0} += interp_step.{0} * chunks;\n", name);
write!(state, " {0} = w * interp_perspective.{0};\n", name);
}
}
_ => panic!(),
}
}
write!(state, "}}\n");
}
}
pub struct OutputState {
hir: hir::State,
output: String,
buffer: RefCell<String>,
should_indent: bool,
output_cxx: bool,
indent: i32,
mask: Option<Box<hir::Expr>>,
cond_index: usize,
return_type: Option<Box<hir::Type>>,
return_declared: bool,
return_vector: bool,
is_scalar: Cell<bool>,
is_lval: Cell<bool>,
name: String,
kind: ShaderKind,
functions: HashMap<(hir::SymRef, u32), bool>,
deps: RefCell<Vec<(hir::SymRef, u32)>>,
vector_mask: u32,
uses_discard: bool,
used_fragcoord: Cell<i32>,
use_perspective: bool,
used_globals: RefCell<Vec<hir::SymRef>>,
texel_fetches: RefCell<Vec<(hir::SymRef, hir::SymRef, hir::TexelFetchOffsets)>>,
}
use std::fmt::{Arguments, Write};
impl OutputState {
fn indent(&mut self) {
if self.should_indent {
self.indent += 1
}
}
fn outdent(&mut self) {
if self.should_indent {
self.indent -= 1
}
}
fn write(&self, s: &str) {
self.buffer.borrow_mut().push_str(s);
}
fn flush_buffer(&mut self) {
self.output.push_str(&self.buffer.borrow());
self.buffer.borrow_mut().clear();
}
fn finish_output(&mut self) -> String {
self.flush_buffer();
let mut s = String::new();
mem::swap(&mut self.output, &mut s);
s
}
fn push_buffer(&self) -> String {
self.buffer.replace(String::new())
}
fn pop_buffer(&self, s: String) -> String {
self.buffer.replace(s)
}
fn write_fmt(&self, args: Arguments) {
let _ = self.buffer.borrow_mut().write_fmt(args);
}
}
pub fn show_identifier(state: &OutputState, i: &syntax::Identifier) {
state.write(&i.0);
}
fn glsl_primitive_type_name_to_cxx(glsl_name: &str) -> &str {
hir::TypeKind::from_glsl_primitive_type_name(glsl_name)
.and_then(|kind| kind.cxx_primitive_type_name())
.unwrap_or(glsl_name)
}
fn add_used_global(state: &OutputState, i: &hir::SymRef) {
let mut globals = state.used_globals.borrow_mut();
if !globals.contains(i) {
globals.push(*i);
}
}
pub fn show_sym(state: &OutputState, i: &hir::SymRef) {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::NativeFunction(_, ref cxx_name, _) => {
let mut name = sym.name.as_str();
if state.output_cxx {
name = cxx_name.unwrap_or(name);
}
state.write(name);
}
hir::SymDecl::Global(..) => {
if state.output_cxx {
add_used_global(state, i);
}
let mut name = sym.name.as_str();
if state.output_cxx {
name = glsl_primitive_type_name_to_cxx(name);
}
state.write(name);
}
hir::SymDecl::UserFunction(..) | hir::SymDecl::Local(..) | hir::SymDecl::Struct(..) => {
let mut name = sym.name.as_str();
// we want to replace constructor names
if state.output_cxx {
name = glsl_primitive_type_name_to_cxx(name);
}
state.write(name);
}
}
}
pub fn show_variable(state: &OutputState, i: &hir::SymRef) {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, ty, _) => {
show_type(state, ty);
state.write(" ");
let mut name = sym.name.as_str();
if state.output_cxx {
name = glsl_primitive_type_name_to_cxx(name);
}
state.write(name);
}
_ => panic!(),
}
}
pub fn write_default_constructor(state: &OutputState, name: &str) {
// write default constructor
let _ = write!(state, "{}() = default;\n", name);
}
pub fn write_constructor(state: &OutputState, name: &str, s: &hir::StructFields) {
if s.fields.len() == 1 {
state.write("explicit ");
}
let _ = write!(state, "{}(", name);
let mut first_field = true;
for field in &s.fields {
if !first_field {
state.write(", ");
}
show_type(state, &field.ty);
state.write(" ");
show_identifier_and_type(state, &field.name, &field.ty);
first_field = false;
}
state.write(") : ");
let mut first_field = true;
for field in &s.fields {
if !first_field {
state.write(", ");
}
let _ = write!(state, "{}({})", field.name, field.name);
first_field = false;
}
state.write("{}\n");
}
pub fn write_convert_constructor(state: &OutputState, name: &str, s: &hir::StructFields) {
if s.fields.len() == 1 {
state.write("explicit ");
}
let _ = write!(state, "{}(", name);
let mut first_field = true;
for field in &s.fields {
if !first_field {
state.write(", ");
}
let is_scalar = state.is_scalar.replace(true);
show_type(state, &field.ty);
state.is_scalar.set(is_scalar);
state.write(" ");
show_identifier_and_type(state, &field.name, &field.ty);
first_field = false;
}
state.write(")");
let mut first_field = true;
for hir::StructField { ty, name } in &s.fields {
if ty.array_sizes.is_none() {
if first_field {
state.write(":");
} else {
state.write(",");
}
let _ = write!(state, "{}({})", name, name);
first_field = false;
}
}
state.write("{\n");
for hir::StructField { ty, name } in &s.fields {
if ty.array_sizes.is_some() {
let _ = write!(state, "this->{}.convert({});\n", name, name);
}
}
state.write("}\n");
let _ = write!(state, "IMPLICIT {}({}_scalar s)", name, name);
let mut first_field = true;
for hir::StructField { ty, name } in &s.fields {
if ty.array_sizes.is_none() {
if first_field {
state.write(":");
} else {
state.write(",");
}
let _ = write!(state, "{}(s.{})", name, name);
first_field = false;
}
}
state.write("{\n");
for hir::StructField { ty, name } in &s.fields {
if ty.array_sizes.is_some() {
let _ = write!(state, "{}.convert(s.{});\n", name, name);
}
}
state.write("}\n");
}
pub fn write_if_then_else(state: &OutputState, name: &str, s: &hir::StructFields) {
let _ = write!(
state,
"friend {} if_then_else(I32 c, {} t, {} e) {{ return {}(\n",
name, name, name, name
);
let mut first_field = true;
for field in &s.fields {
if !first_field {
state.write(", ");
}
let _ = write!(state, "if_then_else(c, t.{}, e.{})", field.name, field.name);
first_field = false;
}
state.write(");\n}");
}
pub fn show_storage_class(state: &OutputState, q: &hir::StorageClass) {
match *q {
hir::StorageClass::None => {}
hir::StorageClass::Const => {
state.write("const ");
}
hir::StorageClass::In => {
state.write("in ");
}
hir::StorageClass::Out => {
state.write("out ");
}
hir::StorageClass::FragColor(index) => {
write!(state, "layout(location = 0, index = {}) out ", index);
}
hir::StorageClass::Uniform | hir::StorageClass::Sampler(..) => {
state.write("uniform ");
}
}
}
pub fn show_sym_decl(state: &OutputState, i: &hir::SymRef) {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(storage, ..) => {
if !state.output_cxx {
show_storage_class(state, storage)
}
if storage == &hir::StorageClass::Const {
state.write("static constexpr ");
}
let mut name = sym.name.as_str();
if state.output_cxx {
name = glsl_primitive_type_name_to_cxx(name);
}
state.write(name);
}
hir::SymDecl::Local(storage, ..) => {
if !state.output_cxx {
show_storage_class(state, storage)
}
if storage == &hir::StorageClass::Const {
state.write("const ");
}
let mut name = sym.name.as_str();
if state.output_cxx {
name = glsl_primitive_type_name_to_cxx(name);
}
state.write(name);
}
hir::SymDecl::Struct(s) => {
let name = sym.name.as_str();
if state.output_cxx {
let name_scalar = format!("{}_scalar", name);
write!(state, "struct {} {{\n", name_scalar);
let is_scalar = state.is_scalar.replace(true);
for field in &s.fields {
show_struct_field(state, field);
}
write_default_constructor(state, &name_scalar);
write_constructor(state, &name_scalar, s);
state.is_scalar.set(is_scalar);
state.write("};\n");
}
write!(state, "struct {} {{\n", name);
for field in &s.fields {
show_struct_field(state, field);
}
// write if_then_else
if state.output_cxx {
write_default_constructor(state, name);
write_constructor(state, name, s);
write_convert_constructor(state, name, s);
write_if_then_else(state, name, s);
}
state.write("}");
}
_ => panic!(),
}
}
pub fn show_type_name(state: &OutputState, t: &syntax::TypeName) {
state.write(&t.0);
}
pub fn show_type_specifier_non_array(state: &mut OutputState, t: &syntax::TypeSpecifierNonArray) {
if let Some(kind) = hir::TypeKind::from_primitive_type_specifier(t) {
show_type_kind(state, &kind);
} else {
match t {
syntax::TypeSpecifierNonArray::Struct(ref _s) => panic!(), //show_struct_non_declaration(state, s),
syntax::TypeSpecifierNonArray::TypeName(ref tn) => show_type_name(state, tn),
_ => unreachable!(),
}
}
}
pub fn show_type_kind(state: &OutputState, t: &hir::TypeKind) {
if state.output_cxx {
if state.is_scalar.get() {
if let Some(name) = t.cxx_primitive_scalar_type_name() {
state.write(name);
} else if let Some(name) = t.cxx_primitive_type_name() {
let mut scalar_name = String::from(name);
scalar_name.push_str("_scalar");
state.write(scalar_name.as_str());
} else {
match t {
hir::TypeKind::Struct(ref s) => {
let mut scalar_name = String::from(state.hir.sym(*s).name.as_str());
scalar_name.push_str("_scalar");
state.write(scalar_name.as_str());
}
_ => unreachable!(),
}
}
} else if let Some(name) = t.cxx_primitive_type_name() {
state.write(name);
} else {
match t {
hir::TypeKind::Struct(ref s) => {
state.write(state.hir.sym(*s).name.as_str());
}
_ => unreachable!(),
}
}
} else if let Some(name) = t.glsl_primitive_type_name() {
state.write(name);
} else {
match t {
hir::TypeKind::Struct(ref s) => {
state.write(state.hir.sym(*s).name.as_str());
}
_ => unreachable!(),
}
}
}
pub fn show_type_specifier(state: &mut OutputState, t: &syntax::TypeSpecifier) {
show_type_specifier_non_array(state, &t.ty);
if let Some(ref arr_spec) = t.array_specifier {
show_array_spec(state, arr_spec);
}
}
pub fn show_type(state: &OutputState, t: &Type) {
if !state.output_cxx {
if let Some(ref precision) = t.precision {
show_precision_qualifier(state, precision);
state.write(" ");
}
}
if state.output_cxx {
if let Some(ref array) = t.array_sizes {
state.write("Array<");
show_type_kind(state, &t.kind);
let size = match &array.sizes[..] {
[size] => size,
_ => panic!(),
};
state.write(",");
show_hir_expr(state, size);
state.write(">");
} else {
show_type_kind(state, &t.kind);
}
} else {
show_type_kind(state, &t.kind);
}
/*if let Some(ref arr_spec) = t.array_sizes {
panic!();
}*/
}
/*pub fn show_fully_specified_type(state: &mut OutputState, t: &FullySpecifiedType) {
state.flat = false;
if let Some(ref qual) = t.qualifier {
if !state.output_cxx {
show_type_qualifier(state, &qual);
} else {
state.flat =
qual.qualifiers.0.iter()
.flat_map(|q| match q { syntax::TypeQualifierSpec::Interpolation(Flat) => Some(()), _ => None})
.next().is_some();
}
state.write(" ");
}
show_type_specifier(state, &t.ty);
}*/
/*pub fn show_struct_non_declaration(state: &mut OutputState, s: &syntax::StructSpecifier) {
state.write("struct ");
if let Some(ref name) = s.name {
let _ = write!(state, "{} ", name);
}
state.write("{\n");
for field in &s.fields.0 {
show_struct_field(state, field);
}
state.write("}");
}*/
pub fn show_struct(_state: &OutputState, _s: &syntax::StructSpecifier) {
panic!();
//show_struct_non_declaration(state, s);
//state.write(";\n");
}
pub fn show_struct_field(state: &OutputState, field: &hir::StructField) {
show_type(state, &field.ty);
state.write(" ");
show_identifier_and_type(state, &field.name, &field.ty);
state.write(";\n");
}
pub fn show_array_spec(state: &OutputState, a: &syntax::ArraySpecifier) {
for dimension in &a.dimensions {
match dimension {
syntax::ArraySpecifierDimension::Unsized => {
state.write("[]");
}
syntax::ArraySpecifierDimension::ExplicitlySized(ref e) => {
state.write("[");
show_expr(state, &e);
state.write("]");
}
}
}
}
pub fn show_identifier_and_type(state: &OutputState, ident: &syntax::Identifier, ty: &hir::Type) {
let _ = write!(state, "{}", ident);
if !state.output_cxx {
if let Some(ref arr_spec) = ty.array_sizes {
show_array_sizes(state, &arr_spec);
}
}
}
pub fn show_arrayed_identifier(state: &OutputState, ident: &syntax::ArrayedIdentifier) {
let _ = write!(state, "{}", ident.ident);
if let Some(ref arr_spec) = ident.array_spec {
show_array_spec(state, &arr_spec);
}
}
pub fn show_array_sizes(state: &OutputState, a: &hir::ArraySizes) {
state.write("[");
match &a.sizes[..] {
[a] => show_hir_expr(state, a),
_ => panic!(),
}
state.write("]");
/*
match *a {
syntax::ArraySpecifier::Unsized => { state.write("[]"); }
syntax::ArraySpecifier::ExplicitlySized(ref e) => {
state.write("[");
show_expr(state, &e);
state.write("]");
}
}*/
}
pub fn show_type_qualifier(state: &OutputState, q: &hir::TypeQualifier) {
let mut qualifiers = q.qualifiers.0.iter();
let first = qualifiers.next().unwrap();
show_type_qualifier_spec(state, first);
for qual_spec in qualifiers {
state.write(" ");
show_type_qualifier_spec(state, qual_spec)
}
}
pub fn show_type_qualifier_spec(state: &OutputState, q: &hir::TypeQualifierSpec) {
match *q {
hir::TypeQualifierSpec::Layout(ref l) => show_layout_qualifier(state, &l),
hir::TypeQualifierSpec::Parameter(ref _p) => panic!(),
hir::TypeQualifierSpec::Memory(ref _m) => panic!(),
hir::TypeQualifierSpec::Invariant => {
state.write("invariant");
}
hir::TypeQualifierSpec::Precise => {
state.write("precise");
}
}
}
pub fn show_syntax_storage_qualifier(state: &OutputState, q: &syntax::StorageQualifier) {
match *q {
syntax::StorageQualifier::Const => {
state.write("const");
}
syntax::StorageQualifier::InOut => {
state.write("inout");
}
syntax::StorageQualifier::In => {
state.write("in");
}
syntax::StorageQualifier::Out => {
state.write("out");
}
syntax::StorageQualifier::Centroid => {
state.write("centroid");
}
syntax::StorageQualifier::Patch => {
state.write("patch");
}
syntax::StorageQualifier::Sample => {
state.write("sample");
}
syntax::StorageQualifier::Uniform => {
state.write("uniform");
}
syntax::StorageQualifier::Attribute => {
state.write("attribute");
}
syntax::StorageQualifier::Varying => {
state.write("varying");
}
syntax::StorageQualifier::Buffer => {
state.write("buffer");
}
syntax::StorageQualifier::Shared => {
state.write("shared");
}
syntax::StorageQualifier::Coherent => {
state.write("coherent");
}
syntax::StorageQualifier::Volatile => {
state.write("volatile");
}
syntax::StorageQualifier::Restrict => {
state.write("restrict");
}
syntax::StorageQualifier::ReadOnly => {
state.write("readonly");
}
syntax::StorageQualifier::WriteOnly => {
state.write("writeonly");
}
syntax::StorageQualifier::Subroutine(ref n) => show_subroutine(state, &n),
}
}
pub fn show_subroutine(state: &OutputState, types: &[syntax::TypeName]) {
state.write("subroutine");
if !types.is_empty() {
state.write("(");
let mut types_iter = types.iter();
let first = types_iter.next().unwrap();
show_type_name(state, first);
for type_name in types_iter {
state.write(", ");
show_type_name(state, type_name);
}
state.write(")");
}
}
pub fn show_layout_qualifier(state: &OutputState, l: &syntax::LayoutQualifier) {
let mut qualifiers = l.ids.0.iter();
let first = qualifiers.next().unwrap();
state.write("layout (");
show_layout_qualifier_spec(state, first);
for qual_spec in qualifiers {
state.write(", ");
show_layout_qualifier_spec(state, qual_spec);
}
state.write(")");
}
pub fn show_layout_qualifier_spec(state: &OutputState, l: &syntax::LayoutQualifierSpec) {
match *l {
syntax::LayoutQualifierSpec::Identifier(ref i, Some(ref e)) => {
let _ = write!(state, "{} = ", i);
show_expr(state, &e);
}
syntax::LayoutQualifierSpec::Identifier(ref i, None) => show_identifier(state, &i),
syntax::LayoutQualifierSpec::Shared => {
state.write("shared");
}
}
}
pub fn show_precision_qualifier(state: &OutputState, p: &syntax::PrecisionQualifier) {
match *p {
syntax::PrecisionQualifier::High => {
state.write("highp");
}
syntax::PrecisionQualifier::Medium => {
state.write("mediump");
}
syntax::PrecisionQualifier::Low => {
state.write("low");
}
}
}
pub fn show_interpolation_qualifier(state: &OutputState, i: &syntax::InterpolationQualifier) {
match *i {
syntax::InterpolationQualifier::Smooth => {
state.write("smooth");
}
syntax::InterpolationQualifier::Flat => {
state.write("flat");
}
syntax::InterpolationQualifier::NoPerspective => {
state.write("noperspective");
}
}
}
pub fn show_parameter_qualifier(state: &mut OutputState, i: &Option<hir::ParameterQualifier>) {
if let Some(i) = i {
if state.output_cxx {
match *i {
hir::ParameterQualifier::Out => {
state.write("&");
}
hir::ParameterQualifier::InOut => {
state.write("&");
}
_ => {}
}
} else {
match *i {
hir::ParameterQualifier::Const => {
state.write("const");
}
hir::ParameterQualifier::In => {
state.write("in");
}
hir::ParameterQualifier::Out => {
state.write("out");
}
hir::ParameterQualifier::InOut => {
state.write("inout");
}
}
}
}
}
pub fn show_float(state: &OutputState, x: f32) {
if x.fract() == 0. {
write!(state, "{}.f", x);
} else {
write!(state, "{}f", x);
}
}
pub fn show_double(state: &OutputState, x: f64) {
// force doubles to print as floats
if x.fract() == 0. {
write!(state, "{}.f", x);
} else {
write!(state, "{}f", x);
}
}
fn expr_run_class(state: &OutputState, expr: &hir::Expr) -> hir::RunClass {
match &expr.kind {
hir::ExprKind::Variable(i) => symbol_run_class(&state.hir.sym(*i).decl, state.vector_mask),
hir::ExprKind::IntConst(_)
| hir::ExprKind::UIntConst(_)
| hir::ExprKind::BoolConst(_)
| hir::ExprKind::FloatConst(_)
| hir::ExprKind::DoubleConst(_) => hir::RunClass::Scalar,
hir::ExprKind::Unary(_, ref e) => expr_run_class(state, e),
hir::ExprKind::Binary(_, ref l, ref r) => {
expr_run_class(state, l).merge(expr_run_class(state, r))
}
hir::ExprKind::Ternary(ref c, ref s, ref e) => expr_run_class(state, c)
.merge(expr_run_class(state, s))
.merge(expr_run_class(state, e)),
hir::ExprKind::Assignment(ref v, _, ref e) => {
expr_run_class(state, v).merge(expr_run_class(state, e))
}
hir::ExprKind::Bracket(ref e, ref indx) => {
indx.iter().fold(
expr_run_class(state, e),
|run_class, indx| run_class.merge(expr_run_class(state, indx)),
)
}
hir::ExprKind::FunCall(ref fun, ref args) => {
let arg_mask: u32 = args.iter().enumerate().fold(0, |mask, (idx, e)| {
if expr_run_class(state, e) == hir::RunClass::Vector {
mask | (1 << idx)
} else {
mask
}
});
match fun {
hir::FunIdentifier::Identifier(ref sym) => match &state.hir.sym(*sym).decl {
hir::SymDecl::NativeFunction(_, _, ref ret_class) => {
if *ret_class != hir::RunClass::Unknown {
*ret_class
} else if arg_mask != 0 {
hir::RunClass::Vector
} else {
hir::RunClass::Scalar
}
}
hir::SymDecl::UserFunction(ref fd, ref run_class) => {
let param_mask: u32 = fd.prototype.parameters.iter().enumerate().fold(
arg_mask,
|mask, (idx, param)| {
if let hir::FunctionParameterDeclaration::Named(Some(qual), p) =
param
{
match qual {
hir::ParameterQualifier::InOut
| hir::ParameterQualifier::Out => {
if symbol_run_class(
&state.hir.sym(p.sym).decl,
arg_mask,
) == hir::RunClass::Vector
{
mask | (1 << idx)
} else {
mask
}
}
_ => mask,
}
} else {
mask
}
},
);
match *run_class {
hir::RunClass::Scalar => hir::RunClass::Scalar,
hir::RunClass::Dependent(mask) => {
if (mask & param_mask) != 0 {
hir::RunClass::Vector
} else {
hir::RunClass::Scalar
}
}
_ => hir::RunClass::Vector,
}
}
hir::SymDecl::Struct(..) => {
if arg_mask != 0 {
hir::RunClass::Vector
} else {
hir::RunClass::Scalar
}
}
_ => panic!(),
},
hir::FunIdentifier::Constructor(..) => {
if arg_mask != 0 {
hir::RunClass::Vector
} else {
hir::RunClass::Scalar
}
}
}
}
hir::ExprKind::Dot(ref e, _) => expr_run_class(state, e),
hir::ExprKind::SwizzleSelector(ref e, _) => expr_run_class(state, e),
hir::ExprKind::PostInc(ref e) => expr_run_class(state, e),
hir::ExprKind::PostDec(ref e) => expr_run_class(state, e),
hir::ExprKind::Comma(_, ref e) => expr_run_class(state, e),
hir::ExprKind::Cond(_, ref e) => expr_run_class(state, e),
hir::ExprKind::CondMask => hir::RunClass::Vector,
}
}
pub fn show_hir_expr(state: &OutputState, expr: &hir::Expr) {
show_hir_expr_inner(state, expr, false);
}
pub fn show_hir_expr_inner(state: &OutputState, expr: &hir::Expr, top_level: bool) {
match expr.kind {
hir::ExprKind::Variable(ref i) => show_sym(state, i),
hir::ExprKind::IntConst(ref x) => {
let _ = write!(state, "{}", x);
}
hir::ExprKind::UIntConst(ref x) => {
let _ = write!(state, "{}u", x);
}
hir::ExprKind::BoolConst(ref x) => {
let _ = write!(state, "{}", x);
}
hir::ExprKind::FloatConst(ref x) => show_float(state, *x),
hir::ExprKind::DoubleConst(ref x) => show_double(state, *x),
hir::ExprKind::Unary(ref op, ref e) => {
show_unary_op(state, &op);
state.write("(");
show_hir_expr(state, &e);
state.write(")");
}
hir::ExprKind::Binary(ref op, ref l, ref r) => {
state.write("(");
show_hir_expr(state, &l);
state.write(")");
show_binary_op(state, &op);
state.write("(");
show_hir_expr(state, &r);
state.write(")");
}
hir::ExprKind::Ternary(ref c, ref s, ref e) => {
if state.output_cxx && expr_run_class(state, c) != hir::RunClass::Scalar {
state.write("if_then_else(");
show_hir_expr(state, &c);
state.write(", ");
show_hir_expr(state, &s);
state.write(", ");
show_hir_expr(state, &e);
state.write(")");
} else {
show_hir_expr(state, &c);
state.write(" ? ");
show_hir_expr(state, &s);
state.write(" : ");
show_hir_expr(state, &e);
}
}
hir::ExprKind::Assignment(ref v, ref op, ref e) => {
let is_output = hir::is_output(v, &state.hir).is_some();
let is_scalar_var = expr_run_class(state, v) == hir::RunClass::Scalar;
let is_scalar_expr = expr_run_class(state, e) == hir::RunClass::Scalar;
let force_scalar = is_scalar_var && !is_scalar_expr;
if let Some(mask) = &state.mask {
let is_scalar_mask = expr_run_class(state, mask) == hir::RunClass::Scalar;
let force_scalar_mask = is_scalar_var && is_scalar_expr && !is_scalar_mask;
if force_scalar || force_scalar_mask {
if top_level {
state.write("if (");
} else {
state.write("(");
}
} else {
state.is_lval.set(true);
show_hir_expr(state, &v);
state.is_lval.set(false);
state.write(" = if_then_else(");
}
if is_output && state.return_declared {
state.write("((");
show_hir_expr(state, mask);
state.write(")&ret_mask)");
} else {
show_hir_expr(state, mask);
}
if force_scalar || force_scalar_mask {
if top_level {
state.write("[0]) { ");
} else {
state.write("[0] ? ");
}
state.is_lval.set(true);
show_hir_expr(state, &v);
state.is_lval.set(false);
state.write(" = ");
} else {
state.write(",");
}
if op != &syntax::AssignmentOp::Equal {
show_hir_expr(state, &v);
}
match *op {
syntax::AssignmentOp::Equal => {}
syntax::AssignmentOp::Mult => {
state.write("*");
}
syntax::AssignmentOp::Div => {
state.write("/");
}
syntax::AssignmentOp::Mod => {
state.write("%");
}
syntax::AssignmentOp::Add => {
state.write("+");
}
syntax::AssignmentOp::Sub => {
state.write("-");
}
syntax::AssignmentOp::LShift => {
state.write("<<");
}
syntax::AssignmentOp::RShift => {
state.write(">>");
}
syntax::AssignmentOp::And => {
state.write("&");
}
syntax::AssignmentOp::Xor => {
state.write("^");
}
syntax::AssignmentOp::Or => {
state.write("|");
}
}
if force_scalar {
state.write("force_scalar(");
}
show_hir_expr(state, &e);
if force_scalar {
state.write(")");
}
if force_scalar || force_scalar_mask {
if top_level {
state.write("; }");
} else {
state.write(" : ");
show_hir_expr(state, &v);
state.write(")");
}
} else {
state.write(",");
show_hir_expr(state, &v);
state.write(")");
}
} else {
state.is_lval.set(true);
show_hir_expr(state, &v);
state.is_lval.set(false);
state.write(" ");
if is_output && state.return_declared {
state.write("= ");
if force_scalar {
state.write("force_scalar(");
}
state.write("if_then_else(ret_mask,");
if op != &syntax::AssignmentOp::Equal {
show_hir_expr(state, &v);
}
match *op {
syntax::AssignmentOp::Equal => {}
syntax::AssignmentOp::Mult => {
state.write("*");
}
syntax::AssignmentOp::Div => {
state.write("/");
}
syntax::AssignmentOp::Mod => {
state.write("%");
}
syntax::AssignmentOp::Add => {
state.write("+");
}
syntax::AssignmentOp::Sub => {
state.write("-");
}
syntax::AssignmentOp::LShift => {
state.write("<<");
}
syntax::AssignmentOp::RShift => {
state.write(">>");
}
syntax::AssignmentOp::And => {
state.write("&");
}
syntax::AssignmentOp::Xor => {
state.write("^");
}
syntax::AssignmentOp::Or => {
state.write("|");
}
}
show_hir_expr(state, &e);
state.write(",");
show_hir_expr(state, &v);
state.write(")");
} else {
show_assignment_op(state, &op);
state.write(" ");
if force_scalar {
state.write("force_scalar(");
}
show_hir_expr(state, &e);
}
if force_scalar {
state.write(")");
}
}
}
hir::ExprKind::Bracket(ref e, ref indx) => {
show_hir_expr(state, &e);
state.write("[");
for dimension in indx {
show_hir_expr(state, dimension);
}
state.write("]");
}
hir::ExprKind::FunCall(ref fun, ref args) => {
let mut cond_mask: u32 = 0;
let mut adapt_mask: u32 = 0;
let mut has_ret = false;
let mut array_constructor = false;
let mut arg_mask: u32 = 0;
for (idx, e) in args.iter().enumerate() {
if expr_run_class(state, e) == hir::RunClass::Vector {
arg_mask |= 1 << idx;
}
}
match fun {
hir::FunIdentifier::Constructor(t) => {
let is_scalar = state.is_scalar.replace(arg_mask == 0);
show_type(state, t);
state.is_scalar.set(is_scalar);
array_constructor = t.array_sizes.is_some();
}
hir::FunIdentifier::Identifier(name) => {
if state.output_cxx {
let sym = state.hir.sym(*name);
match &sym.decl {
hir::SymDecl::NativeFunction(..) => {
if sym.name == "texelFetchOffset" && args.len() >= 4 {
if let Some((sampler, base, x, y)) = hir::get_texel_fetch_offset(
&state.hir, &args[0], &args[1], &args[3],
) {
let base_sym = state.hir.sym(base);
let sampler_sym = state.hir.sym(sampler);
add_used_global(state, &sampler);
if let hir::SymDecl::Global(..) = &base_sym.decl {
add_used_global(state, &base);
}
write!(
state,
"texelFetchUnchecked({}, {}_{}_fetch, {}, {})",
sampler_sym.name,
sampler_sym.name,
base_sym.name,
x,
y,
);
return;
}
}
show_sym(state, name)
}
hir::SymDecl::UserFunction(ref fd, ref _run_class) => {
if (state.mask.is_some() || state.return_declared) &&
!fd.globals.is_empty()
{
cond_mask |= 1 << 31;
}
let mut param_mask: u32 = 0;
for (idx, (param, e)) in
fd.prototype.parameters.iter().zip(args.iter()).enumerate()
{
if let hir::FunctionParameterDeclaration::Named(qual, p) = param
{
if symbol_run_class(&state.hir.sym(p.sym).decl, arg_mask)
== hir::RunClass::Vector
{
param_mask |= 1 << idx;
}
match qual {
Some(hir::ParameterQualifier::InOut)
| Some(hir::ParameterQualifier::Out) => {
if state.mask.is_some() || state.return_declared {
cond_mask |= 1 << idx;
}
if (!arg_mask & param_mask & (1 << idx)) != 0 {
if adapt_mask == 0 {
state.write(if top_level {
"{ "
} else {
"({ "
});
}
show_type(state, &p.ty);
write!(state, " _arg{}_ = ", idx);
show_hir_expr(state, e);
state.write("; ");
adapt_mask |= 1 << idx;
}
}
_ => {}
}
}
}
if adapt_mask != 0 &&
fd.prototype.ty.kind != hir::TypeKind::Void &&
!top_level
{
state.write("auto _ret_ = ");
has_ret = true;
}
--> --------------------
--> maximum size reached
--> --------------------
[ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet)
]
|
2026-04-06
|
|
|
|
|