nak: Add initial translation from NIR

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
Faith Ekstrand
2023-01-30 20:53:16 -06:00
committed by Marge Bot
parent a4a5fe2270
commit 5585f57c5c
2 changed files with 238 additions and 3 deletions
+11 -3
View File
@@ -3,10 +3,12 @@
* SPDX-License-Identifier: MIT
*/
mod nak_from_nir;
mod nak_ir;
mod nir;
use nak_bindings::*;
use nak_from_nir::*;
#[repr(C)]
struct ShaderBin {
@@ -23,9 +25,15 @@ pub extern "C" fn nak_shader_bin_destroy(bin: *mut nak_shader_bin) {
#[no_mangle]
pub extern "C" fn nak_compile_shader(
_nir: *mut nir_shader,
_nak: *const nak_compiler,
nir: *mut nir_shader,
nak: *const nak_compiler,
) -> *mut nak_shader_bin {
println!("Hello from rust!");
unsafe { nak_postprocess_nir(nir, nak) };
let nir = unsafe { &*nir };
let mut s = nak_shader_from_nir(nir);
println!("NAK IR:\n{}", &s);
std::ptr::null_mut()
}
+227
View File
@@ -0,0 +1,227 @@
/*
* Copyright © 2022 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#![allow(non_upper_case_globals)]
use crate::nak_ir::*;
use crate::nir::*;
use nak_bindings::*;
struct ShaderFromNir<'a> {
nir: &'a nir_shader,
func: Option<Function>,
instrs: Vec<Instr>,
fs_out_regs: Vec<Src>,
}
impl<'a> ShaderFromNir<'a> {
fn new(nir: &'a nir_shader) -> Self {
let mut fs_out_regs = Vec::new();
if nir.info.stage() == MESA_SHADER_FRAGMENT {
fs_out_regs
.resize(nir.num_outputs.try_into().unwrap(), Src::new_zero());
}
Self {
nir: nir,
func: None,
instrs: Vec::new(),
fs_out_regs: fs_out_regs,
}
}
pub fn alloc_ssa(&mut self, file: RegFile, comps: u8) -> Src {
self.func.as_mut().unwrap().alloc_ssa(file, comps)
}
fn ref_for_nir_def(&self, def: &nir_def) -> Src {
assert!(def.bit_size == 32 || def.bit_size == 64);
let dwords = (def.bit_size / 32) * def.num_components;
//Src::new_ssa(def.index, dwords, !def.divergent)
Src::new_ssa(RegFile::GPR, def.index, dwords)
}
fn get_src(&self, src: &nir_src) -> Src {
self.ref_for_nir_def(&src.as_def())
}
fn get_dst(&self, def: &nir_def) -> Dst {
self.ref_for_nir_def(def).as_dst()
}
fn get_alu_src(&mut self, alu_src: &nir_alu_src) -> Src {
assert!(alu_src.src.bit_size() == 32);
if alu_src.src.num_components() == 1 {
self.get_src(&alu_src.src)
} else {
let vec_src = self.get_src(&alu_src.src);
let comp = self.alloc_ssa(vec_src.as_ssa().unwrap().file(), 1);
let mut dsts = Vec::new();
for c in 0..alu_src.src.num_components() {
if c == alu_src.swizzle[0] {
dsts.push(comp.as_dst());
} else {
dsts.push(Dst::Zero);
}
}
self.instrs.push(Instr::new_split(&dsts, vec_src));
comp
}
}
fn parse_alu(&mut self, alu: &nir_alu_instr) {
let mut srcs = Vec::new();
for alu_src in alu.srcs_as_slice() {
srcs.push(self.get_alu_src(alu_src));
}
let srcs = srcs;
let dst = self.get_dst(&alu.def);
match alu.op {
nir_op_fadd => {
self.instrs.push(Instr::new_fadd(dst, srcs[0], srcs[1]));
}
nir_op_mov => {
self.instrs.push(Instr::new_mov(dst, srcs[0]));
}
nir_op_pack_64_2x32_split => {
self.instrs.push(Instr::new_vec(dst, &[srcs[0], srcs[1]]));
}
_ => panic!("Unsupported ALU instruction"),
}
}
fn parse_jump(&mut self, jump: &nir_jump_instr) {
match jump.type_ {
_ => panic!("Unsupported jump instruction"),
}
}
fn parse_tex(&mut self, _tex: &nir_tex_instr) {
panic!("Texture instructions unimplemented");
}
fn parse_intrinsic(&mut self, intrin: &nir_intrinsic_instr) {
let srcs = intrin.srcs_as_slice();
match intrin.intrinsic {
nir_intrinsic_load_input => {
let addr = u16::try_from(intrin.base()).unwrap();
let vtx = Src::new_zero();
let offset = self.get_src(&srcs[0]);
let dst = self.get_dst(&intrin.def);
self.instrs.push(Instr::new_ald(dst, addr, vtx, offset));
}
nir_intrinsic_load_per_vertex_input => {
let addr = u16::try_from(intrin.base()).unwrap();
let vtx = self.get_src(&srcs[0]);
let offset = self.get_src(&srcs[1]);
let dst = self.get_dst(&intrin.def);
self.instrs.push(Instr::new_ald(dst, addr, vtx, offset));
}
nir_intrinsic_store_output => {
if self.nir.info.stage() == MESA_SHADER_FRAGMENT {
/* We assume these only ever happen in the last block.
* This is ensured by nir_lower_io_to_temporaries()
*/
let data = self.get_src(&srcs[0]);
assert!(srcs[1].is_zero());
let base: u8 = intrin.base().try_into().unwrap();
let mut dsts = Vec::new();
for c in 0..intrin.num_components {
let tmp = self.alloc_ssa(RegFile::GPR, 1);
self.fs_out_regs[(base + c) as usize] = tmp;
dsts.push(tmp);
}
self.instrs.push(Instr::new_split(&dsts, data))
} else {
let data = self.get_src(&srcs[0]);
let vtx = Src::new_zero();
let offset = self.get_src(&srcs[1]);
let addr: u16 = intrin.base().try_into().unwrap();
self.instrs.push(Instr::new_ast(addr, data, vtx, offset))
}
}
_ => panic!("Unsupported intrinsic instruction"),
}
}
fn parse_load_const(&mut self, load_const: &nir_load_const_instr) {
let dst = self.ref_for_nir_def(&load_const.def);
let mut srcs = Vec::new();
for c in 0..load_const.def.num_components {
assert!(load_const.def.bit_size == 32);
let imm_u32 = unsafe { load_const.values()[c as usize].u32_ };
srcs.push(Src::new_imm_u32(imm_u32));
}
self.instrs.push(Instr::new_vec(dst, &srcs));
}
fn parse_undef(&mut self, _ssa_undef: &nir_undef_instr) {
panic!("SSA undef not implemented yet");
}
fn parse_basic_block(&mut self, nb: &nir_block) -> BasicBlock {
for ni in nb.iter_instr_list() {
match ni.type_ {
nir_instr_type_alu => self.parse_alu(ni.as_alu().unwrap()),
nir_instr_type_jump => self.parse_jump(ni.as_jump().unwrap()),
nir_instr_type_tex => self.parse_tex(ni.as_tex().unwrap()),
nir_instr_type_intrinsic => {
self.parse_intrinsic(ni.as_intrinsic().unwrap())
}
nir_instr_type_load_const => {
self.parse_load_const(ni.as_load_const().unwrap())
}
nir_instr_type_undef => {
self.parse_undef(ni.as_undef().unwrap())
}
_ => panic!("Unsupported instruction type"),
}
}
let mut b = BasicBlock::new(0 /* TODO: Block indices */);
b.instrs.append(&mut self.instrs);
b
}
pub fn parse_function_impl(&mut self, nfi: &nir_function_impl) -> Function {
self.func = Some(Function::new(0, nfi.ssa_alloc));
for node in nfi.iter_body() {
/* TODO: Control-flow */
let b = self.parse_basic_block(node.as_block().unwrap());
self.func.as_mut().unwrap().blocks.push(b);
}
let end_block = self.func.as_mut().unwrap().blocks.last_mut().unwrap();
if self.nir.info.stage() == MESA_SHADER_FRAGMENT
&& nfi.function().is_entrypoint
{
let fs_out_regs =
std::mem::replace(&mut self.fs_out_regs, Vec::new());
end_block.instrs.push(Instr::new_fs_out(&fs_out_regs));
}
end_block.instrs.push(Instr::new_exit());
self.func.take().unwrap()
}
pub fn parse_shader(&mut self) -> Shader {
let mut s = Shader::new();
for nf in self.nir.iter_functions() {
if let Some(nfi) = nf.get_impl() {
let f = self.parse_function_impl(nfi);
s.functions.push(f);
}
}
s
}
}
pub fn nak_shader_from_nir(ns: &nir_shader) -> Shader {
ShaderFromNir::new(ns).parse_shader()
}