mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-26 00:34:35 +00:00
Added documentation to InstanBuilder and PhysicalDevice Selector
Updated readme's example code and included better build instructions
This commit is contained in:
parent
7de79b81b1
commit
37656d311a
60
README.md
60
README.md
@ -1,11 +1,11 @@
|
||||
# Vk-Bootstrap
|
||||
|
||||
A Vulkan utility library meant to jump start a Vulkan Application
|
||||
A Vulkan utility library meant to jump start any Vulkan Application
|
||||
|
||||
This library simplifies the tedious process of:
|
||||
|
||||
* Instance Creation
|
||||
* Physical Device Selection
|
||||
* Picking a Physical Device
|
||||
* Device Creation
|
||||
* Getting Queues
|
||||
* Swapchain Creation
|
||||
@ -14,7 +14,7 @@ It also adds several conveniences for:
|
||||
|
||||
* enabling validation layers
|
||||
* setting up a debug callback
|
||||
* selecting a gpu based on a small set of common criteria
|
||||
* select a gpu based on a set of common criteria like features, extensions, memory, etc.
|
||||
|
||||
## Example
|
||||
|
||||
@ -22,65 +22,74 @@ It also adds several conveniences for:
|
||||
|
||||
#include "VkBootstrap.h"
|
||||
|
||||
void device_init()
|
||||
void init_vulkan()
|
||||
{
|
||||
vkb::InstanceBuilder builder;
|
||||
builder.setup_validation_layers()
|
||||
.set_app_name ("example")
|
||||
builder.check_and_setup_validation_layers()
|
||||
.set_app_name ("Example Vulkan Application")
|
||||
.set_default_debug_messenger ();
|
||||
auto inst_ret = builder.build();
|
||||
if (!inst_ret.has_value()) {
|
||||
// error
|
||||
}
|
||||
vkb::Instance inst = inst_ret.value();
|
||||
vkb::Instance vkb_inst = inst_ret.value();
|
||||
|
||||
vkb::PhysicalDeviceSelector selector{ inst };
|
||||
selector.set_surface (/* from user created window*/)
|
||||
.set_minimum_version (1, 0)
|
||||
.require_dedicated_transfer_queue();
|
||||
.set_minimum_version (1, 1) //require a vulkan 1.1 capable device
|
||||
.require_dedicated_transfer_queue(); //require a transfer queue
|
||||
auto phys_ret = selector.select ();
|
||||
if (!phys_ret.has_value()) {
|
||||
// error
|
||||
}
|
||||
vkb::PhysicalDevice physical_device = phys_ret.value();
|
||||
|
||||
vkb::DeviceBuilder device_builder{ physical_device };
|
||||
vkb::DeviceBuilder device_builder{ phys_ret.value() };
|
||||
auto dev_ret = device_builder.build ();
|
||||
if (!dev_ret.has_value()){
|
||||
// error
|
||||
}
|
||||
vkb::Device device = dev_ret.value();
|
||||
|
||||
auto graphics_queue_ret = vkb::get_graphics_queue(device);
|
||||
// Get the VkDevice handle used in the rest of a vulkan application
|
||||
VkDevice device = dev_ret.value().device;
|
||||
|
||||
// Get the graphics queue with a helper function
|
||||
auto graphics_queue_ret = vkb::get_graphics_queue(dev_ret.value());
|
||||
if (!graphics_queue_ret.has_value()){
|
||||
// error
|
||||
}
|
||||
VkQueue graphics_queue = graphics_queue_ret.value();
|
||||
|
||||
// Reduced 400-500 lines of boilerplate to a less than fifty.
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Using this library
|
||||
See `example/triangle.cpp` for an example that renders a triangle to the screen.
|
||||
|
||||
#### Simple
|
||||
## Setting up vk-bootstrap
|
||||
|
||||
Copy the `src/VkBootstrap.h` and `src/VkBootstrap.cpp` into your project
|
||||
### Simple
|
||||
|
||||
#### With git-submodule + CMake
|
||||
This library has no external dependencies.
|
||||
Simply copy the `src/VkBootstrap.h` and `src/VkBootstrap.cpp` files into your project and compile them as you normally would
|
||||
|
||||
add this project as a git-submodule
|
||||
### With git-submodule + CMake
|
||||
|
||||
Add this project as a git-submodule
|
||||
|
||||
```bash
|
||||
git submodule add https://github.com/charles-lunarg/vk-bootstrap
|
||||
```
|
||||
|
||||
Then add the project with cmake
|
||||
With CMake, add the project as a subdirectory
|
||||
|
||||
```cmake
|
||||
add_subdirectory(vk-bootstrap)
|
||||
|
||||
target_link_libraries(your_application_name vk-bootstrap)
|
||||
```
|
||||
|
||||
## Manually Building
|
||||
### Manually Building
|
||||
|
||||
```bash
|
||||
git clone https://github.com/charles-lunarg/vk-bootstrap
|
||||
@ -90,17 +99,17 @@ cd build
|
||||
cmake ..
|
||||
```
|
||||
|
||||
To test, glfw and Catch2 are needed and automatically included using git submodules.
|
||||
## Testing
|
||||
|
||||
In the project directory, run
|
||||
To test, glfw and Catch2 are automatically included using git submodules.
|
||||
|
||||
In the project directory, run the following to get the required dependencies to test.
|
||||
|
||||
```bash
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
to get the required dependencies for testing setup.
|
||||
|
||||
Then return to the build directory and enable tests with `VK_BOOTSTRAP_TEST`
|
||||
In the build directory, enable tests by adding `-DVK_BOOTSTRAP_TEST` to the cmake command line arguments
|
||||
|
||||
```bash
|
||||
cmake ../path/to/vk-bootstrap/ -DVK_BOOTSTRAP_TEST=ON
|
||||
@ -112,4 +121,3 @@ cmake ../path/to/vk-bootstrap/ -DVK_BOOTSTRAP_TEST=ON
|
||||
* More examples
|
||||
* Testing
|
||||
* Documenting API
|
||||
* Fleshing out device configuration
|
||||
|
@ -42,7 +42,8 @@ int device_initialization (Init& init) {
|
||||
init.window = create_window_glfw (false);
|
||||
|
||||
vkb::InstanceBuilder instance_builder;
|
||||
auto instance_ret = instance_builder.set_default_debug_messenger ().setup_validation_layers ().build ();
|
||||
auto instance_ret =
|
||||
instance_builder.set_default_debug_messenger ().check_and_setup_validation_layers ().build ();
|
||||
if (!instance_ret) {
|
||||
std::cout << static_cast<uint32_t> (instance_ret.error ().type) << "\n";
|
||||
}
|
||||
|
@ -312,37 +312,37 @@ InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t mino
|
||||
info.api_version = VK_MAKE_VERSION (major, minor, patch);
|
||||
return *this;
|
||||
}
|
||||
InstanceBuilder& InstanceBuilder::add_layer (const char* layer_name) {
|
||||
InstanceBuilder& InstanceBuilder::must_enable_layer (const char* layer_name) {
|
||||
if (!layer_name) return *this;
|
||||
info.layers.push_back (layer_name);
|
||||
return *this;
|
||||
}
|
||||
InstanceBuilder& InstanceBuilder::add_extension (const char* extension_name) {
|
||||
InstanceBuilder& InstanceBuilder::must_enable_extension (const char* extension_name) {
|
||||
if (!extension_name) return *this;
|
||||
info.extensions.push_back (extension_name);
|
||||
return *this;
|
||||
}
|
||||
bool InstanceBuilder::check_and_add_layer (const char* layer_name) {
|
||||
if (!layer_name) return false;
|
||||
bool available = detail::check_layer_supported (system.available_layers, layer_name);
|
||||
if (available) info.layers.push_back (layer_name);
|
||||
return available;
|
||||
InstanceBuilder& InstanceBuilder::check_and_add_layer (const char* layer_name) {
|
||||
if (!layer_name) return *this;
|
||||
if (detail::check_layer_supported (system.available_layers, layer_name))
|
||||
info.layers.push_back (layer_name);
|
||||
return *this;
|
||||
}
|
||||
bool InstanceBuilder::check_and_add_extension (const char* extension_name) {
|
||||
if (!extension_name) return false;
|
||||
bool available = detail::check_extension_supported (system.available_extensions, extension_name);
|
||||
if (available) info.extensions.push_back (extension_name);
|
||||
return available;
|
||||
InstanceBuilder& InstanceBuilder::check_and_add_extension (const char* extension_name) {
|
||||
if (!extension_name) return *this;
|
||||
if (detail::check_extension_supported (system.available_extensions, extension_name))
|
||||
info.extensions.push_back (extension_name);
|
||||
return *this;
|
||||
}
|
||||
InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation) {
|
||||
InstanceBuilder& InstanceBuilder::must_enable_validation_layers (bool enable_validation) {
|
||||
info.enable_validation_layers = enable_validation;
|
||||
return *this;
|
||||
}
|
||||
bool InstanceBuilder::check_and_setup_validation_layers (bool enable_validation) {
|
||||
InstanceBuilder& InstanceBuilder::check_and_setup_validation_layers (bool enable_validation) {
|
||||
bool available =
|
||||
detail::check_extension_supported (system.available_extensions, detail::validation_layer_name);
|
||||
setup_validation_layers (available);
|
||||
return available;
|
||||
info.enable_validation_layers = available;
|
||||
return *this;
|
||||
}
|
||||
|
||||
InstanceBuilder& InstanceBuilder::set_default_debug_messenger () {
|
||||
@ -513,8 +513,8 @@ int get_graphics_queue_index (std::vector<VkQueueFamilyProperties> const& famili
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
// finds a compute queue which is distinct from the graphics queue and tries to find one without transfer support
|
||||
// returns -1 if none is found
|
||||
// finds a compute queue which is distinct from the graphics queue and tries to find one without
|
||||
// transfer support returns -1 if none is found
|
||||
int get_distinct_compute_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
|
||||
int compute = -1;
|
||||
for (int i = 0; i < families.size (); i++) {
|
||||
@ -529,8 +529,8 @@ int get_distinct_compute_queue_index (std::vector<VkQueueFamilyProperties> const
|
||||
}
|
||||
return compute;
|
||||
}
|
||||
// finds a transfer queue which is distinct from the graphics queue and tries to find one without compute support
|
||||
// returns -1 if none is found
|
||||
// finds a transfer queue which is distinct from the graphics queue and tries to find one without
|
||||
// compute support returns -1 if none is found
|
||||
int get_distinct_transfer_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
|
||||
int transfer = -1;
|
||||
for (int i = 0; i < families.size (); i++) {
|
||||
|
@ -124,37 +124,61 @@ void destroy_instance (Instance instance); // release instance resources
|
||||
|
||||
class InstanceBuilder {
|
||||
public:
|
||||
InstanceBuilder(); //automatically gets available layers and extensions
|
||||
InstanceBuilder (); // automatically gets available layers and extensions.
|
||||
|
||||
detail::Expected<Instance, detail::Error<InstanceError>> build (); // use builder pattern
|
||||
detail::Expected<Instance, detail::Error<InstanceError>> build ();
|
||||
|
||||
// Sets the name of the application. Defaults to "" if none is provided.
|
||||
InstanceBuilder& set_app_name (const char* app_name);
|
||||
// Sets the name of the engine. Defaults to "" if none is provided.
|
||||
InstanceBuilder& set_engine_name (const char* engine_name);
|
||||
|
||||
// Sets the (major, minor, patch) version of the application.
|
||||
InstanceBuilder& set_app_version (uint32_t major, uint32_t minor, uint32_t patch);
|
||||
// Sets the (major, minor, patch) version of the engine.
|
||||
InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch);
|
||||
// Sets the vulkan API version to use.
|
||||
InstanceBuilder& set_api_version (uint32_t major, uint32_t minor, uint32_t patch);
|
||||
|
||||
InstanceBuilder& add_layer (const char* layer_name);
|
||||
InstanceBuilder& add_extension (const char* extension_name);
|
||||
|
||||
bool check_and_add_layer (const char* layer_name);
|
||||
bool check_and_add_extension (const char* extension_name);
|
||||
// Loads the specified layer if it is available.
|
||||
InstanceBuilder& check_and_add_layer (const char* layer_name);
|
||||
// Adds a layer to be enabled. Will fail to create an instance if the layer isn't available.
|
||||
InstanceBuilder& must_enable_layer (const char* layer_name);
|
||||
// Enables the specified extension if it is avaiable.
|
||||
InstanceBuilder& check_and_add_extension (const char* extension_name);
|
||||
// Adds an extension to be enabled. Will fail to create an instance if the extension isn't available.
|
||||
InstanceBuilder& must_enable_extension (const char* extension_name);
|
||||
|
||||
InstanceBuilder& setup_validation_layers (bool enable_validation = true);
|
||||
// Headless Mode does not load the required extensions for presentation. Defaults to false.
|
||||
InstanceBuilder& set_headless (bool headless = false);
|
||||
// Checks if the validation layers are available and loads them if they are.
|
||||
InstanceBuilder& check_and_setup_validation_layers (bool enable_validation = true);
|
||||
// Enables the validation layers. Will fail to create an instance if the validation layers aren't available.
|
||||
InstanceBuilder& must_enable_validation_layers (bool enable_validation = true);
|
||||
|
||||
bool check_and_setup_validation_layers (bool enable_validation = true);
|
||||
|
||||
// Use a default debug callback that prints to standard out.
|
||||
InstanceBuilder& set_default_debug_messenger ();
|
||||
// Provide a user defined debug callback.
|
||||
InstanceBuilder& set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback);
|
||||
// Set what message severity is needed to trigger the callback.
|
||||
InstanceBuilder& set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
|
||||
// Add a message severity to the list that triggers the callback.
|
||||
InstanceBuilder& add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
|
||||
// Set what message type triggers the callback.
|
||||
InstanceBuilder& set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
|
||||
// Add a message type to the list of that triggers the callback.
|
||||
InstanceBuilder& add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
|
||||
|
||||
// Disable some validation checks.
|
||||
// Checks: All, and Shaders
|
||||
InstanceBuilder& add_validation_disable (VkValidationCheckEXT check);
|
||||
|
||||
// Enables optional parts of the validation layers.
|
||||
// Parts: best practices, gpu assisted, and gpu assisted reserve binding slot.
|
||||
InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable);
|
||||
|
||||
// Disables sections of the validation layers.
|
||||
// Options: All, shaders, thread safety, api parameters, object lifetimes, core checks, and unique handles.
|
||||
InstanceBuilder& add_validation_feature_disable (VkValidationFeatureDisableEXT disable);
|
||||
|
||||
private:
|
||||
@ -237,36 +261,53 @@ struct PhysicalDevice {
|
||||
friend class DeviceBuilder;
|
||||
};
|
||||
|
||||
enum class PreferredDeviceType { discrete, integrated, virtual_gpu, cpu, dont_care };
|
||||
struct PhysicalDeviceSelector {
|
||||
public:
|
||||
// Requires a vkb::Instance to construct, needed to pass instance creation info.
|
||||
PhysicalDeviceSelector (Instance const& instance);
|
||||
|
||||
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> select ();
|
||||
|
||||
// Set the surface in which the physical device should render to.
|
||||
PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance);
|
||||
|
||||
enum PreferredDeviceType { discrete, integrated, virtual_gpu, cpu, dont_care };
|
||||
// Set the desired physical device type to select. Defaults to PreferredDeviceType::discrete.
|
||||
PhysicalDeviceSelector& prefer_gpu_device_type (PreferredDeviceType type = PreferredDeviceType::discrete);
|
||||
// Allow fallback to a device type that isn't the preferred physical device type. Defaults to true.
|
||||
PhysicalDeviceSelector& allow_fallback_gpu (bool fallback = true);
|
||||
|
||||
// Require that a physical device supports presentation. Defaults to true.
|
||||
PhysicalDeviceSelector& require_present (bool require = true);
|
||||
PhysicalDeviceSelector& require_dedicated_transfer_queue ();
|
||||
// Require a queue family that supports compute operations but not graphics nor transfer.
|
||||
PhysicalDeviceSelector& require_dedicated_compute_queue ();
|
||||
// Require a queue family that supports transfer operations but not graphics nor compute.
|
||||
PhysicalDeviceSelector& require_dedicated_transfer_queue ();
|
||||
|
||||
// Require a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available.
|
||||
PhysicalDeviceSelector& required_device_memory_size (VkDeviceSize size);
|
||||
// Prefer a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available.
|
||||
PhysicalDeviceSelector& desired_device_memory_size (VkDeviceSize size);
|
||||
|
||||
// Require a physical device which supports a specific extension.
|
||||
PhysicalDeviceSelector& add_required_extension (const char* extension);
|
||||
// Require a physical device which supports a set of extensions.
|
||||
PhysicalDeviceSelector& add_required_extensions (std::vector<const char*> extensions);
|
||||
|
||||
// Prefer a physical device which supports a specific extension.
|
||||
PhysicalDeviceSelector& add_desired_extension (const char* extension);
|
||||
// Prefer a physical device which supports a set of extensions.
|
||||
PhysicalDeviceSelector& add_desired_extensions (std::vector<const char*> extensions);
|
||||
|
||||
// Prefer a physical device that supports a (major, minor) version of vulkan.
|
||||
PhysicalDeviceSelector& set_desired_version (uint32_t major, uint32_t minor);
|
||||
// Require a physical device that supports a (major, minor) version of vulkan. Default is Vulkan 1.0.
|
||||
PhysicalDeviceSelector& set_minimum_version (uint32_t major = 1, uint32_t minor = 0);
|
||||
|
||||
// Require a physical device which supports the features in VkPhysicalDeviceFeatures.
|
||||
PhysicalDeviceSelector& set_required_features (VkPhysicalDeviceFeatures features);
|
||||
|
||||
// Ignore all criteria and choose the first physical device that is available.
|
||||
// Only use when: The first gpu in the list may be set by global user preferences and an application may wish to respect it.
|
||||
PhysicalDeviceSelector& select_first_device_unconditionally (bool unconditionally = true);
|
||||
|
||||
private:
|
||||
@ -339,14 +380,19 @@ class DeviceBuilder {
|
||||
|
||||
detail::Expected<Device, detail::Error<DeviceError>> build ();
|
||||
|
||||
template <typename T> DeviceBuilder& add_pNext (T* structure);
|
||||
|
||||
// Require a queue family that supports compute operations but not graphics nor transfer.
|
||||
DeviceBuilder& request_dedicated_compute_queue (bool compute = true);
|
||||
// Require a queue family that supports transfer operations but not graphics nor compute.
|
||||
DeviceBuilder& request_dedicated_transfer_queue (bool transfer = true);
|
||||
|
||||
/* For advanced users */
|
||||
// For Advanced Users: specify the exact list of VkDeviceQueueCreateInfo's needed for the application.
|
||||
// If a custom queue setup is provided, getting the queues and queue indexes is up to the applicatoin.
|
||||
DeviceBuilder& custom_queue_setup (std::vector<CustomQueueDescription> queue_descriptions);
|
||||
|
||||
// For Advanced Users: Add a structure to the pNext chain of VkDeviceCreateInfo.
|
||||
// The structure must be valid when DeviceBuilder::build() is called.
|
||||
template <typename T> DeviceBuilder& add_pNext (T* structure);
|
||||
|
||||
private:
|
||||
struct DeviceInfo {
|
||||
VkDeviceCreateFlags flags = 0;
|
||||
|
@ -44,7 +44,7 @@ int test_instance_basic () {
|
||||
vkb::InstanceBuilder builder;
|
||||
|
||||
auto instance_ret =
|
||||
builder.setup_validation_layers ()
|
||||
builder.check_and_setup_validation_layers ()
|
||||
.set_app_name ("test")
|
||||
.set_debug_callback ([] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
@ -71,7 +71,7 @@ int test_instance_headless () {
|
||||
vkb::InstanceBuilder builder;
|
||||
|
||||
auto instance_ret =
|
||||
builder.setup_validation_layers ()
|
||||
builder.check_and_setup_validation_layers ()
|
||||
.set_headless ()
|
||||
.set_app_version (4, 5, 6)
|
||||
.set_app_name ("headless")
|
||||
|
Loading…
Reference in New Issue
Block a user