diff --git a/CMakeLists.txt b/CMakeLists.txt index bd7c6d9..a4938ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,3 +417,9 @@ configure_file(cmake/stable-diffusion.pc.in install(FILES "${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +# ROCmFPX: build against the ROCmFPX fork of ggml (adds ROCmFP4/ROCmFPX quant types) +option(SD_ROCMFPX "sd: ggml is the ROCmFPX fork; force-include API shims" OFF) +if(SD_ROCMFPX) + target_compile_options(stable-diffusion PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/rfx_compat.h) +endif() diff --git a/include/stable-diffusion.h b/include/stable-diffusion.h index 267e7a7..ace983e 100644 --- a/include/stable-diffusion.h +++ b/include/stable-diffusion.h @@ -144,7 +144,15 @@ enum sd_type_t { SD_TYPE_Q2_0 = 42, SD_TYPE_F8_E4M3 = 43, SD_TYPE_F8_E5M2 = 44, - SD_TYPE_COUNT = 45, + // ROCmFPX fork of ggml (github.com/charlie12345/ROCmFPX); ids match its ggml_type + SD_TYPE_Q4_0_ROCMFP4 = 100, + SD_TYPE_Q4_0_ROCMFP4_FAST = 101, + SD_TYPE_Q6_0_ROCMFPX = 102, + SD_TYPE_Q8_0_ROCMFPX = 103, + SD_TYPE_Q3_0_ROCMFPX = 104, + SD_TYPE_Q2_0_ROCMFPX = 107, + SD_TYPE_Q4_0_ROCMI4 = 108, + SD_TYPE_COUNT = 109, }; enum sd_log_level_t { diff --git a/src/model_io/gguf_io.cpp b/src/model_io/gguf_io.cpp index 8120131..1337dbb 100644 --- a/src/model_io/gguf_io.cpp +++ b/src/model_io/gguf_io.cpp @@ -167,6 +167,17 @@ bool GGUFStreamingWriter::write_metadata(const std::string& file_path, return false; } + const bool is_moss_image = std::any_of(tensors.begin(), tensors.end(), [](const TensorWritePlan& tensor) { + return tensor.name == "video_embedder.bias"; + }) && std::any_of(tensors.begin(), tensors.end(), [](const TensorWritePlan& tensor) { + return tensor.name == "layers.0.proj.q.weight"; + }) && std::any_of(tensors.begin(), tensors.end(), [](const TensorWritePlan& tensor) { + return tensor.name == "final_linear_video.weight"; + }); + if (is_moss_image) { + gguf_set_val_str(gguf_ctx_, "general.architecture", "moss_image"); + } + for (const TensorWritePlan& plan : tensors) { ggml_tensor* tensor = ggml_new_tensor(meta_ctx_, plan.type, plan.n_dims, plan.ne); if (tensor == nullptr) { diff --git a/src/model_loader.cpp b/src/model_loader.cpp index 8822b2c..a677baa 100644 --- a/src/model_loader.cpp +++ b/src/model_loader.cpp @@ -1605,6 +1605,10 @@ bool ModelLoader::tensor_should_be_converted(const TensorStorage& tensor_storage if (tensor_storage.is_int8_tensorwise) { return false; } + if (type == GGML_TYPE_F32 && tensor_storage.type != GGML_TYPE_F32) { + // widening to F32 is lossless and keeps element-wise ops valid (e.g. BF16 adaLN tables in LTX-2.5) + return true; + } if (type != GGML_TYPE_COUNT) { if (ggml_is_quantized(type) && tensor_storage.ne[0] % ggml_blck_size(type) != 0) { // Pass, do not convert diff --git a/src/name_conversion.cpp b/src/name_conversion.cpp index 6a519ba..e1ecdef 100644 --- a/src/name_conversion.cpp +++ b/src/name_conversion.cpp @@ -1696,6 +1696,13 @@ std::string convert_tensor_name(std::string name, SDVersion version) { replace_with_prefix_map(name, prefix_map); if (version == VERSION_MOSS_IMAGE) { + // The official Diffusers MOSS checkpoint stores Qwen3.5 under + // `language_model.*`, while the internal LLM runner uses `model.*`. + // GGUF Qwen3.5 checkpoints already use the latter namespace. + const std::string hf_language_model_prefix = "text_encoders.llm.language_model."; + if (starts_with(name, hf_language_model_prefix)) { + name = "text_encoders.llm.model." + name.substr(hf_language_model_prefix.size()); + } const std::string te_prefix = "text_encoders.llm."; if (starts_with(name, te_prefix + "blk.")) { static const std::vector> qwen35_name_map = { diff --git a/src/stable-diffusion.cpp b/src/stable-diffusion.cpp index 1cc4c09..50566f5 100644 --- a/src/stable-diffusion.cpp +++ b/src/stable-diffusion.cpp @@ -48,7 +48,7 @@ enum sd_type_t str_to_sd_type(const char* str) { } for (int i = 0; i < std::min(SD_TYPE_COUNT, GGML_TYPE_COUNT); i++) { auto trait = ggml_get_type_traits((ggml_type)i); - if (!strcmp(str, trait->type_name)) { + if (trait->type_name != nullptr && !strcmp(str, trait->type_name)) { return (enum sd_type_t)i; } } diff --git a/rfx_compat.h b/rfx_compat.h new file mode 100644 index 0000000..eb36d34 --- /dev/null +++ b/rfx_compat.h @@ -0,0 +1,13 @@ +// shims so stable-diffusion.cpp builds against the ROCmFPX fork of ggml (older API) +#pragma once +#include "ggml.h" +#ifdef __cplusplus +static inline bool ggml_prec_set_acc(struct ggml_tensor * a, enum ggml_prec prec) { + switch (a->op) { + case GGML_OP_MUL_MAT: + case GGML_OP_MUL_MAT_ID: a->op_params[0] = (int32_t) prec; return true; + case GGML_OP_FLASH_ATTN_EXT: a->op_params[3] = (int32_t) prec; return true; + default: return false; + } +} +#endif