init
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
////
|
||||
- Copyright (c) 2023-2025, Sascha Willems
|
||||
-
|
||||
- SPDX-License-Identifier: Apache-2.0
|
||||
-
|
||||
- Licensed under the Apache License, Version 2.0 the "License";
|
||||
- you may not use this file except in compliance with the License.
|
||||
- You may obtain a copy of the License at
|
||||
-
|
||||
- http://www.apache.org/licenses/LICENSE-2.0
|
||||
-
|
||||
- Unless required by applicable law or agreed to in writing, software
|
||||
- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
- See the License for the specific language governing permissions and
|
||||
- limitations under the License.
|
||||
-
|
||||
////
|
||||
= Framework
|
||||
// omit in toc
|
||||
:pp: {plus}{plus}
|
||||
|
||||
This folder contains the base framework used by the samples.
|
||||
It offers sample base classes, encapsulates common functionality for e.g.
|
||||
loading assets (images, models, shaders), wraps common Vulkan objects and implements frequently used concepts like a cache and a scene graph.
|
||||
The framework also implements platform support for Windows, Linux, MacOS and Android.
|
||||
|
||||
It can be used as a guideline for writing advanced Vulkan applications.
|
||||
|
||||
Before trying to implement common functions, consider checking if the framework doesn't already provides what you are looking for.
|
||||
|
||||
== Sample base classes
|
||||
|
||||
The framework provides two different sample base classes.
|
||||
When xref:../scripts/README.adoc[creating new samples], you can choose between one of them:
|
||||
|
||||
=== High level base sample class
|
||||
|
||||
This base class abstracts away most of the Vulkan API calls and as such makes heavy use of the Vulkan object wrapper classes of the framework.
|
||||
Writing samples with the base class is less verbose.
|
||||
|
||||
See link:./vulkan_sample.h[vulkan_sample.h] and link:./vulkan_sample.cpp[vulkan_sample.cpp].
|
||||
|
||||
=== API sample base class
|
||||
|
||||
This base class uses less abstraction, letting you work more explicitly with the api.
|
||||
|
||||
See link:./api_vulkan_sample.h[api_vulkan_sample.h] and link:./api_vulkan_sample.cpp[api_vulkan_sample.cpp].
|
||||
|
||||
=== Support for Vulkan-Hpp
|
||||
|
||||
While the framework itself primarily uses the C-Interface for Vulkan, both the high level and the API sample base class also come with https://github.com/KhronosGroup/Vulkan-Hpp[Vulkan-Hpp] variants, letting you write samples using the C{pp} Vulkan language bindings instead.
|
||||
|
||||
See link:./hpp_vulkan_sample.h[hpp_vulkan_sample.h] / link:./hpp_vulkan_sample.cpp[hpp_vulkan_sample.cpp] and link:./hpp_api_vulkan_sample.h[hpp_api_vulkan_sample.h] / link:./hpp_api_vulkan_sample.cpp[hpp_api_vulkan_sample.cpp].
|
||||
|
||||
== Commonly used framework concepts
|
||||
|
||||
=== Enabling extensions
|
||||
|
||||
Vulkan is an extensible api.
|
||||
New features are usually exposed through either instance or device extensions.
|
||||
Extensions can be enabled in the constructor of both the high level and api base sample class:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
MySample::MySample()
|
||||
{
|
||||
add_instance_extension(VK_SOME_INSTANCE_EXTENSION_NAME);
|
||||
add_device_extension(VK_SOME_DEVICE_EXTENSION_NAME);
|
||||
}
|
||||
----
|
||||
|
||||
NOTE: The framework uses the https://github.com/zeux/volk[Volk] meta-loader, which will automatically load extension function pointers for all enabled extensions.
|
||||
There is no need to manually get extension pointer functions.
|
||||
|
||||
=== Changing the Vulkan api version
|
||||
|
||||
By default all samples create a Vulkan 1.1 instance.
|
||||
Higher versions can be requested in the constructor of a sample:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
MySample::MySample()
|
||||
{
|
||||
set_api_version(VK_API_VERSION_1_2);
|
||||
}
|
||||
----
|
||||
|
||||
=== Requesting GPU features
|
||||
|
||||
Most extensions also require enabling corresponding feature flags.
|
||||
This can be done by overriding the `request_gpu_features` function of the base class:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
void MySample::request_gpu_features(vkb::PhysicalDevice &gpu)
|
||||
{
|
||||
// Get a reference to the feature structure required for an extension
|
||||
auto &requested_extension_feature = gpu
|
||||
request_extension_features<VkPhysicalDeviceSomeExtensionFeaturesKHR>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SOME_EXTENSION_FEATURES_KHR);
|
||||
|
||||
// Enable a selected feature
|
||||
requested_extension_feature.featureName = VK_TRUE;
|
||||
}
|
||||
----
|
||||
|
||||
=== Extending the graphical user interface
|
||||
|
||||
The framework includes a graphical user interface based on https://github.com/ocornut/imgui[Dear ImGui].
|
||||
This can be used by samples to display values and add controls like buttons, dropdowns, etc.
|
||||
|
||||
To add additional elements to the UI of a sample, you override the respective function from the base class:
|
||||
|
||||
Samples based on the high level base class need to override the `draw_gui` function:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
void MySample::draw_gui()
|
||||
{
|
||||
if (ImGui::Checkbox("Enable Option", &option_enabled))
|
||||
{
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Samples based on the api base class need to override the `on_update_ui_overlay` function:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
void MyApiSample::on_update_ui_overlay(vkb::Drawer &drawer)
|
||||
{
|
||||
if (drawer.checkbox("Enable option", &option_enabled))
|
||||
{
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
=== Loading models
|
||||
|
||||
The framework supports https://www.khronos.org/gltf/[glTF models] and includes a loader for this format.
|
||||
|
||||
The high level base class works with a single glTF scene loaded at startup.
|
||||
The scene is part of the base class, and there is no need to explicitly draw it:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
bool MySample::prepare(const vkb::ApplicationOptions &options)
|
||||
{
|
||||
scene = load_scene("filename.gltf");
|
||||
}
|
||||
----
|
||||
|
||||
With the api base class are explicitly declared, loaded and rendered:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
// my_sample.h
|
||||
class MyApiSample : public ApiVulkanSample
|
||||
{
|
||||
std::unique_ptr<vkb::sg::SubMesh> modelA;
|
||||
std::unique_ptr<vkb::sg::SubMesh> modelB;
|
||||
...
|
||||
}
|
||||
|
||||
// my_sample.cpp
|
||||
bool MyApiSample::prepare(const vkb::ApplicationOptions &options)
|
||||
{
|
||||
modelA = load_model("filenameA.gltf");
|
||||
modelB = load_model("filenameB.gltf");
|
||||
}
|
||||
|
||||
void MyApiSample::build_command_buffers()
|
||||
{
|
||||
vkBeginCommandBuffer(...);
|
||||
...
|
||||
draw_model(modelA, draw_cmd_buffers[i]);
|
||||
...
|
||||
draw_model(modelB, draw_cmd_buffers[i]);
|
||||
...
|
||||
vkEndCommandBufer(...);
|
||||
}
|
||||
----
|
||||
|
||||
=== Loading images
|
||||
|
||||
The framework supports the https://www.khronos.org/ktx/[KTX] GPU container format and includes a loader for this format.
|
||||
As a container format, KTX supports different image formats ranging from basic RGBA images to compressed formats.
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
texture = load_texture("rgba_texture.ktx", vkb::sg::Image::Color);
|
||||
----
|
||||
|
||||
Images (textures) loaded like this can then be used as descriptors later on:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
VkDescriptorImageInfo image_descriptor = create_descriptor(texture);
|
||||
----
|
||||
|
||||
=== Loading shaders
|
||||
|
||||
The framework supports loading textual GLSL shaders.
|
||||
These shaders are then compiled to https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html[SPIR-V] at runtime so Vulkan can ingest them.
|
||||
|
||||
With the high level base class, shaders are attached to the scene graphics' render pipeline:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
vkb::ShaderSource vert_shader("vs.vert");
|
||||
vkb::ShaderSource frag_shader("fs.frag");
|
||||
auto scene_subpass = std::make_unique<vkb::ForwardSubpass>(get_render_context(), std::move(vert_shader), std::move(frag_shader), *scene, *camera);
|
||||
|
||||
auto render_pipeline = vkb::RenderPipeline();
|
||||
render_pipeline.add_subpass(std::move(scene_subpass));
|
||||
|
||||
set_render_pipeline(std::move(render_pipeline));
|
||||
----
|
||||
|
||||
While in the api base class, this is again more explicitly by creating shader modules used at pipeline creation time:
|
||||
|
||||
[,cpp]
|
||||
----
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages;
|
||||
...
|
||||
shader_stages[0] = load_shader("vs.vert", VK_SHADER_STAGE_VERTEX_BIT);
|
||||
shader_stages[1] = load_shader("fs.frag", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &pipeline_create_info, nullptr, &pipeline));
|
||||
----
|
||||
Reference in New Issue
Block a user