https://github.com/KhronosGroup/Vulkan-Samples
先介绍下本项目的框架。
如何构建
按项目的 readme 教程 ,windows 下推荐用 Visual Studio,不需要额外配置即可配置构建调试项目,缺点是太慢了,不管是构建还是 IDE 使用方面; 使用 VsCode 的话配置比较麻烦,可以安装 cmake-tools 插件,然后在 ui 中配置 build kit,其实也比较简单,缺点是构建也很慢

用 CLion 配置 Visual Studio 工具链,构建速度相对较快,且调试也更方便,推荐使用;

vulkan_samples 可执行文件源码
其源文件位于 app/main.cpp,其主要流程为:
auto code = platform.initialize(plugins::get_all());
if (code == vkb::ExitCode::Success)
{
code = platform.main_loop();
}
platform.terminate(code);第一步是初始化 plugins, 这里的 插件 实际是 vlukan_samples 的各功能模块,如运行 sample 子命令的就是 StartSample 插件,截屏的是 Screenshot 等。
主循环函数 main_loop (framework/platform/platform.cpp):
ExitCode Platform::main_loop()
{
ExitCode exit_code = ExitCode::Success;
while (exit_code == ExitCode::Success)
{
exit_code = main_loop_frame();
}
return exit_code;
}进一步 main_loop_frame:
ExitCode Platform::main_loop_frame()
{
try
{
// Load the requested app
if (app_requested())
{
if (!start_app())
{
throw std::runtime_error("Failed to load requested application");
}
// Compensate for load times of the app by rendering the first frame pre-emptively
timer.tick<Timer::Seconds>();
active_app->update(0.01667f);
}
if (!active_app)
{
return ExitCode::NoSample;
}
update();
if (active_app->should_close())
{
std::string id = active_app->get_name();
on_app_close(id);
active_app->finish();
}
window->process_events();
if (window->should_close() || close_requested)
{
return ExitCode::Close;
}
}
catch (std::exception &e)
{
LOGE("Error Message: {}", e.what());
LOGE("Failed when running application {}", active_app->get_name());
on_app_error(active_app->get_name());
if (app_requested())
{
LOGI("Attempting to load next application");
}
else
{
set_last_error(e.what());
return ExitCode::FatalError;
}
}
return ExitCode::Success;
}进一步阅读各个函数,
Platform::start_app
bool Platform::start_app()
{
auto *requested_app_info = requested_app;
// Reset early incase error in preparation stage
requested_app = nullptr;
if (active_app)
{
auto execution_time = timer.stop();
LOGI("Closing App (Runtime: {:.1f})", execution_time);
auto app_id = active_app->get_name();
active_app->finish();
}
// Reset target environment to default prior to each sample to properly support batch mode
vkb::GLSLCompiler::reset_target_environment();
active_app = requested_app_info->create();
if (!active_app)
{
LOGE("Failed to create a valid vulkan app.");
return false;
}
auto sample_info = static_cast<const apps::SampleInfo *>(requested_app_info);
active_app->set_name(sample_info->name);
if (!active_app->prepare({false, window.get()}))
{
LOGE("Failed to prepare vulkan app.");
return false;
}
on_app_start(requested_app_info->id);
return true;
}- 调用 create 函数(即每个 sample 中的 create_xxx )创建该类型 app 实例,
- 调用 app 的 prepare 函数
- 触发相关插件的 on_app_start
Platform::update
void Platform::update()
{
auto delta_time = static_cast<float>(timer.tick<Timer::Seconds>());
if (focused || always_render)
{
on_update(delta_time);
if (fixed_simulation_fps)
{
delta_time = simulation_frame_time;
}
active_app->update_overlay(delta_time, [=, this]() {
on_update_ui_overlay(*active_app->get_drawer());
});
active_app->update(delta_time);
if (auto *app = dynamic_cast<VulkanSampleCpp *>(active_app.get()))
{
if (app->has_render_context())
{
on_post_draw(reinterpret_cast<vkb::RenderContext &>(app->get_render_context()));
}
}
else if (auto *app = dynamic_cast<VulkanSampleC *>(active_app.get()))
{
if (app->has_render_context())
{
on_post_draw(app->get_render_context());
}
}
}
}- 触发相关插件的 on_update
- 调用 app 的 update_overlay 和 update
- 触发相关插件的 on_post_draw
框架提供了两种不同的示例基类:
- 高级示例基类(framework/vulkan_sample.h):此基类抽象了大部分 Vulkan API 调用,因此大量使用了框架的 Vulkan 对象包装器类。使用基类编写示例代码更简洁。
- API 示例基类(framework/api_vulkan_sample.h):这个基类使用较少的抽象,让您更明确地使用 API。 另两个对应的 C++ 变体基类
项目结构
- components:组件封装了所有与特定功能相关的代码。这里的功能主要有公共 utils 和各平台支持。
- framework:示例框架代码
- samples:示例代码