gl: get some more reflection work done
This commit is contained in:
parent
6fcee1691f
commit
66d1c872ee
|
@ -6,14 +6,14 @@ use crate::reflect::cross::{CompiledAst, CrossReflect, GlslReflect, HlslReflect}
|
||||||
use crate::reflect::ReflectShader;
|
use crate::reflect::ReflectShader;
|
||||||
|
|
||||||
pub type GlVersion = spirv_cross::glsl::Version;
|
pub type GlVersion = spirv_cross::glsl::Version;
|
||||||
pub struct GlslangCompileContext {
|
pub struct GlslangGlslContext {
|
||||||
pub texture_fixups: Vec<u32>,
|
pub texture_fixups: Vec<u32>,
|
||||||
pub compiler: CompiledAst<spirv_cross::glsl::Target>
|
pub compiler: CompiledAst<spirv_cross::glsl::Target>
|
||||||
}
|
}
|
||||||
impl FromCompilation<GlslangCompilation> for GLSL {
|
impl FromCompilation<GlslangCompilation> for GLSL {
|
||||||
type Target = GLSL;
|
type Target = GLSL;
|
||||||
type Options = GlVersion;
|
type Options = GlVersion;
|
||||||
type Context = GlslangCompileContext;
|
type Context = GlslangGlslContext;
|
||||||
|
|
||||||
fn from_compilation(
|
fn from_compilation(
|
||||||
compile: GlslangCompilation,
|
compile: GlslangCompilation,
|
||||||
|
|
|
@ -15,7 +15,7 @@ use spirv_cross::{glsl, hlsl, ErrorCode};
|
||||||
|
|
||||||
use crate::back::targets::{GLSL, HLSL};
|
use crate::back::targets::{GLSL, HLSL};
|
||||||
use crate::back::{CompileShader, ShaderCompilerOutput};
|
use crate::back::{CompileShader, ShaderCompilerOutput};
|
||||||
use crate::back::cross::GlslangCompileContext;
|
use crate::back::cross::GlslangGlslContext;
|
||||||
|
|
||||||
pub struct CrossReflect<T>
|
pub struct CrossReflect<T>
|
||||||
where
|
where
|
||||||
|
@ -291,7 +291,6 @@ where
|
||||||
blame: SemanticErrorBlame,
|
blame: SemanticErrorBlame,
|
||||||
) -> Result<(), ShaderReflectError> {
|
) -> Result<(), ShaderReflectError> {
|
||||||
let ranges = ast.get_active_buffer_ranges(resource.id)?;
|
let ranges = ast.get_active_buffer_ranges(resource.id)?;
|
||||||
eprintln!("{ranges:?}");
|
|
||||||
for range in ranges {
|
for range in ranges {
|
||||||
let name = ast.get_member_name(resource.base_type_id, range.index)?;
|
let name = ast.get_member_name(resource.base_type_id, range.index)?;
|
||||||
let ubo_type = ast.get_type(resource.base_type_id)?;
|
let ubo_type = ast.get_type(resource.base_type_id)?;
|
||||||
|
@ -333,6 +332,7 @@ where
|
||||||
meta.parameter_meta.insert(
|
meta.parameter_meta.insert(
|
||||||
parameter.index,
|
parameter.index,
|
||||||
VariableMeta {
|
VariableMeta {
|
||||||
|
id: name,
|
||||||
offset,
|
offset,
|
||||||
components: typeinfo.size,
|
components: typeinfo.size,
|
||||||
},
|
},
|
||||||
|
@ -360,6 +360,7 @@ where
|
||||||
meta.variable_meta.insert(
|
meta.variable_meta.insert(
|
||||||
*semantics,
|
*semantics,
|
||||||
VariableMeta {
|
VariableMeta {
|
||||||
|
id: name,
|
||||||
offset,
|
offset,
|
||||||
components: typeinfo.size * typeinfo.columns,
|
components: typeinfo.size * typeinfo.columns,
|
||||||
},
|
},
|
||||||
|
@ -381,6 +382,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this will break if range is both ubo and push buf whatever
|
||||||
let offset = offset_type(range.offset);
|
let offset = offset_type(range.offset);
|
||||||
if let Some(meta) = meta.texture_size_meta.get_mut(&texture) {
|
if let Some(meta) = meta.texture_size_meta.get_mut(&texture) {
|
||||||
if offset != meta.offset {
|
if offset != meta.offset {
|
||||||
|
@ -405,6 +407,7 @@ where
|
||||||
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
||||||
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
||||||
},
|
},
|
||||||
|
id: name
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -683,7 +686,7 @@ where
|
||||||
|
|
||||||
impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
|
impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
|
||||||
type Options = glsl::Version;
|
type Options = glsl::Version;
|
||||||
type Context = GlslangCompileContext;
|
type Context = GlslangGlslContext;
|
||||||
|
|
||||||
fn compile(
|
fn compile(
|
||||||
mut self,
|
mut self,
|
||||||
|
@ -745,9 +748,9 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
for res in &vertex_resources.uniform_buffers {
|
for res in &vertex_resources.uniform_buffers {
|
||||||
if flatten {
|
// if flatten {
|
||||||
self.vertex.flatten_buffer_block(res.id)?;
|
// self.vertex.flatten_buffer_block(res.id)?;
|
||||||
}
|
// }
|
||||||
self.vertex.set_name(res.id, "RARCH_UBO_VERTEX_INSTANCE")?;
|
self.vertex.set_name(res.id, "RARCH_UBO_VERTEX_INSTANCE")?;
|
||||||
self.vertex.set_name(res.base_type_id, "RARCH_UBO_VERTEX")?;
|
self.vertex.set_name(res.base_type_id, "RARCH_UBO_VERTEX")?;
|
||||||
self.vertex
|
self.vertex
|
||||||
|
@ -778,9 +781,9 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for res in &fragment_resources.uniform_buffers {
|
for res in &fragment_resources.uniform_buffers {
|
||||||
if flatten {
|
// if flatten {
|
||||||
self.fragment.flatten_buffer_block(res.id)?;
|
// self.fragment.flatten_buffer_block(res.id)?;
|
||||||
}
|
// }
|
||||||
self.fragment
|
self.fragment
|
||||||
.set_name(res.id, "RARCH_UBO_FRAGMENT_INSTANCE")?;
|
.set_name(res.id, "RARCH_UBO_FRAGMENT_INSTANCE")?;
|
||||||
self.fragment
|
self.fragment
|
||||||
|
@ -806,7 +809,7 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
|
||||||
Ok(ShaderCompilerOutput {
|
Ok(ShaderCompilerOutput {
|
||||||
vertex: self.vertex.compile()?,
|
vertex: self.vertex.compile()?,
|
||||||
fragment: self.fragment.compile()?,
|
fragment: self.fragment.compile()?,
|
||||||
context: GlslangCompileContext {
|
context: GlslangGlslContext {
|
||||||
texture_fixups,
|
texture_fixups,
|
||||||
compiler: CompiledAst {
|
compiler: CompiledAst {
|
||||||
vertex: self.vertex,
|
vertex: self.vertex,
|
||||||
|
|
|
@ -122,6 +122,7 @@ pub struct VariableMeta {
|
||||||
// this might bite us in the back because retroarch keeps separate UBO/push offsets.. eh
|
// this might bite us in the back because retroarch keeps separate UBO/push offsets.. eh
|
||||||
pub offset: MemberOffset,
|
pub offset: MemberOffset,
|
||||||
pub components: u32,
|
pub components: u32,
|
||||||
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -129,6 +130,7 @@ pub struct TextureSizeMeta {
|
||||||
// this might bite us in the back because retroarch keeps separate UBO/push offsets..
|
// this might bite us in the back because retroarch keeps separate UBO/push offsets..
|
||||||
pub offset: MemberOffset,
|
pub offset: MemberOffset,
|
||||||
pub stage_mask: BindingStage,
|
pub stage_mask: BindingStage,
|
||||||
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -3,18 +3,19 @@ mod hello_triangle;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use gl::types::{GLenum, GLuint};
|
use gl::types::{GLenum, GLint, GLsizeiptr, GLuint};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use spirv_cross::spirv::Decoration;
|
||||||
|
|
||||||
use librashader::ShaderSource;
|
use librashader::ShaderSource;
|
||||||
use librashader_presets::ShaderPassConfig;
|
use librashader_presets::ShaderPassConfig;
|
||||||
use librashader_reflect::back::CompileShader;
|
use librashader_reflect::back::{CompileShader, ShaderCompilerOutput};
|
||||||
use librashader_reflect::back::cross::GlVersion;
|
use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion};
|
||||||
use librashader_reflect::back::targets::{FromCompilation, GLSL};
|
use librashader_reflect::back::targets::{FromCompilation, GLSL};
|
||||||
use librashader_reflect::front::shaderc::GlslangCompilation;
|
use librashader_reflect::front::shaderc::GlslangCompilation;
|
||||||
use librashader_reflect::reflect::cross::CrossReflect;
|
use librashader_reflect::reflect::cross::CrossReflect;
|
||||||
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
|
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, ShaderReflection, UniformSemantic};
|
||||||
use librashader_reflect::reflect::semantics::{SemanticMap, TextureSemantics, VariableSemantics};
|
use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, VariableMeta, VariableSemantics};
|
||||||
use librashader_reflect::reflect::{TextureSemanticMap, VariableSemanticMap};
|
use librashader_reflect::reflect::{TextureSemanticMap, VariableSemanticMap};
|
||||||
|
|
||||||
pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
|
pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
|
||||||
|
@ -52,7 +53,97 @@ pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSema
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RingBuffer<T, const SIZE: usize> {
|
||||||
|
items: [T; SIZE],
|
||||||
|
index: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T, const SIZE: usize> RingBuffer<T, SIZE>
|
||||||
|
where T: Copy, T: Default
|
||||||
|
{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
items: [T::default(); SIZE],
|
||||||
|
index: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T, const SIZE: usize> RingBuffer<T, SIZE> {
|
||||||
|
pub fn current(&self) -> &T {
|
||||||
|
&self.items[self.index]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(&mut self) {
|
||||||
|
self.index += 1;
|
||||||
|
if self.index >= SIZE {
|
||||||
|
self.index = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Location<T> {
|
||||||
|
vertex: T,
|
||||||
|
fragment: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParameterLocation {
|
||||||
|
Ubo(Location<GLint>),
|
||||||
|
Push(Location<GLint>),
|
||||||
|
}
|
||||||
|
pub struct FilterPass {
|
||||||
|
reflection: ShaderReflection,
|
||||||
|
compiled: ShaderCompilerOutput<String, GlslangGlslContext>,
|
||||||
|
program: GLuint,
|
||||||
|
ubo_location: Location<GLuint>,
|
||||||
|
ubo_ring: Option<RingBuffer<GLuint, 16>>,
|
||||||
|
uniform_buffer: Vec<u8>,
|
||||||
|
push_buffer: Vec<u8>,
|
||||||
|
locations: FxHashMap<String, ParameterLocation>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FilterChain {
|
||||||
|
reflections: Vec<ShaderReflection>,
|
||||||
|
compiled: Vec<ShaderCompilerOutput<String, GlslangGlslContext>>,
|
||||||
|
programs: Vec<GLuint>,
|
||||||
|
ubo_location: Location<GLint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reflect_parameter(pipeline: GLuint, meta: &VariableMeta) -> ParameterLocation {
|
||||||
|
// todo: support both ubo and pushco
|
||||||
|
// todo: fix this.
|
||||||
|
match meta.offset {
|
||||||
|
MemberOffset::Ubo(_) => {
|
||||||
|
let vert_name = format!("RARCH_UBO_VERTEX_INSTANCE.{}\0", meta.id);
|
||||||
|
let frag_name = format!("RARCH_UBO_FRAGMENT_INSTANCE.{}\0", meta.id);
|
||||||
|
unsafe {
|
||||||
|
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
||||||
|
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
||||||
|
|
||||||
|
ParameterLocation::Ubo(Location {
|
||||||
|
vertex,
|
||||||
|
fragment
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MemberOffset::PushConstant(_) => {
|
||||||
|
let vert_name = format!("RARCH_PUSH_VERTEX_INSTANCE.{}\0", meta.id);
|
||||||
|
let frag_name = format!("RARCH_PUSH_FRAGMENT_INSTANCE.{}\0", meta.id);
|
||||||
|
unsafe {
|
||||||
|
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
||||||
|
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
||||||
|
|
||||||
|
ParameterLocation::Push(Location {
|
||||||
|
vertex,
|
||||||
|
fragment
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// todo: init gl
|
// todo: init gl
|
||||||
|
|
||||||
pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
|
pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
|
||||||
|
@ -96,41 +187,114 @@ pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
|
||||||
non_uniform_semantics: texture_semantics
|
non_uniform_semantics: texture_semantics
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut reflections = Vec::new();
|
let mut filters = Vec::new();
|
||||||
let mut compiled = Vec::new();
|
|
||||||
|
|
||||||
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
|
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
|
||||||
let reflection = reflect.reflect(index as u32, &semantics)?;
|
let reflection = reflect.reflect(index as u32, &semantics)?;
|
||||||
let glsl = reflect.compile(GlVersion::V4_60)?;
|
let glsl = reflect.compile(GlVersion::V4_60)?;
|
||||||
|
|
||||||
|
let vertex_resources = glsl.context.compiler.vertex.get_shader_resources()?;
|
||||||
|
|
||||||
// shader_gl3: 1375
|
// todo: split this out.
|
||||||
reflection.meta.texture_meta.get(&SemanticMap {
|
let (program, ubo_location) = unsafe {
|
||||||
semantics: TextureSemantics::Source,
|
let vertex = gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str());
|
||||||
index: 0
|
let fragment = gl_compile_shader(gl::FRAGMENT_SHADER, glsl.fragment.as_str());
|
||||||
}).unwrap().binding;
|
|
||||||
|
|
||||||
// unsafe {
|
let program = gl::CreateProgram();
|
||||||
// let vertex = gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str());
|
gl::AttachShader(program, vertex);
|
||||||
// let fragment = gl_compile_shader(gl::FRAGMENT_SHADER, glsl.fragment.as_str());
|
gl::AttachShader(program, fragment);
|
||||||
//
|
|
||||||
// let program = gl::CreateProgram();
|
for res in &vertex_resources.stage_inputs {
|
||||||
// gl::AttachShader(program, vertex);
|
let loc = glsl.context.compiler.vertex.get_decoration(res.id, Decoration::Location)?;
|
||||||
// gl::AttachShader(program, fragment);
|
let loc_name = format!("RARCH_ATTRIBUTE_{loc}");
|
||||||
//
|
gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast())
|
||||||
// }
|
}
|
||||||
|
gl::LinkProgram(program);
|
||||||
|
gl::DeleteShader(vertex);
|
||||||
|
gl::DeleteShader(fragment);
|
||||||
|
|
||||||
|
let mut status = 0;
|
||||||
|
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
|
||||||
|
if status != 1 {
|
||||||
|
panic!("failed to link program")
|
||||||
|
}
|
||||||
|
|
||||||
|
for binding in &glsl.context.texture_fixups {
|
||||||
|
let loc_name = format!("RARCH_TEXTURE_{}", *binding);
|
||||||
|
unsafe {
|
||||||
|
let location = gl::GetUniformLocation(program, loc_name.as_str().as_ptr().cast());
|
||||||
|
if location >= 0 {
|
||||||
|
gl::Uniform1i(location, *binding as GLint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
gl::UseProgram(0);
|
||||||
|
(program, Location {
|
||||||
|
vertex: gl::GetUniformBlockIndex(program, b"RARCH_UBO_VERTEX\0".as_ptr().cast()),
|
||||||
|
fragment: gl::GetUniformBlockIndex(program, b"RARCH_UBO_FRAGMENT\0".as_ptr().cast()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let ubo_ring = if let Some(ubo) = &reflection.ubo {
|
||||||
|
let size = ubo.size;
|
||||||
|
let mut ring: RingBuffer<GLuint, 16> = RingBuffer::new();
|
||||||
|
unsafe {
|
||||||
|
gl::GenBuffers(16, ring.items.as_mut_ptr());
|
||||||
|
for buffer in &ring.items {
|
||||||
|
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
|
||||||
|
gl::BufferData(gl::UNIFORM_BUFFER, size as GLsizeiptr, std::ptr::null(), gl::STREAM_DRAW);
|
||||||
|
}
|
||||||
|
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
|
||||||
|
}
|
||||||
|
Some(ring)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let uniform_buffer = vec![0; reflection.ubo.as_ref().map(|ubo| ubo.size as usize).unwrap_or(0)];
|
||||||
|
let push_buffer = vec![0; reflection.push_constant.as_ref().map(|push| push.size as usize).unwrap_or(0)];
|
||||||
|
|
||||||
|
// todo: reflect indexed parameters
|
||||||
|
let mut locations = FxHashMap::default();
|
||||||
|
for param in reflection.meta.parameter_meta.values() {
|
||||||
|
locations.insert(param.id.clone(), reflect_parameter(program, param));
|
||||||
|
}
|
||||||
|
|
||||||
|
for param in reflection.meta.variable_meta.values() {
|
||||||
|
locations.insert(param.id.clone(), reflect_parameter(program, param));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
compiled.push(glsl);
|
eprintln!("{:#?}", semantics);
|
||||||
reflections.push(reflection);
|
eprintln!("{:#?}", reflection.meta);
|
||||||
|
eprintln!("{:#?}", locations);
|
||||||
|
eprintln!("{:#?}", reflection.push_constant);
|
||||||
|
eprintln!("====fragment====");
|
||||||
|
eprintln!("{:#}", glsl.fragment);
|
||||||
|
eprintln!("====vertex====");
|
||||||
|
eprintln!("{:#}", glsl.vertex);
|
||||||
|
|
||||||
|
filters.push(FilterPass {
|
||||||
|
reflection,
|
||||||
|
compiled: glsl,
|
||||||
|
program,
|
||||||
|
ubo_location,
|
||||||
|
ubo_ring,
|
||||||
|
uniform_buffer,
|
||||||
|
push_buffer,
|
||||||
|
locations
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut glprogram: Vec<GLuint> = Vec::new();
|
// let mut glprogram: Vec<GLuint> = Vec::new();
|
||||||
for compilation in &compiled {
|
// for compilation in &compiled {
|
||||||
// compilation.context.compiler.vertex
|
// // compilation.context.compiler.vertex
|
||||||
}
|
// }
|
||||||
|
|
||||||
eprintln!("{:#?}", reflections);
|
// eprintln!("{:#?}", reflections);
|
||||||
|
|
||||||
// eprintln!("{:#?}", compiled./);
|
// eprintln!("{:#?}", compiled./);
|
||||||
// eprintln!("{:?}", preset);
|
// eprintln!("{:?}", preset);
|
||||||
|
@ -164,13 +328,15 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn triangle() {
|
fn triangle() {
|
||||||
let (glfw, window, events, shader, vao) = hello_triangle::setup();
|
let (glfw, window, events, shader, vao) = hello_triangle::setup();
|
||||||
|
load("../test/basic.slangp")
|
||||||
|
.unwrap();
|
||||||
hello_triangle::do_loop(glfw, window, events, shader, vao);
|
hello_triangle::do_loop(glfw, window, events, shader, vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn load_preset() {
|
// fn load_preset() {
|
||||||
|
//
|
||||||
load("../test/basic.slangp")
|
// load("../test/basic.slangp")
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue