mirror of
https://github.com/DarthAffe/StableDiffusion.NET.git
synced 2025-12-13 05:48:40 +00:00
Compare commits
No commits in common. "a7ccbe8ef2713b798f30bf666f689048aa30e433" and "289abe4d2075016e7d371a13cefb214c926dcd2a" have entirely different histories.
a7ccbe8ef2
...
289abe4d20
@ -1,6 +1,8 @@
|
|||||||
# StableDiffusion.NET
|
# StableDiffusion.NET
|
||||||
|
|
||||||
Based on https://github.com/leejet/stable-diffusion.cpp
|
Based on
|
||||||
|
https://github.com/seasonjs/stable-diffusion.cpp-build
|
||||||
|
https://github.com/leejet/stable-diffusion.cpp
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
### Setup
|
### Setup
|
||||||
@ -9,5 +11,6 @@ Run `build.bat` to build the native libs (modify params like CUDA-builds if need
|
|||||||
### Example
|
### Example
|
||||||
```csharp
|
```csharp
|
||||||
using StableDiffusionModel sd = new(@"<path_to_model>", new ModelParameter());
|
using StableDiffusionModel sd = new(@"<path_to_model>", new ModelParameter());
|
||||||
using StableDiffusionImage image = sd.TextToImage("<prompt>", new StableDiffusionParameter());
|
using StableDiffusionParameter parameter = new StableDiffusionParameter();
|
||||||
|
using StableDiffusionImage image = sd.TextToImage("<prompt>", parameter);
|
||||||
```
|
```
|
||||||
|
|||||||
22
StableDiffusion.NET/Attributes/NativeName.cs
Normal file
22
StableDiffusion.NET/Attributes/NativeName.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace StableDiffusion.NET;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
|
internal class NativeName : Attribute
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public NativeName(string name)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -2,8 +2,15 @@
|
|||||||
|
|
||||||
public enum LogLevel
|
public enum LogLevel
|
||||||
{
|
{
|
||||||
|
[NativeName("DEBUG")]
|
||||||
Debug,
|
Debug,
|
||||||
|
|
||||||
|
[NativeName("INFO")]
|
||||||
Info,
|
Info,
|
||||||
|
|
||||||
|
[NativeName("WARN")]
|
||||||
Warn,
|
Warn,
|
||||||
|
|
||||||
|
[NativeName("ERROR")]
|
||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
@ -2,23 +2,27 @@
|
|||||||
|
|
||||||
public enum Quantization
|
public enum Quantization
|
||||||
{
|
{
|
||||||
F32 = 0,
|
[NativeName("DEFAULT")]
|
||||||
F16 = 1,
|
Default,
|
||||||
Q4_0 = 2,
|
|
||||||
Q4_1 = 3,
|
[NativeName("F32")]
|
||||||
// Q4_2 = 4, support has been removed
|
F32,
|
||||||
// Q4_3 (5) support has been removed
|
|
||||||
Q5_0 = 6,
|
[NativeName("F16")]
|
||||||
Q5_1 = 7,
|
F16,
|
||||||
Q8_0 = 8,
|
|
||||||
Q8_1 = 9,
|
[NativeName("Q4_0")]
|
||||||
Q2_K = 10,
|
Q4_0,
|
||||||
Q3_K = 11,
|
|
||||||
Q4_K = 12,
|
[NativeName("Q4_1")]
|
||||||
Q5_K = 13,
|
Q4_1,
|
||||||
Q6_K = 14,
|
|
||||||
Q8_K = 15,
|
[NativeName("Q5_0")]
|
||||||
I8,
|
Q5_0,
|
||||||
I16,
|
|
||||||
I32,
|
[NativeName("Q5_1")]
|
||||||
|
Q5_1,
|
||||||
|
|
||||||
|
[NativeName("Q8_0")]
|
||||||
|
Q8_0
|
||||||
}
|
}
|
||||||
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
public enum RngType
|
public enum RngType
|
||||||
{
|
{
|
||||||
|
[NativeName("STD_DEFAULT_RNG")]
|
||||||
Standard,
|
Standard,
|
||||||
|
|
||||||
|
[NativeName("CUDA_RNG")]
|
||||||
Cuda
|
Cuda
|
||||||
}
|
}
|
||||||
@ -2,13 +2,30 @@
|
|||||||
|
|
||||||
public enum Sampler
|
public enum Sampler
|
||||||
{
|
{
|
||||||
|
[NativeName("EULER_A")]
|
||||||
Euler_A,
|
Euler_A,
|
||||||
|
|
||||||
|
[NativeName("EULER")]
|
||||||
Euler,
|
Euler,
|
||||||
|
|
||||||
|
[NativeName("HEUN")]
|
||||||
Heun,
|
Heun,
|
||||||
|
|
||||||
|
[NativeName("DPM2")]
|
||||||
DPM2,
|
DPM2,
|
||||||
|
|
||||||
|
[NativeName("DPMPP2S_A")]
|
||||||
DPMPP2SA,
|
DPMPP2SA,
|
||||||
|
|
||||||
|
[NativeName("DPMPP2M")]
|
||||||
DPMPP2M,
|
DPMPP2M,
|
||||||
|
|
||||||
|
[NativeName("DPMPP2Mv2")]
|
||||||
DPMPP2Mv2,
|
DPMPP2Mv2,
|
||||||
|
|
||||||
|
[NativeName("LCM")]
|
||||||
LCM,
|
LCM,
|
||||||
|
|
||||||
|
[NativeName("N_SAMPLE_METHODS")]
|
||||||
N_Sample_Methods
|
N_Sample_Methods
|
||||||
}
|
}
|
||||||
@ -2,8 +2,15 @@
|
|||||||
|
|
||||||
public enum Schedule
|
public enum Schedule
|
||||||
{
|
{
|
||||||
|
[NativeName("DEFAULT")]
|
||||||
Default,
|
Default,
|
||||||
|
|
||||||
|
[NativeName("DISCRETE")]
|
||||||
Discrete,
|
Discrete,
|
||||||
|
|
||||||
|
[NativeName("KARRAS")]
|
||||||
Karras,
|
Karras,
|
||||||
|
|
||||||
|
[NativeName("N_SCHEDULES")]
|
||||||
N_Schedules
|
N_Schedules
|
||||||
}
|
}
|
||||||
18
StableDiffusion.NET/Extensions/EnumExtension.cs
Normal file
18
StableDiffusion.NET/Extensions/EnumExtension.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace StableDiffusion.NET;
|
||||||
|
|
||||||
|
internal static class EnumExtension
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public static string? GetNativeName(this Enum value)
|
||||||
|
{
|
||||||
|
FieldInfo? fieldInfo = value.GetType().GetField(value.ToString());
|
||||||
|
NativeName? nativeName = fieldInfo?.GetCustomAttribute<NativeName>();
|
||||||
|
return nativeName?.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -8,14 +8,13 @@ public class ModelParameter
|
|||||||
public bool VaeDecodeOnly { get; set; } = false;
|
public bool VaeDecodeOnly { get; set; } = false;
|
||||||
public bool VaeTiling { get; set; } = false;
|
public bool VaeTiling { get; set; } = false;
|
||||||
public string TaesdPath { get; set; } = string.Empty;
|
public string TaesdPath { get; set; } = string.Empty;
|
||||||
|
public string ESRGANPath { get; set; } = string.Empty;
|
||||||
public string LoraModelDir { get; set; } = string.Empty;
|
public string LoraModelDir { get; set; } = string.Empty;
|
||||||
public RngType RngType { get; set; } = RngType.Standard;
|
public RngType RngType { get; set; } = RngType.Standard;
|
||||||
public string VaePath { get; set; } = string.Empty;
|
public string VaePath { get; set; } = string.Empty;
|
||||||
|
public Quantization Quantization { get; set; } = Quantization.Default;
|
||||||
//TODO DarthAffe 01.01.2024: K-Quants doesn't seem to work so far
|
|
||||||
public Quantization Quantization { get; set; } = Quantization.F16;
|
|
||||||
|
|
||||||
public Schedule Schedule { get; set; } = Schedule.Default;
|
public Schedule Schedule { get; set; } = Schedule.Default;
|
||||||
|
public int ClipSkip { get; set; } = -1;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#pragma warning disable CS0169 // Field is never used
|
#pragma warning disable CS0169 // Field is never used
|
||||||
|
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
|
||||||
#pragma warning disable IDE1006
|
#pragma warning disable IDE1006
|
||||||
|
#pragma warning disable IDE0051
|
||||||
|
#pragma warning disable IDE0044
|
||||||
// ReSharper disable InconsistentNaming
|
// ReSharper disable InconsistentNaming
|
||||||
// ReSharper disable ArrangeTypeMemberModifiers
|
// ReSharper disable ArrangeTypeMemberModifiers
|
||||||
|
|
||||||
@ -7,96 +10,89 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace StableDiffusion.NET;
|
namespace StableDiffusion.NET;
|
||||||
|
|
||||||
using rng_type_t = RngType;
|
|
||||||
using sample_method_t = Sampler;
|
|
||||||
using schedule_t = Schedule;
|
|
||||||
using sd_type_t = Quantization;
|
|
||||||
using sd_log_level_t = LogLevel;
|
|
||||||
|
|
||||||
internal unsafe partial class Native
|
internal unsafe partial class Native
|
||||||
{
|
{
|
||||||
#region Constants
|
#region Constants
|
||||||
|
|
||||||
private const string LIB_NAME = "stable-diffusion";
|
private const string LIB_NAME = "sd-abi";
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region DLL-Import
|
#region DLL-Import
|
||||||
|
|
||||||
internal struct sd_ctx_t;
|
internal struct stable_diffusion_ctx;
|
||||||
internal struct upscaler_ctx_t;
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
internal struct stable_diffusion_full_params
|
||||||
internal struct sd_image_t
|
|
||||||
{
|
{
|
||||||
internal uint width;
|
string negative_prompt;
|
||||||
internal uint height;
|
float cfg_scale;
|
||||||
internal uint channel;
|
int width;
|
||||||
internal byte* data;
|
int height;
|
||||||
|
int sample_method;
|
||||||
|
int sample_steps;
|
||||||
|
long seed;
|
||||||
|
int batch_count;
|
||||||
|
float strength;
|
||||||
}
|
}
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "get_num_physical_cores")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_default_params_ref")]
|
||||||
internal static partial int get_num_physical_cores();
|
internal static partial stable_diffusion_full_params* stable_diffusion_full_default_params_ref();
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "sd_get_system_info")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_negative_prompt")]
|
||||||
internal static partial void* sd_get_system_info();
|
internal static partial void stable_diffusion_full_params_set_negative_prompt(stable_diffusion_full_params* @params, [MarshalAs(UnmanagedType.LPStr)] string negative_prompt);
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "new_sd_ctx")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_cfg_scale")]
|
||||||
internal static partial sd_ctx_t* new_sd_ctx([MarshalAs(UnmanagedType.LPStr)] string model_path,
|
internal static partial void stable_diffusion_full_params_set_cfg_scale(stable_diffusion_full_params* @params, float cfg_scale);
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string vae_path,
|
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string taesd_path,
|
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string lora_model_dir,
|
|
||||||
[MarshalAs(UnmanagedType.I1)] bool vae_decode_only,
|
|
||||||
[MarshalAs(UnmanagedType.I1)] bool vae_tiling,
|
|
||||||
[MarshalAs(UnmanagedType.I1)] bool free_params_immediately,
|
|
||||||
int n_threads,
|
|
||||||
sd_type_t wtype,
|
|
||||||
rng_type_t rng_type,
|
|
||||||
schedule_t s);
|
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "free_sd_ctx")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_width")]
|
||||||
internal static partial void free_sd_ctx(sd_ctx_t* sd_ctx);
|
internal static partial void stable_diffusion_full_params_set_width(stable_diffusion_full_params* @params, int width);
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "txt2img")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_height")]
|
||||||
internal static partial sd_image_t* txt2img(sd_ctx_t* sd_ctx,
|
internal static partial void stable_diffusion_full_params_set_height(stable_diffusion_full_params* @params, int height);
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string prompt,
|
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string negative_prompt,
|
|
||||||
int clip_skip,
|
|
||||||
float cfg_scale,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
sample_method_t sample_method,
|
|
||||||
int sample_steps,
|
|
||||||
long seed,
|
|
||||||
int batch_count);
|
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "img2img")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_sample_method")]
|
||||||
internal static partial sd_image_t* img2img(sd_ctx_t* sd_ctx,
|
internal static partial void stable_diffusion_full_params_set_sample_method(stable_diffusion_full_params* @params, [MarshalAs(UnmanagedType.LPStr)] string sample_method);
|
||||||
sd_image_t init_image,
|
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string prompt,
|
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string negative_prompt,
|
|
||||||
int clip_skip,
|
|
||||||
float cfg_scale,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
sample_method_t sample_method,
|
|
||||||
int sample_steps,
|
|
||||||
float strength,
|
|
||||||
long seed,
|
|
||||||
int batch_count);
|
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "new_upscaler_ctx")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_sample_steps")]
|
||||||
internal static partial upscaler_ctx_t* new_upscaler_ctx([MarshalAs(UnmanagedType.LPStr)] string esrgan_path,
|
internal static partial void stable_diffusion_full_params_set_sample_steps(stable_diffusion_full_params* @params, int sample_steps);
|
||||||
int n_threads,
|
|
||||||
sd_type_t wtype);
|
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "free_upscaler_ctx")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_seed")]
|
||||||
internal static partial void free_upscaler_ctx(upscaler_ctx_t* upscaler_ctx);
|
internal static partial void stable_diffusion_full_params_set_seed(stable_diffusion_full_params* @params, long seed);
|
||||||
|
|
||||||
[LibraryImport(LIB_NAME, EntryPoint = "upscale")]
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_batch_count")]
|
||||||
internal static partial sd_image_t upscale(upscaler_ctx_t* upscaler_ctx,
|
internal static partial void stable_diffusion_full_params_set_batch_count(stable_diffusion_full_params* @params, int batch_count);
|
||||||
sd_image_t input_image,
|
|
||||||
int upscale_factor);
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_strength")]
|
||||||
|
internal static partial void stable_diffusion_full_params_set_strength(stable_diffusion_full_params* @params, float strength);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_init")]
|
||||||
|
internal static partial stable_diffusion_ctx* stable_diffusion_init(int n_threads, [MarshalAs(UnmanagedType.I1)] bool vae_decode_only, [MarshalAs(UnmanagedType.LPStr)] string taesd_path, [MarshalAs(UnmanagedType.LPStr)] string esrgan_path, [MarshalAs(UnmanagedType.I1)] bool free_params_immediately, [MarshalAs(UnmanagedType.I1)] bool vae_tiling, [MarshalAs(UnmanagedType.LPStr)] string lora_model_dir, [MarshalAs(UnmanagedType.LPStr)] string rng_type);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_load_from_file")]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
internal static partial bool stable_diffusion_load_from_file(stable_diffusion_ctx* ctx, [MarshalAs(UnmanagedType.LPStr)] string file_path, [MarshalAs(UnmanagedType.LPStr)] string vae_path, [MarshalAs(UnmanagedType.LPStr)] string wtype, [MarshalAs(UnmanagedType.LPStr)] string schedule, int clip_skip);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_predict_image")]
|
||||||
|
internal static partial byte* stable_diffusion_predict_image(stable_diffusion_ctx* ctx, stable_diffusion_full_params* @params, [MarshalAs(UnmanagedType.LPStr)] string prompt);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_image_predict_image")]
|
||||||
|
internal static partial byte* stable_diffusion_image_predict_image(stable_diffusion_ctx* ctx, stable_diffusion_full_params* @params, byte* init_image, [MarshalAs(UnmanagedType.LPStr)] string prompt);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_set_log_level")]
|
||||||
|
internal static partial void stable_diffusion_set_log_level([MarshalAs(UnmanagedType.LPStr)] string level);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_get_system_info")]
|
||||||
|
[return: MarshalAs(UnmanagedType.LPStr)]
|
||||||
|
internal static partial string stable_diffusion_get_system_info();
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_free")]
|
||||||
|
internal static partial void stable_diffusion_free(stable_diffusion_ctx* ctx);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_free_full_params")]
|
||||||
|
internal static partial void stable_diffusion_free_full_params(stable_diffusion_full_params* @params);
|
||||||
|
|
||||||
|
[LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_free_buffer")]
|
||||||
|
internal static partial void stable_diffusion_free_buffer(byte* buffer);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
78
StableDiffusion.NET/StableDiffusion.cs
Normal file
78
StableDiffusion.NET/StableDiffusion.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace StableDiffusion.NET;
|
||||||
|
|
||||||
|
public sealed unsafe class StableDiffusionModel : IDisposable
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
private readonly string _modelPath;
|
||||||
|
private readonly ModelParameter _parameter;
|
||||||
|
|
||||||
|
private Native.stable_diffusion_ctx* _ctx;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public StableDiffusionModel(string modelPath, ModelParameter parameter)
|
||||||
|
{
|
||||||
|
this._modelPath = modelPath;
|
||||||
|
this._parameter = parameter;
|
||||||
|
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
~StableDiffusionModel() => Dispose();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
_ctx = Native.stable_diffusion_init(_parameter.ThreadCount, _parameter.VaeDecodeOnly, _parameter.TaesdPath, _parameter.ESRGANPath, false, _parameter.VaeTiling, _parameter.LoraModelDir, _parameter.RngType.GetNativeName() ?? "STD_DEFAULT_RNG");
|
||||||
|
if (_ctx == null) throw new NullReferenceException("Failed to initialize Stable Diffusion");
|
||||||
|
|
||||||
|
bool success = Native.stable_diffusion_load_from_file(_ctx, _modelPath, _parameter.VaePath, _parameter.Quantization.GetNativeName() ?? "DEFAULT", _parameter.Schedule.GetNativeName() ?? "DEFAULT", _parameter.ClipSkip);
|
||||||
|
if (!success) throw new IOException("Failed to load model");
|
||||||
|
}
|
||||||
|
|
||||||
|
public StableDiffusionImage TextToImage(string prompt, StableDiffusionParameter parameter)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
byte* result = Native.stable_diffusion_predict_image(_ctx, parameter.ParamPtr, prompt);
|
||||||
|
return new StableDiffusionImage(result, parameter.Width, parameter.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StableDiffusionImage ImageToImage(string prompt, Span<byte> image, StableDiffusionParameter parameter)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
fixed (byte* imagePtr = image)
|
||||||
|
{
|
||||||
|
byte* result = Native.stable_diffusion_image_predict_image(_ctx, parameter.ParamPtr, imagePtr, prompt);
|
||||||
|
return new StableDiffusionImage(result, parameter.Width, parameter.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
|
||||||
|
Native.stable_diffusion_free(_ctx);
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetSystemInfo() => Native.stable_diffusion_get_system_info();
|
||||||
|
|
||||||
|
public static void SetLogLevel(LogLevel level) => Native.stable_diffusion_set_log_level(level.GetNativeName() ?? "ERROR");
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -1,20 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace StableDiffusion.NET;
|
namespace StableDiffusion.NET;
|
||||||
|
|
||||||
public sealed unsafe class StableDiffusionImage : IDisposable
|
public sealed unsafe class StableDiffusionImage : IDisposable
|
||||||
{
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
public const int BPP = 3;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
internal readonly Native.sd_image_t* Image;
|
private readonly byte* _imagePtr;
|
||||||
|
|
||||||
public int Width { get; }
|
public int Width { get; }
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
public int Bpp { get; }
|
|
||||||
public int Stride { get; }
|
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Data
|
public ReadOnlySpan<byte> Data
|
||||||
{
|
{
|
||||||
@ -22,7 +25,7 @@ public sealed unsafe class StableDiffusionImage : IDisposable
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
return new ReadOnlySpan<byte>(Image->data, Width * Height * Bpp);
|
return new ReadOnlySpan<byte>(_imagePtr, Width * Height * BPP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,14 +33,11 @@ public sealed unsafe class StableDiffusionImage : IDisposable
|
|||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
internal unsafe StableDiffusionImage(Native.sd_image_t* image)
|
internal StableDiffusionImage(byte* ptr, int width, int height)
|
||||||
{
|
{
|
||||||
this.Image = image;
|
this._imagePtr = ptr;
|
||||||
|
this.Width = width;
|
||||||
Width = (int)image->width;
|
this.Height = height;
|
||||||
Height = (int)image->height;
|
|
||||||
Bpp = (int)image->channel;
|
|
||||||
Stride = Width * Bpp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~StableDiffusionImage() => Dispose();
|
~StableDiffusionImage() => Dispose();
|
||||||
@ -50,9 +50,8 @@ public sealed unsafe class StableDiffusionImage : IDisposable
|
|||||||
{
|
{
|
||||||
if (_disposed) return;
|
if (_disposed) return;
|
||||||
|
|
||||||
Marshal.FreeHGlobal((nint)Image->data);
|
Native.stable_diffusion_free_buffer(_imagePtr);
|
||||||
Marshal.FreeHGlobal((nint)Image);
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,181 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace StableDiffusion.NET;
|
|
||||||
|
|
||||||
public sealed unsafe class StableDiffusionModel : IDisposable
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
private readonly string _modelPath;
|
|
||||||
private readonly ModelParameter _parameter;
|
|
||||||
private readonly UpscalerModelParameter? _upscalerParameter;
|
|
||||||
|
|
||||||
private Native.sd_ctx_t* _ctx;
|
|
||||||
private Native.upscaler_ctx_t* _upscalerCtx;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
public StableDiffusionModel(string modelPath, ModelParameter parameter, UpscalerModelParameter? upscalerParameter = null)
|
|
||||||
{
|
|
||||||
this._modelPath = modelPath;
|
|
||||||
this._parameter = parameter;
|
|
||||||
this._upscalerParameter = upscalerParameter;
|
|
||||||
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
~StableDiffusionModel() => Dispose();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
private void Initialize()
|
|
||||||
{
|
|
||||||
_ctx = Native.new_sd_ctx(_modelPath,
|
|
||||||
_parameter.VaePath,
|
|
||||||
_parameter.TaesdPath,
|
|
||||||
_parameter.LoraModelDir,
|
|
||||||
_parameter.VaeDecodeOnly,
|
|
||||||
_parameter.VaeTiling,
|
|
||||||
false,
|
|
||||||
_parameter.ThreadCount,
|
|
||||||
_parameter.Quantization,
|
|
||||||
_parameter.RngType,
|
|
||||||
_parameter.Schedule);
|
|
||||||
if (_ctx == null) throw new NullReferenceException("Failed to initialize Stable Diffusion");
|
|
||||||
|
|
||||||
if (_upscalerParameter != null)
|
|
||||||
{
|
|
||||||
_upscalerCtx = Native.new_upscaler_ctx(_upscalerParameter.ESRGANPath,
|
|
||||||
_upscalerParameter.ThreadCount,
|
|
||||||
_upscalerParameter.Quantization);
|
|
||||||
if (_upscalerCtx == null) throw new NullReferenceException("Failed to initialize Stable Diffusion");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public StableDiffusionImage TextToImage(string prompt, StableDiffusionParameter parameter)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
Native.sd_image_t* result = Native.txt2img(_ctx,
|
|
||||||
prompt,
|
|
||||||
parameter.NegativePrompt,
|
|
||||||
parameter.ClipSkip,
|
|
||||||
parameter.CfgScale,
|
|
||||||
parameter.Width,
|
|
||||||
parameter.Height,
|
|
||||||
parameter.SampleMethod,
|
|
||||||
parameter.SampleSteps,
|
|
||||||
parameter.Seed,
|
|
||||||
1);
|
|
||||||
|
|
||||||
return new StableDiffusionImage(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StableDiffusionImage ImageToImage(string prompt, in ReadOnlySpan<byte> image, StableDiffusionParameter parameter)
|
|
||||||
{
|
|
||||||
fixed (byte* imagePtr = image)
|
|
||||||
{
|
|
||||||
Native.sd_image_t img = new()
|
|
||||||
{
|
|
||||||
width = (uint)parameter.Width,
|
|
||||||
height = (uint)parameter.Height,
|
|
||||||
channel = 3,
|
|
||||||
data = imagePtr
|
|
||||||
};
|
|
||||||
|
|
||||||
return ImageToImage(prompt, img, parameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public StableDiffusionImage ImageToImage(string prompt, StableDiffusionImage image, StableDiffusionParameter parameter)
|
|
||||||
=> ImageToImage(prompt, *image.Image, parameter);
|
|
||||||
|
|
||||||
private StableDiffusionImage ImageToImage(string prompt, Native.sd_image_t image, StableDiffusionParameter parameter)
|
|
||||||
{
|
|
||||||
Native.sd_image_t* result = Native.img2img(_ctx,
|
|
||||||
image,
|
|
||||||
prompt,
|
|
||||||
parameter.NegativePrompt,
|
|
||||||
parameter.ClipSkip,
|
|
||||||
parameter.CfgScale,
|
|
||||||
parameter.Width,
|
|
||||||
parameter.Height,
|
|
||||||
parameter.SampleMethod,
|
|
||||||
parameter.SampleSteps,
|
|
||||||
parameter.Strength,
|
|
||||||
parameter.Seed,
|
|
||||||
1);
|
|
||||||
|
|
||||||
|
|
||||||
return new StableDiffusionImage(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StableDiffusionImage Upscale(StableDiffusionImage image, int upscaleFactor)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(upscaleFactor, 0, nameof(upscaleFactor));
|
|
||||||
|
|
||||||
if (_upscalerCtx == null) throw new NullReferenceException("The upscaler is not initialized.");
|
|
||||||
|
|
||||||
return Upscale(*image.Image, upscaleFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StableDiffusionImage Upscale(in ReadOnlySpan<byte> image, int width, int height, int upscaleFactor)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(upscaleFactor, 0, nameof(upscaleFactor));
|
|
||||||
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(width, 0, nameof(upscaleFactor));
|
|
||||||
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(height, 0, nameof(upscaleFactor));
|
|
||||||
|
|
||||||
if (_upscalerCtx == null) throw new NullReferenceException("The upscaler is not initialized.");
|
|
||||||
|
|
||||||
fixed (byte* imagePtr = image)
|
|
||||||
{
|
|
||||||
Native.sd_image_t srcImage = new()
|
|
||||||
{
|
|
||||||
width = (uint)width,
|
|
||||||
height = (uint)height,
|
|
||||||
channel = 3,
|
|
||||||
data = imagePtr
|
|
||||||
};
|
|
||||||
|
|
||||||
return Upscale(srcImage, upscaleFactor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private StableDiffusionImage Upscale(Native.sd_image_t image, int upscaleFactor)
|
|
||||||
{
|
|
||||||
Native.sd_image_t result = Native.upscale(_upscalerCtx, image, upscaleFactor);
|
|
||||||
return new StableDiffusionImage(&result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_disposed) return;
|
|
||||||
|
|
||||||
Native.free_sd_ctx(_ctx);
|
|
||||||
|
|
||||||
if (_upscalerCtx != null)
|
|
||||||
Native.free_upscaler_ctx(_upscalerCtx);
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetSystemInfo()
|
|
||||||
{
|
|
||||||
void* s = Native.sd_get_system_info();
|
|
||||||
return Marshal.PtrToStringUTF8((nint)s) ?? "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetNumPhysicalCores() => Native.get_num_physical_cores();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,18 +1,197 @@
|
|||||||
namespace StableDiffusion.NET;
|
using System;
|
||||||
|
|
||||||
public sealed class StableDiffusionParameter
|
namespace StableDiffusion.NET;
|
||||||
|
|
||||||
|
public sealed unsafe class StableDiffusionParameter : IDisposable
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
public string NegativePrompt { get; set; } = string.Empty;
|
private bool _disposed;
|
||||||
public float CfgScale { get; set; } = 7.5f;
|
|
||||||
public int Width { get; set; } = 512;
|
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
|
||||||
public int Height { get; set; } = 512;
|
internal readonly Native.stable_diffusion_full_params* ParamPtr;
|
||||||
public Sampler SampleMethod { get; set; } = Sampler.Euler_A;
|
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
|
||||||
public int SampleSteps { get; set; } = 25;
|
|
||||||
public long Seed { get; set; } = -1;
|
private string _negativePrompt;
|
||||||
public float Strength { get; set; } = 0.7f;
|
public string NegativePrompt
|
||||||
public int ClipSkip { get; set; } = -1;
|
{
|
||||||
|
get => _negativePrompt;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (_negativePrompt != value)
|
||||||
|
{
|
||||||
|
_negativePrompt = value;
|
||||||
|
Native.stable_diffusion_full_params_set_negative_prompt(ParamPtr, _negativePrompt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float _cfgScale;
|
||||||
|
public float CfgScale
|
||||||
|
{
|
||||||
|
get => _cfgScale;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (Math.Abs(_cfgScale - value) > 0.0001)
|
||||||
|
{
|
||||||
|
_cfgScale = value;
|
||||||
|
Native.stable_diffusion_full_params_set_cfg_scale(ParamPtr, _cfgScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _width;
|
||||||
|
public int Width
|
||||||
|
{
|
||||||
|
get => _width;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (_width != value)
|
||||||
|
{
|
||||||
|
_width = value;
|
||||||
|
Native.stable_diffusion_full_params_set_width(ParamPtr, _width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _height;
|
||||||
|
public int Height
|
||||||
|
{
|
||||||
|
get => _height;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (_height != value)
|
||||||
|
{
|
||||||
|
_height = value;
|
||||||
|
Native.stable_diffusion_full_params_set_height(ParamPtr, _height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Sampler _sampleMethod;
|
||||||
|
public Sampler SampleMethod
|
||||||
|
{
|
||||||
|
get => _sampleMethod;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (_sampleMethod != value)
|
||||||
|
{
|
||||||
|
_sampleMethod = value;
|
||||||
|
Native.stable_diffusion_full_params_set_sample_method(ParamPtr, _sampleMethod.GetNativeName() ?? "EULER_A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _sampleSteps;
|
||||||
|
public int SampleSteps
|
||||||
|
{
|
||||||
|
get => _sampleSteps;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (_sampleSteps != value)
|
||||||
|
{
|
||||||
|
_sampleSteps = value;
|
||||||
|
Native.stable_diffusion_full_params_set_sample_steps(ParamPtr, _sampleSteps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long _seed;
|
||||||
|
public long Seed
|
||||||
|
{
|
||||||
|
get => _seed;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (_seed != value)
|
||||||
|
{
|
||||||
|
_seed = value;
|
||||||
|
Native.stable_diffusion_full_params_set_seed(ParamPtr, _seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _batchCount;
|
||||||
|
public int BatchCount
|
||||||
|
{
|
||||||
|
get => _batchCount;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (_batchCount != value)
|
||||||
|
{
|
||||||
|
_batchCount = value;
|
||||||
|
Native.stable_diffusion_full_params_set_batch_count(ParamPtr, _batchCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float _strength;
|
||||||
|
public float Strength
|
||||||
|
{
|
||||||
|
get => _strength;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (Math.Abs(_strength - value) > 0.0001)
|
||||||
|
{
|
||||||
|
_strength = value;
|
||||||
|
Native.stable_diffusion_full_params_set_strength(ParamPtr, _strength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||||
|
public StableDiffusionParameter()
|
||||||
|
{
|
||||||
|
ParamPtr = Native.stable_diffusion_full_default_params_ref();
|
||||||
|
|
||||||
|
NegativePrompt = string.Empty;
|
||||||
|
CfgScale = 7.5f;
|
||||||
|
Width = 512;
|
||||||
|
Height = 512;
|
||||||
|
SampleMethod = Sampler.Euler_A;
|
||||||
|
SampleSteps = 25;
|
||||||
|
Seed = -1;
|
||||||
|
BatchCount = 1;
|
||||||
|
Strength = 0.7f;
|
||||||
|
}
|
||||||
|
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||||
|
|
||||||
|
~StableDiffusionParameter() => Dispose();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
|
||||||
|
Native.stable_diffusion_free_full_params(ParamPtr);
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,14 +0,0 @@
|
|||||||
namespace StableDiffusion.NET;
|
|
||||||
|
|
||||||
public class UpscalerModelParameter
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
public int ThreadCount { get; set; } = 8;
|
|
||||||
public string ESRGANPath { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
//TODO DarthAffe 01.01.2024: K-Quants doesn't seem to work so far
|
|
||||||
public Quantization Quantization { get; set; } = Quantization.F16;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
14
build.bat
14
build.bat
@ -1,12 +1,10 @@
|
|||||||
if not exist stable-diffusion.cpp (
|
if not exist stable-diffusion.cpp-build (
|
||||||
git clone --recursive https://github.com/leejet/stable-diffusion.cpp
|
git clone https://github.com/DarthAffe/stable-diffusion.cpp-build
|
||||||
)
|
)
|
||||||
|
|
||||||
cd stable-diffusion.cpp
|
cd stable-diffusion.cpp-build
|
||||||
git fetch
|
git fetch
|
||||||
git checkout 2c5f3fc53a040a0f97ff8f359e8f8d1385bfd154
|
git checkout b518ce72f1ba448f164e58961b1513ccacc95006
|
||||||
git submodule init
|
|
||||||
git submodule update
|
|
||||||
|
|
||||||
if not exist build (
|
if not exist build (
|
||||||
mkdir build
|
mkdir build
|
||||||
@ -15,13 +13,13 @@ if not exist build (
|
|||||||
cd build
|
cd build
|
||||||
|
|
||||||
rem remove -DSD_CUBLAS=ON to disable cuda support
|
rem remove -DSD_CUBLAS=ON to disable cuda support
|
||||||
cmake .. -DBUILD_SHARED_LIBS=ON -DSD_BUILD_EXAMPLES=OFF -DSD_CUBLAS=ON
|
cmake .. -DCMAKE_BUILD_TYPE=Release -DSD_CUBLAS=ON
|
||||||
cmake --build . --config Release
|
cmake --build . --config Release
|
||||||
|
|
||||||
cd ..\..
|
cd ..\..
|
||||||
|
|
||||||
dotnet publish -c Release -o bin
|
dotnet publish -c Release -o bin
|
||||||
|
|
||||||
copy .\stable-diffusion.cpp\build\bin\Release\*.dll .\bin\
|
copy .\stable-diffusion.cpp-build\build\bin\Release\sd-abi.dll .\bin\sd-abi.dll
|
||||||
|
|
||||||
pause
|
pause
|
||||||
Loading…
x
Reference in New Issue
Block a user