diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e35fd0..dcccc46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ if(EXISTS "${KIMODO_GGML_SOURCE_DIR}/CMakeLists.txt") target_compile_definitions(kimodo PRIVATE KIMODO_HAVE_GGML=1) if(KIMODO_ENABLE_VULKAN AND TARGET ggml-vulkan) target_link_libraries(kimodo PRIVATE ggml-vulkan) - target_compile_definitions(kimodo PRIVATE KIMODO_HAVE_GGML_VULKAN=1) + target_compile_definitions(kimodo PRIVATE $<$:KIMODO_HAVE_GGML_VULKAN=1>) endif() target_link_libraries(kmd-inspect PRIVATE ggml) target_compile_definitions(kmd-inspect PRIVATE KIMODO_HAVE_GGML=1) @@ -50,42 +50,42 @@ if(EXISTS "${KIMODO_GGML_SOURCE_DIR}/CMakeLists.txt") src/gguf.cpp src/ggml_weights.cpp src/denoiser.cpp src/diffusion.cpp src/motion_rep.cpp src/motion_decode.cpp) target_include_directories(kmd-sample-fixture PRIVATE src) - target_link_libraries(kmd-sample-fixture PRIVATE ggml ggml-vulkan) - target_compile_definitions(kmd-sample-fixture PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kmd-sample-fixture PRIVATE ggml $) + target_compile_definitions(kmd-sample-fixture PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_executable(kmd-generate src/generate.cpp) target_link_libraries(kmd-generate PRIVATE kimodo) add_executable(kmd-encode src/encode.cpp) target_sources(kmd-encode PRIVATE src/llm_text_encoder.cpp src/llm_tokenizer.cpp) target_include_directories(kmd-encode PRIVATE src) - target_link_libraries(kmd-encode PRIVATE ggml ggml-vulkan) - target_compile_definitions(kmd-encode PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kmd-encode PRIVATE ggml $) + target_compile_definitions(kmd-encode PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_executable(kimodo-llm-layer-parity tests/llm_layer_parity.cpp) - target_link_libraries(kimodo-llm-layer-parity PRIVATE ggml ggml-vulkan) + target_link_libraries(kimodo-llm-layer-parity PRIVATE ggml $) target_include_directories(kimodo-llm-layer-parity PRIVATE src) - target_compile_definitions(kimodo-llm-layer-parity PRIVATE KIMODO_HAVE_GGML_VULKAN=1) + target_compile_definitions(kimodo-llm-layer-parity PRIVATE $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_executable(kimodo-llm-final-norm-parity tests/llm_final_norm_parity.cpp) - target_link_libraries(kimodo-llm-final-norm-parity PRIVATE ggml ggml-vulkan) - target_compile_definitions(kimodo-llm-final-norm-parity PRIVATE KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-llm-final-norm-parity PRIVATE ggml $) + target_compile_definitions(kimodo-llm-final-norm-parity PRIVATE $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_executable(kimodo-llm-tokenizer-test tests/llm_tokenizer_test.cpp src/llm_tokenizer.cpp) target_include_directories(kimodo-llm-tokenizer-test PRIVATE src) target_link_libraries(kimodo-llm-tokenizer-test PRIVATE ggml) add_executable(kimodo-llm-embedding-parity tests/llm_embedding_parity.cpp) - target_link_libraries(kimodo-llm-embedding-parity PRIVATE ggml ggml-vulkan) + target_link_libraries(kimodo-llm-embedding-parity PRIVATE ggml $) add_executable(kimodo-multiprompt-fixture-parity tests/multiprompt_fixture_parity.cpp) target_sources(kimodo-multiprompt-fixture-parity PRIVATE src/gguf.cpp src/ggml_weights.cpp src/denoiser.cpp src/sequence.cpp src/motion_rep.cpp src/diffusion.cpp) target_include_directories(kimodo-multiprompt-fixture-parity PRIVATE src) - target_link_libraries(kimodo-multiprompt-fixture-parity PRIVATE ggml ggml-vulkan) - target_compile_definitions(kimodo-multiprompt-fixture-parity PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-multiprompt-fixture-parity PRIVATE ggml $) + target_compile_definitions(kimodo-multiprompt-fixture-parity PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_executable(kimodo-stage-fixture-parity tests/stage_fixture_parity.cpp) target_sources(kimodo-stage-fixture-parity PRIVATE src/gguf.cpp src/ggml_weights.cpp src/denoiser.cpp src/motion_rep.cpp src/diffusion.cpp) target_include_directories(kimodo-stage-fixture-parity PRIVATE src) - target_link_libraries(kimodo-stage-fixture-parity PRIVATE ggml ggml-vulkan) - target_compile_definitions(kimodo-stage-fixture-parity PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-stage-fixture-parity PRIVATE ggml $) + target_compile_definitions(kimodo-stage-fixture-parity PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_executable(kimodo-llm-text-session-parity tests/llm_text_session_parity.cpp src/llm_text_encoder.cpp src/llm_tokenizer.cpp) target_include_directories(kimodo-llm-text-session-parity PRIVATE src) - target_link_libraries(kimodo-llm-text-session-parity PRIVATE ggml ggml-vulkan) - target_compile_definitions(kimodo-llm-text-session-parity PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-llm-text-session-parity PRIVATE ggml $) + target_compile_definitions(kimodo-llm-text-session-parity PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) endif() include(CTest) if(BUILD_TESTING AND KIMODO_BUILD_TESTS) @@ -109,7 +109,7 @@ if(BUILD_TESTING AND KIMODO_BUILD_TESTS) COMMAND kimodo-llm-text-session-parity "${KIMODO_LLM_TEXT_BUNDLE}" "${KIMODO_LLM_TEXT_FIXTURE}") add_executable(kimodo-root-parity tests/root_parity.cpp src/motion_rep.cpp) target_include_directories(kimodo-root-parity PRIVATE src) - target_link_libraries(kimodo-root-parity PRIVATE kimodo ggml ggml-vulkan) + target_link_libraries(kimodo-root-parity PRIVATE kimodo ggml $) add_test(NAME kimodo-root-parity COMMAND kimodo-root-parity "${KIMODO_ROOT_PARITY_MODEL}" "${KIMODO_ROOT_PARITY_FIXTURE}" root) add_test(NAME kimodo-body-parity @@ -122,15 +122,15 @@ if(BUILD_TESTING AND KIMODO_BUILD_TESTS) add_executable(kimodo-ggml-weights-test tests/ggml_weights_test.cpp) target_sources(kimodo-ggml-weights-test PRIVATE src/gguf.cpp src/ggml_weights.cpp) target_include_directories(kimodo-ggml-weights-test PRIVATE src) - target_link_libraries(kimodo-ggml-weights-test PRIVATE kimodo ggml ggml-vulkan) - target_compile_definitions(kimodo-ggml-weights-test PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-ggml-weights-test PRIVATE kimodo ggml $) + target_compile_definitions(kimodo-ggml-weights-test PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_test(NAME kimodo-ggml-weights-test COMMAND kimodo-ggml-weights-test "${KIMODO_ROOT_PARITY_MODEL}") add_executable(kimodo-denoiser-runtime-test tests/denoiser_runtime_test.cpp) target_sources(kimodo-denoiser-runtime-test PRIVATE src/gguf.cpp src/ggml_weights.cpp src/denoiser.cpp src/motion_rep.cpp src/diffusion.cpp) target_include_directories(kimodo-denoiser-runtime-test PRIVATE src) - target_link_libraries(kimodo-denoiser-runtime-test PRIVATE kimodo ggml ggml-vulkan) - target_compile_definitions(kimodo-denoiser-runtime-test PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-denoiser-runtime-test PRIVATE kimodo ggml $) + target_compile_definitions(kimodo-denoiser-runtime-test PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_test(NAME kimodo-denoiser-runtime-root COMMAND kimodo-denoiser-runtime-test "${KIMODO_ROOT_PARITY_MODEL}" "${KIMODO_ROOT_PARITY_FIXTURE}" root) add_test(NAME kimodo-denoiser-runtime-body @@ -140,8 +140,8 @@ if(BUILD_TESTING AND KIMODO_BUILD_TESTS) add_executable(kimodo-decode-test tests/decode_test.cpp) target_sources(kimodo-decode-test PRIVATE src/gguf.cpp src/ggml_weights.cpp src/motion_decode.cpp) target_include_directories(kimodo-decode-test PRIVATE src) - target_link_libraries(kimodo-decode-test PRIVATE kimodo ggml ggml-vulkan) - target_compile_definitions(kimodo-decode-test PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-decode-test PRIVATE kimodo ggml $) + target_compile_definitions(kimodo-decode-test PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) add_test(NAME kimodo-decode-test COMMAND kimodo-decode-test "${KIMODO_ROOT_PARITY_MODEL}" "${KIMODO_ROOT_PARITY_FIXTURE}") add_executable(kimodo-generate-smoke tests/generate_smoke.cpp) target_link_libraries(kimodo-generate-smoke PRIVATE kimodo) @@ -149,8 +149,8 @@ if(BUILD_TESTING AND KIMODO_BUILD_TESTS) add_executable(kimodo-sampler2-test tests/sampler2_test.cpp) target_sources(kimodo-sampler2-test PRIVATE src/gguf.cpp src/ggml_weights.cpp src/denoiser.cpp src/motion_rep.cpp src/diffusion.cpp) target_include_directories(kimodo-sampler2-test PRIVATE src) - target_link_libraries(kimodo-sampler2-test PRIVATE kimodo ggml ggml-vulkan) - target_compile_definitions(kimodo-sampler2-test PRIVATE KIMODO_HAVE_GGML=1 KIMODO_HAVE_GGML_VULKAN=1) + target_link_libraries(kimodo-sampler2-test PRIVATE kimodo ggml $) + target_compile_definitions(kimodo-sampler2-test PRIVATE KIMODO_HAVE_GGML=1 $<$:KIMODO_HAVE_GGML_VULKAN=1>) if(IS_DIRECTORY "${KIMODO_MULTIPROMPT_FIXTURE}") add_test(NAME kimodo-multiprompt-fixture-parity COMMAND kimodo-multiprompt-fixture-parity "${KIMODO_ROOT_PARITY_MODEL}" "${KIMODO_MULTIPROMPT_FIXTURE}") diff --git a/src/ggml_weights.cpp b/src/ggml_weights.cpp index 4fe751f..738111a 100644 --- a/src/ggml_weights.cpp +++ b/src/ggml_weights.cpp @@ -81,6 +81,17 @@ std::expected, std::string> ggml_motion_wei configure_vulkan_f32_parity(); if (ggml_backend_vk_get_device_count() > 0) result->backend_ = ggml_backend_vk_init(0); } +#else + // No Vulkan compiled in: try any registered GPU device (e.g. Metal on + // macOS), keeping KIMODO_BACKEND=cpu as the deterministic escape hatch. + const bool force_cpu = [] { + const char *value = std::getenv("KIMODO_BACKEND"); + return value && std::string_view(value) == "cpu"; + }(); + if (!force_cpu) { + if (auto *device = ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_GPU)) + result->backend_ = ggml_backend_dev_init(device, nullptr); + } #endif if (!result->backend_) { result->backend_ = ggml_backend_cpu_init(); diff --git a/src/llm_text_encoder.cpp b/src/llm_text_encoder.cpp index b67c059..47aa509 100644 --- a/src/llm_text_encoder.cpp +++ b/src/llm_text_encoder.cpp @@ -8,7 +8,9 @@ #include #include #include +#if defined(KIMODO_HAVE_GGML_VULKAN) #include +#endif #include #include @@ -216,7 +218,16 @@ std::expected, std::string> llm_text_encoder:: for (int i = 0; i < 32; ++i) { char name[32]; std::snprintf(name, sizeof(name), "layer-%02d.gguf", i); if (!std::filesystem::is_regular_file(path / name)) return std::unexpected("text bundle missing " + std::string(name)); } auto result = std::unique_ptr(new llm_text_encoder); result->impl_ = std::make_unique(); +#if defined(KIMODO_HAVE_GGML_VULKAN) if (use_vulkan() && ggml_backend_vk_get_device_count()) result->impl_->backend = ggml_backend_vk_init(0); +#else + // No Vulkan compiled in: fall back to any registered GPU device (e.g. + // Metal on macOS) unless KIMODO_BACKEND=cpu requests the CPU path. + if (use_vulkan()) { + if (auto *device = ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_GPU)) + result->impl_->backend = ggml_backend_dev_init(device, nullptr); + } +#endif if (!result->impl_->backend) { result->impl_->backend = ggml_backend_cpu_init(); if (!result->impl_->backend) return std::unexpected("cannot initialize text backend");