diff --git a/VL.OpenEXR.vl b/VL.OpenEXR.vl index e0d8386..eeb066f 100644 --- a/VL.OpenEXR.vl +++ b/VL.OpenEXR.vl @@ -1,548 +1,534 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/help/Example Write an exr texture.vl b/help/Example Write an exr texture.vl new file mode 100644 index 0000000..97e1581 --- /dev/null +++ b/help/Example Write an exr texture.vl @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + High + + + + + + + + + + + + + + + + + + + + + + Bang + + + + + + + + 9 + Link + + + + + + + + 9 + Comment + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/native/VL.OpenEXR.Native.dll b/lib/native/VL.OpenEXR.Native.dll deleted file mode 100644 index dbbe7f3..0000000 Binary files a/lib/native/VL.OpenEXR.Native.dll and /dev/null differ diff --git a/lib/net8.0/VL.OpenEXR.dll b/lib/net8.0/VL.OpenEXR.dll new file mode 100644 index 0000000..0a5e121 Binary files /dev/null and b/lib/net8.0/VL.OpenEXR.dll differ diff --git a/lib/netstandard2.0/VL.OpenEXR.dll b/lib/netstandard2.0/VL.OpenEXR.dll deleted file mode 100644 index 8ab1315..0000000 Binary files a/lib/netstandard2.0/VL.OpenEXR.dll and /dev/null differ diff --git a/runtimes/win-x64/native/VL.OpenEXR.Native.dll b/runtimes/win-x64/native/VL.OpenEXR.Native.dll new file mode 100644 index 0000000..3705aa5 Binary files /dev/null and b/runtimes/win-x64/native/VL.OpenEXR.Native.dll differ diff --git a/src/VL.OpenEXR.cs b/src/VL.OpenEXR.cs index 91d9cf6..6b50735 100644 --- a/src/VL.OpenEXR.cs +++ b/src/VL.OpenEXR.cs @@ -13,6 +13,14 @@ enum ExrPixelFormat RGBF32 = 3 } + public enum ExrEncoding { + Uncompressed = 0, + RLE = 1, + ZIP1 = 2, + ZIP16 = 3, + PIZ = 4, + } + public static class ExrLoader { #pragma warning disable CA5393 @@ -21,7 +29,7 @@ public static class ExrLoader [DllImport("../native/VL.OpenEXR.Native.dll")] static extern IntPtr load_from_path(string path, out int width, out int height, out ExrPixelFormat format); - public static Texture LoadFromPath(string path, GraphicsDevice device, CommandList commandList) + public static Texture LoadFromPath(string path, GraphicsDevice device) { ExrPixelFormat exrFormat; PixelFormat format; @@ -32,7 +40,7 @@ public static Texture LoadFromPath(string path, GraphicsDevice device, CommandLi format = PixelFormat.None; return null; } - + int sizeInBytes = 0; bool hasAlpha = true; (format, sizeInBytes, hasAlpha) = exrFormat switch @@ -44,10 +52,12 @@ public static Texture LoadFromPath(string path, GraphicsDevice device, CommandLi _ => (PixelFormat.None, 0, false), }; - var dataPointer = new DataPointer(ptr, width * height * (hasAlpha?4:3) * sizeInBytes); + var rowPitch = width * (hasAlpha ? 4 : 3) * sizeInBytes; - var texture = Texture.New2D(device, width, height, format); - texture.SetData(commandList, dataPointer); + var texture = Texture.New( + device, + TextureDescription.New2D(width, height, format, usage: GraphicsResourceUsage.Immutable), + new DataBox(ptr, rowPitch, rowPitch * height)); Marshal.FreeCoTaskMem(ptr); @@ -55,15 +65,20 @@ public static Texture LoadFromPath(string path, GraphicsDevice device, CommandLi } } - public static class ExrWriter + public static unsafe class ExrWriter { #pragma warning disable CA5393 [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] [DllImport("../native/VL.OpenEXR.Native.dll")] - static extern void write_texture(string path, int width, int height, ExrPixelFormat format, IntPtr data); - - public static void WriteTexture(byte[] data, string path, int width, int height, PixelFormat format) + static extern int write_texture(string path, int width, int height, ExrPixelFormat format, ExrEncoding encoding, IntPtr data); + + public static int WriteTexture(byte[] data, string path, int width, int height, PixelFormat format, ExrEncoding encoding) + { + return WriteTexture((ReadOnlySpan)data, path, width, height, format, encoding); + } + + public static int WriteTexture(ReadOnlySpan data, string path, int width, int height, PixelFormat format, ExrEncoding encoding) { ExrPixelFormat exrFormat = format switch { @@ -73,20 +88,11 @@ public static void WriteTexture(byte[] data, string path, int width, int height, _ => ExrPixelFormat.Unknown }; - if(exrFormat == ExrPixelFormat.Unknown) return; + if(exrFormat == ExrPixelFormat.Unknown) return 1; //return with error - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); - try - { - write_texture(path, width, height, exrFormat, handle.AddrOfPinnedObject()); - } - catch(Exception e) - { - Console.WriteLine(e); - } - finally - { - handle.Free(); + fixed (byte* pointer = data) + { + return write_texture(path, width, height, exrFormat, encoding, new IntPtr(pointer)); } } } diff --git a/src/VL.OpenEXR.csproj b/src/VL.OpenEXR.csproj index 7c1c5fa..7189b77 100644 --- a/src/VL.OpenEXR.csproj +++ b/src/VL.OpenEXR.csproj @@ -1,23 +1,13 @@ - + - netstandard2.0 - 8.0 + net8.0 + ..\lib + true - - False - lib\Stride.dll - - - False - lib\Stride.Core.dll - - - False - lib\Steide.Graphics.dll - + diff --git a/src/VL.OpenEXR.sln b/src/VL.OpenEXR.sln index a41aa39..1d104be 100644 --- a/src/VL.OpenEXR.sln +++ b/src/VL.OpenEXR.sln @@ -1,25 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31129.286 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VL.OpenEXR", "VL.OpenEXR.csproj", "{FDC6242A-4830-412E-8A76-BF776C864EF9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FDC6242A-4830-412E-8A76-BF776C864EF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FDC6242A-4830-412E-8A76-BF776C864EF9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FDC6242A-4830-412E-8A76-BF776C864EF9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FDC6242A-4830-412E-8A76-BF776C864EF9}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {3C82B099-E534-4942-8049-DCF7C225D615} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VL.OpenEXR", "VL.OpenEXR.csproj", "{FDC6242A-4830-412E-8A76-BF776C864EF9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FDC6242A-4830-412E-8A76-BF776C864EF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FDC6242A-4830-412E-8A76-BF776C864EF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDC6242A-4830-412E-8A76-BF776C864EF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDC6242A-4830-412E-8A76-BF776C864EF9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3C82B099-E534-4942-8049-DCF7C225D615} + EndGlobalSection +EndGlobal diff --git a/src/native/.cargo/config.toml b/src/native/.cargo/config.toml new file mode 100644 index 0000000..8d22ea8 --- /dev/null +++ b/src/native/.cargo/config.toml @@ -0,0 +1,13 @@ +#paths = ["/home/arturo/Code/na"] + +[build] +target-dir = "./target" +#rustflags = ["-Clink-arg=-fuse-ld=lld", "-Zshare-generics"] +#rustflags = ["-Clink-arg=-fuse-ld=lld"] +#rustflags = ["-Clink-arg=-fuse-ld=mold"] +#pipelining = true + +[target.x86_64-unknown-linux-gnu] +linker = "clang" +#rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/mold", "-Zshare-generics"] +rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/mold"] diff --git a/src/native/Cargo.toml b/src/native/Cargo.toml index a1a0e7c..85e8fa6 100644 --- a/src/native/Cargo.toml +++ b/src/native/Cargo.toml @@ -9,7 +9,7 @@ name = "vl_openexr_native" crate-type = ["cdylib"] [dependencies] -exr = "1.4.1" +exr = "1.72.0" radiant = "0.3.0" [profile.release] diff --git a/src/native/src/lib.rs b/src/native/src/lib.rs index 68a3be4..a604fdf 100644 --- a/src/native/src/lib.rs +++ b/src/native/src/lib.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::fs::File; use std::io::BufReader; use std::os::raw::c_char; @@ -6,60 +7,116 @@ use std::ffi::CStr; use std::path::Path; use std::slice::from_raw_parts; +use exr::error::UnitResult; use exr::prelude::*; +#[derive(Clone, Copy, Debug)] +#[repr(u32)] +pub enum ExrEncoding { + Uncompressed = 0, + RLE = 1, + ZIP1 = 2, + ZIP16 = 3, + PIZ = 4, +} + +#[derive(Clone, Copy, Debug)] +#[repr(i32)] +pub enum ExrPixelFormat +{ + Unknown = -1, + U32 = 0, + F16 = 1, + F32 = 2, + RGBF32 = 3 +} + #[no_mangle] -pub unsafe extern fn write_texture(path: *const c_char, width: i32, height: i32, format: i32, data: *const Sample) { - let path_str = CStr::from_ptr(path).to_str().unwrap(); +pub unsafe extern fn write_texture(path: *const c_char, width: i32, height: i32, format: ExrPixelFormat, encoding: ExrEncoding, data: *const Sample) -> i32 { + let path = match CStr::from_ptr(path).to_str() { + Ok(path) => path, + Err(err) => { + println!("{err}"); + return 1 + } + }; - match format { - 0 => { // U32 + let result = match format { + ExrPixelFormat::U32 => { let ptr = data as *const u32; let array = from_raw_parts(ptr, (width * height * 4) as usize); - write_rgba_file( - path_str, - width as usize, height as usize, - |x,y| ( - array[(y * (width as usize) + x) * 4 + 0], - array[(y * (width as usize) + x) * 4 + 1], - array[(y * (width as usize) + x) * 4 + 2], - array[(y * (width as usize) + x) * 4 + 3] - ) - ).unwrap(); + write_exr(path, array, width as usize, height as usize, encoding) }, - 1 => { // F16 + ExrPixelFormat::F16 => { let ptr = data as *const f16; let array = from_raw_parts(ptr, (width * height * 4) as usize); - write_rgba_file( - path_str, - width as usize, height as usize, - |x,y| ( - array[(y * (width as usize) + x) * 4 + 0], - array[(y * (width as usize) + x) * 4 + 1], - array[(y * (width as usize) + x) * 4 + 2], - array[(y * (width as usize) + x) * 4 + 3] - ) - ).unwrap(); + write_exr(path, array, width as usize, height as usize, encoding) }, - 2 => { // F32 + ExrPixelFormat::F32 => { let ptr = data as *const f32; let array = from_raw_parts(ptr, (width * height * 4) as usize); - write_rgba_file( - path_str, - width as usize, height as usize, - |x,y| ( - array[(y * (width as usize) + x) * 4 + 0], - array[(y * (width as usize) + x) * 4 + 1], - array[(y * (width as usize) + x) * 4 + 2], - array[(y * (width as usize) + x) * 4 + 3] - ) - ).unwrap(); + write_exr(path, array, width as usize, height as usize, encoding) } - _ => { // Unknown + _ => { + // Unknown + Err(Error::NotSupported(Cow::Owned(format!("Encoding {encoding:?} not supported")))) } + }; + + match result { + Ok(()) => 0, + Err(err) => { + println!("{err}"); + 1 + }, } } +fn write_exr(path: impl AsRef, array: &[T], width: usize, height: usize, encoding: ExrEncoding) -> UnitResult { + let channels = SpecificChannels::rgba(|Vec2(x,y)| ( + array[(y * width + x) * 4 + 0], + array[(y * width + x) * 4 + 1], + array[(y * width + x) * 4 + 2], + array[(y * width + x) * 4 + 3] + )); + let encoding = match encoding { + // See encoding presets but expanded here to make clearer the + // encoding compression + ExrEncoding::Uncompressed => Encoding { + compression: Compression::Uncompressed, + blocks: Blocks::ScanLines, // longest lines, faster memcpy + line_order: LineOrder::Increasing // presumably fastest? + }, + ExrEncoding::RLE => Encoding { + compression: Compression::RLE, + blocks: Blocks::Tiles(Vec2(64, 64)), // optimize for RLE compression + line_order: LineOrder::Unspecified + }, + ExrEncoding::ZIP16 => Encoding { + compression: Compression::ZIP16, + blocks: Blocks::ScanLines, // largest possible, but also with high probability of parallel workers + line_order: LineOrder::Increasing + }, + ExrEncoding::PIZ => Encoding { + compression: Compression::PIZ, + blocks: Blocks::Tiles(Vec2(256, 256)), + line_order: LineOrder::Unspecified + }, + ExrEncoding::ZIP1 => Encoding { + compression: Compression::ZIP1, + blocks: Blocks::ScanLines, + line_order: LineOrder::Increasing + } + }; + let layer = Layer::new( + Vec2(width, height), + LayerAttributes::named("first layer"), + encoding, + channels + ); + Image::from_layer(layer).write().to_file(path) +} + #[no_mangle] pub unsafe extern fn load_from_path(path: *const c_char, width: *mut i32, height: *mut i32, format: *mut i32) -> *mut [Sample;4] { let path_str = CStr::from_ptr(path).to_str().unwrap(); @@ -85,13 +142,13 @@ pub unsafe extern fn load_from_path(path: *const c_char, width: *mut i32, height let size = meta.headers[0].layer_size; *width = size.0 as i32; *height = size.1 as i32; - + let sample_type = meta.headers[0].channels.uniform_sample_type; - + match sample_type { Some(v) => { *format = v as i32; - + match v { SampleType::F16 => load_exr_f16(path_str) as *mut [Sample;4], SampleType::F32 => load_exr_f32(path_str) as *mut [Sample;4], @@ -108,7 +165,7 @@ pub unsafe extern fn load_from_path(path: *const c_char, width: *mut i32, height *width = -1; *height = -1; *format = -1; - + std::ptr::null_mut() as *mut [Sample;4] } } @@ -134,7 +191,7 @@ fn load_exr_f16(path: &str) -> usize { let mut pixel = image.layer_data.channel_data.pixels.into_iter().flatten().collect::>(); let ptr = pixel.as_mut_ptr(); mem::forget(pixel); - + return unsafe { mem::transmute(ptr) }; } @@ -156,7 +213,7 @@ fn load_exr_f32(path: &str) -> usize { let mut pixel = image.layer_data.channel_data.pixels.into_iter().flatten().collect::>(); let ptr = pixel.as_mut_ptr(); mem::forget(pixel); - + return unsafe { mem::transmute(ptr) }; } @@ -178,7 +235,7 @@ fn load_exr_u32(path: &str) -> usize { let mut pixel = image.layer_data.channel_data.pixels.into_iter().flatten().collect::>(); let ptr = pixel.as_mut_ptr(); mem::forget(pixel); - + return unsafe { mem::transmute(ptr) }; } @@ -202,6 +259,6 @@ fn load_exr_u32(path: &str) -> usize { // let mut pixel = image.layer_data.channel_data.pixels.into_iter().flatten().collect::>(); // let ptr = pixel.as_mut_ptr(); // mem::forget(pixel); - + // return unsafe { mem::transmute(ptr) }; -// } +// } \ No newline at end of file