wisdom
Loading...
Searching...
No Matches
Library Structure

This page provides an overview of the Wisdom library structure and its components.

Overview

The Wisdom library is structured into several modules, each providing a specific functionality. The provided classes and functions are designed to be easy to use and overhead free. When using the library as a header-only library, all the functions are inline and do not incur any overhead. Most of the classes are done in an independent way, so you only need to store classes that you need. The classes, as well as functions and types and their respective documentation, are generated to maintain consistency of interface and ease of use. Files that generate everything are stored at xml directory. Those files can be used to generate the API and its documentation in any other language, providing you have a geneartor and a way to link those functions to C++ code.

How It Works

The library sits above the DirectX 12 and Vulkan APIs, providing a minimal abstraction layer. The library implementation is split into 2 implementations: one for DirectX 12 and one for Vulkan. Both implementations are designed to be as similar as possible, providing a consistent interface for the user. The library also does not use virtual functions, so it is as fast as possible.

The implementation for DirectX 12 is done in the wisdom/dx12 directory, while the implementation for Vulkan is done in the wisdom/vulkan directory. DirectX 12 implementation is prefixed with DX12 and Vulkan implementation is prefixed with VK. So the classes are named DX12Factory, DX12Adapter, VKFactory, VKAdapter and so on.

Then the implementation is wrapped into the wis::Factory, wis::Adapter, wis::Device and so on. File wisdom/include/wisdom/wisdom.hpp is the main header file that includes all the necessary headers for the library. It also selects the implementation based on the platform and the API. On Windows, it will use DirectX 12 implementation, while on Linux it will use Vulkan implementation.

Note
To use Vulkan implementation on Windows, you can set the WISDOM_FORCE_VULKAN CMake flag to ON or define WISDOM_FORCE_VULKAN in global preprocessor. NuGet package also has this flag in the propertiy page of the project.

The implementation will scan if you have Vulkan SDK installed and if it is available, it will use Vulkan implementation. Otherwise it will produce an error that Vulkan is not available.

Note
For modules there are 2 implementations - one uses regular module name import wisdom and the other uses import wisdom.fvk. This is done due to the fact that preprocessor switches do not affect modules imported from other libraries. You cannot use both imports in the same project, so you should choose one of them. Althogh both modules provide implemntations for both DirectX 12 and Vulkan.

Types

Only .hpp files provided to be used in your project. The .h files contain the implementation details and are not meant to be used directly. However types that they provide can be used directly in your project. One use case is to use both DirectX 12 and Vulkan implementations in the same project. In such case you should use prefixed types, like wis::DX12Factory and wis::VKFactory, to avoid name clashes. Functions that create device and factory are also prefixed with DX12 or VK for that particular reason.

For regular use you can use the wis::Factory, wis::Adapter, wis::Device and so on types, which are the main types of the library. All the extensions and platform-specific addons follow the same naming convention, so you can use them without any issues.

All the examples and documentation will be provided with non-prefixed types to simplify the usage.

All the types have a destructor and independent lifetime, so you can use them without worrying about the lifetime of the underlying resources. For example, if wis::Device is destroyed before wis::Buffer, the buffer will still be valid and can be used. The underlying resources will be released when the last reference to them is destroyed. The library uses RAII principles to manage the lifetime of the resources, so you don't have to worry about memory leaks or resource management. Most of the classes are move-only, so you can use them without worrying about copying the resources.

API

Provided API is designed to be easy to use and understand. It is based on the modern C++ standards and best practices. Most of the API functions return wis::Result type, which is a simple wrapper around the error code and the error message. Error messages are brief and compile-time created, and their lifetime is static, so you can use them without worrying about the lifetime of the error message. Since the library is designed to be used with modern C++ standards, output is best handled with structured bindings.

Example of how to use the API:

auto&& [result, factory] = wis::CreateFactory();

The CreateFactory function will return a wis::Result and a wis::Factory object. The wis::Result object will contain the error code and the error message, while the wis::Factory object will contain the factory object.

The library also provides RVO (Return Value Optimization) for the functions that return objects. Those functions will return the object directly, and result will be stored in the first argument of the function.

Example of how to use the API with RVO:

wis::Result result = wis::success;
auto factory = wis::CreateFactory(result);
Main source of communication of operation success. To check for success compare wis::Result::status w...
Definition api.hpp:1534

Those functions are generated with first argument being wis::Result& and returning the object directly. So if you want to squeeze the last bit of performance, you can use this approach, since it will avoid using extra move constructor or move assignment.

Extending the Library

The library is designed to be extensible, so you can add your own extensions and functionality to it. Open-ended extensibility is one of the key features of the library. Every class has a corresponding Internal class that provides the implementation details. To query the internal implementation, you can use the GetInternal and GetMutableInternal. Once you have the internal implementation, you can use it to extend the library with your own functionality. To follow the practice you can see the implementation of any extension from wisdom/extensions directory.

You don't have to use the same conventions as the library does, but it is recommended to follow the same naming conventions and structure to keep the code consistent and easy to read.

Note
Although the library provides internals, it is not recommended to rely on them in your code. The internals are subject to change and may not be stable across different versions of the library. Although logical components like wis::DX12Device having ID3D12Device* are guaranteed to exist as long as underlying APIs don't change the logic.