diff --git a/CMakeLists.txt b/CMakeLists.txt index b79b696..5fc769c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,8 +20,8 @@ endif() FetchContent_Declare( stable-diffusion-cpp - GIT_REPOSITORY https://github.com/lmagder/stable-diffusion.cpp.git - GIT_TAG f974370e049da45866d70f45673c5453e089251b # fix-untyped-tensors + GIT_REPOSITORY https://github.com/leejet/stable-diffusion.cpp.git + GIT_TAG ac54e0076052a196b7df961eb1f792c9ff4d7f22 # sd 3.5 support ) FetchContent_Declare( @@ -30,8 +30,22 @@ FetchContent_Declare( GIT_TAG f9ff166845a59327eda431af82ee85a9c7532c5d ) +find_package(Vulkan QUIET) +if(NOT WIN32 AND NOT Vulkan_FOUND) + if(EXISTS ${CMAKE_SYSROOT}/usr/lib/x86_64-linux-gnu/libvulkan.so) + set(Vulkan_INCLUDE_DIR ${CMAKE_SYSROOT}/usr/include) + set(Vulkan_LIBRARY ${CMAKE_SYSROOT}/usr/lib/x86_64-linux-gnu/libvulkan.so) + find_package(Vulkan) + endif() +endif() + +if(Vulkan_FOUND) + set(SD_FLASH_ATTN ON) + set(SD_VULKAN ON) +endif() + set(IMPLIB_SOURCE_FILES "") -if (CUDAToolkit_FOUND) +if (CUDAToolkit_FOUND AND NOT Vulkan_FOUND) set(SD_CUBLAS ON) set(SD_FLASH_ATTN ON) set(GGML_CUDA_F16 ON) @@ -87,7 +101,7 @@ target_compile_definitions(node-stable-diffusion-cpp PRIVATE NAPI_VERSION=9 NODE target_link_libraries(node-stable-diffusion-cpp ${CMAKE_JS_LIB} stable-diffusion) -if (CUDAToolkit_FOUND) +if (CUDAToolkit_FOUND AND NOT Vulkan_FOUND) file(GENERATE OUTPUT $/cuda_version.json INPUT ${CUDAToolkit_LIBRARY_ROOT}/version.json) else() file(GENERATE OUTPUT $/cuda_version.json CONTENT "{}") @@ -98,5 +112,3 @@ if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET) execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS}) target_link_options(node-stable-diffusion-cpp PRIVATE "/DELAYLOAD:nvcuda.dll") endif() - - diff --git a/cudadeps.ts b/cudadeps.ts index 73e23ee..592d7b4 100644 --- a/cudadeps.ts +++ b/cudadeps.ts @@ -59,8 +59,10 @@ if (fs.existsSync(versionListPath) && process.env.npm_command !== "ci") { const versionList = JSON.parse(fs.readFileSync(versionListPath, { encoding: "utf8" })); const versionListHash = hasher({ sort: true }).hash(versionList) + "_" + cudaSubfolder; const downloadMarkerPath = path.join(resolvedPath, downloadMarkerFile); + const componentCount = Object.keys(versionList).length; + const needsDownload = !fs.existsSync(downloadMarkerPath) || fs.readFileSync(downloadMarkerPath).toString() !== versionListHash; - if (!fs.existsSync(downloadMarkerPath) || fs.readFileSync(downloadMarkerPath).toString() !== versionListHash) { + if (componentCount > 0 && needsDownload) { console.info(`Downloading components ${components} for ${arch} - ${platform}`); for (const componentId of components) { diff --git a/index.d.ts b/index.d.ts index a479500..1a414c4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -8,6 +8,8 @@ declare module "@lmagder/node-stable-diffusion-cpp" { DPMPP2M, DPMPP2Mv2, LCM, + IPNDM, + IPNDM_V } declare enum Schedule { @@ -15,6 +17,7 @@ declare module "@lmagder/node-stable-diffusion-cpp" { Discrete, Karras, AYS, + GITS, } declare enum Type { @@ -66,6 +69,7 @@ declare module "@lmagder/node-stable-diffusion-cpp" { negativePrompt?: string; clipSkip?: number; cfgScale?: number; + guidance?: number; width?: number; height?: number; sampleMethod?: SampleMethod; @@ -84,6 +88,7 @@ declare module "@lmagder/node-stable-diffusion-cpp" { negativePrompt?: string; clipSkip?: number; cfgScale?: number; + guidance?: number; width?: number; height?: number; sampleMethod?: SampleMethod; @@ -116,7 +121,11 @@ declare module "@lmagder/node-stable-diffusion-cpp" { export const createContext: ( params: { - model: string; + model?: string; + clipL?: string; + clipG?: string; + t5xxl?: string; + diffusionModel?: string; vae?: string; taesd?: string; controlNet?: string; diff --git a/src/NodeModule.cpp b/src/NodeModule.cpp index 74f9f7a..12c40b5 100644 --- a/src/NodeModule.cpp +++ b/src/NodeModule.cpp @@ -248,7 +248,7 @@ namespace return ret; } - + class NodeStableDiffusionCpp : public Napi::Addon { public: @@ -268,6 +268,8 @@ namespace Napi::PropertyDescriptor::Value("DPMPP2M", Napi::Number::New(env, DPMPP2M)), Napi::PropertyDescriptor::Value("DPMPP2Mv2", Napi::Number::New(env, DPMPP2Mv2)), Napi::PropertyDescriptor::Value("LCM", Napi::Number::New(env, LCM)), + Napi::PropertyDescriptor::Value("IPNDM", Napi::Number::New(env, IPNDM)), + Napi::PropertyDescriptor::Value("IPNDM_V", Napi::Number::New(env, IPNDM_V)), }); sampleMethodEnum.Freeze(); @@ -278,6 +280,7 @@ namespace Napi::PropertyDescriptor::Value("Discrete", Napi::Number::New(env, DISCRETE)), Napi::PropertyDescriptor::Value("Karras", Napi::Number::New(env, KARRAS)), Napi::PropertyDescriptor::Value("AYS", Napi::Number::New(env, AYS)), + Napi::PropertyDescriptor::Value("GITS", Napi::Number::New(env, GITS)), }); scheduleEnum.Freeze(); @@ -336,7 +339,11 @@ namespace { Napi::Value tmp; const auto params = info[0].ToObject(); - const auto model = params.Get("model").ToString().Utf8Value(); + const auto model = (tmp = params.Get("model"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); + const auto clipL = (tmp = params.Get("clipL"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); + const auto clipG = (tmp = params.Get("clipG"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); + const auto t5xxl = (tmp = params.Get("t5xxl"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); + const auto diffusionModel = (tmp = params.Get("diffusionModel"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); const auto vae = (tmp = params.Get("vae"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); const auto taesd = (tmp = params.Get("taesd"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); const auto controlNet = (tmp = params.Get("controlNet"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); @@ -375,9 +382,34 @@ namespace return queueStableDiffusionWorker(info.Env(), cppContextData, [=](CPPContextData& ctx) { - ctx.sdCtx = { new_sd_ctx(model.c_str(), vae.c_str(), taesd.c_str(), controlNet.c_str(), loraDir.c_str(), - embedDir.c_str(), stackedIdEmbedDir.c_str(), vaeDecodeOnly, vaeTiling, freeParamsImmediately, numThreads, weightType, - cudaRng ? CUDA_RNG : STD_DEFAULT_RNG, schedule, keepClipOnCpu, keepControlNetOnCpu, keepVaeOnCpu), [](sd_ctx_t* c) { if (c) free_sd_ctx(c); } }; + ctx.sdCtx = { + new_sd_ctx( + model.c_str(), + clipL.c_str(), + clipG.c_str(), + t5xxl.c_str(), + diffusionModel.c_str(), + vae.c_str(), + taesd.c_str(), + controlNet.c_str(), + loraDir.c_str(), + embedDir.c_str(), + stackedIdEmbedDir.c_str(), + vaeDecodeOnly, + vaeTiling, + freeParamsImmediately, + numThreads, + weightType, + cudaRng ? CUDA_RNG : STD_DEFAULT_RNG, + schedule, + keepClipOnCpu, + keepControlNetOnCpu, + keepVaeOnCpu + ), + [](sd_ctx_t* c) { + if (c) free_sd_ctx(c); + } + }; if (!ctx.sdCtx) throw std::runtime_error("Context creation failed"); @@ -427,12 +459,32 @@ namespace const auto styleRatio = (tmp = params.Get("styleRatio"), tmp.IsUndefined() ? 20.0f : tmp.ToNumber().FloatValue()); const auto normalizeInput = (tmp = params.Get("normalizeInput"), tmp.IsUndefined() ? false : tmp.ToBoolean().Value()); const auto inputIdImagesPath = (tmp = params.Get("inputIdImagesPath"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); + const auto guidance = (tmp = params.Get("guidance"), tmp.IsUndefined() ? 0.0f : tmp.ToNumber().FloatValue()); + if (sampleMethod >= N_SAMPLE_METHODS) throw Napi::Error::New(info.Env(), "Invalid sampleMethod"); return queueStableDiffusionWorker(info.Env(), cppContextData, [=, sdCtx = cppContextData->sdCtx, controlCond = std::move(controlCond)](CPPContextData& ctx) { - return SdImageList(txt2img(sdCtx.get(), prompt.c_str(), negativePrompt.c_str(), clipSkip, cfgScale, width, height, sampleMethod, sampleSteps, seed, batchCount, controlCond.get(), controlStrength, styleRatio, normalizeInput, inputIdImagesPath.c_str()), batchCount); + return SdImageList(txt2img( + sdCtx.get(), + prompt.c_str(), + negativePrompt.c_str(), + clipSkip, + cfgScale, + guidance, + width, + height, + sampleMethod, + sampleSteps, + seed, + batchCount, + controlCond.get(), + controlStrength, + styleRatio, + normalizeInput, + inputIdImagesPath.c_str() + ), batchCount); }, [batchCount](Napi::Env env, SdImageList&& images) { @@ -468,12 +520,33 @@ namespace const auto styleRatio = (tmp = params.Get("styleRatio"), tmp.IsUndefined() ? 20.0f : tmp.ToNumber().FloatValue()); const auto normalizeInput = (tmp = params.Get("normalizeInput"), tmp.IsUndefined() ? false : tmp.ToBoolean().Value()); const auto inputIdImagesPath = (tmp = params.Get("inputIdImagesPath"), tmp.IsUndefined() ? "" : tmp.ToString().Utf8Value()); + const auto guidance = (tmp = params.Get("guidance"), tmp.IsUndefined() ? 0.0f : tmp.ToNumber().FloatValue()); if (sampleMethod >= N_SAMPLE_METHODS) throw Napi::Error::New(info.Env(), "Invalid sampleMethod"); return queueStableDiffusionWorker(info.Env(), cppContextData, [=, sdCtx = cppContextData->sdCtx, initImage = std::move(initImage), controlCond = std::move(controlCond)](CPPContextData& ctx) { - return SdImageList(img2img(sdCtx.get(), *initImage, prompt.c_str(), negativePrompt.c_str(), clipSkip, cfgScale, width, height, sampleMethod, sampleSteps, strength, seed, batchCount, controlCond.get(), controlStrength, styleRatio, normalizeInput, inputIdImagesPath.c_str()), batchCount); + return SdImageList(img2img( + sdCtx.get(), + *initImage, + prompt.c_str(), + negativePrompt.c_str(), + clipSkip, + cfgScale, + guidance, + width, + height, + sampleMethod, + sampleSteps, + strength, + seed, + batchCount, + controlCond.get(), + controlStrength, + styleRatio, + normalizeInput, + inputIdImagesPath.c_str() + ), batchCount); }, [batchCount](Napi::Env env, SdImageList&& images) {