mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
10 KiB
254 lines
10 KiB
#ifndef Magnum_Vk_ShaderSet_h |
|
#define Magnum_Vk_ShaderSet_h |
|
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
|
2020, 2021, 2022, 2023, 2024 |
|
Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
copy of this software and associated documentation files (the "Software"), |
|
to deal in the Software without restriction, including without limitation |
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
and/or sell copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
/** @file |
|
* @brief Class @ref Magnum::Vk::ShaderSet, @ref Magnum::Vk::ShaderSpecialization |
|
* @m_since_latest |
|
*/ |
|
|
|
#include <initializer_list> |
|
#include <Corrade/Containers/Pointer.h> |
|
|
|
#include "Magnum/Tags.h" |
|
#include "Magnum/Vk/Vk.h" |
|
#include "Magnum/Vk/Vulkan.h" |
|
#include "Magnum/Vk/visibility.h" |
|
|
|
namespace Magnum { namespace Vk { |
|
|
|
/** |
|
@brief Shader specialization |
|
@m_since_latest |
|
|
|
Used by @ref ShaderSet for specifying shader specialization constants. See its |
|
documentation for more information. |
|
*/ |
|
class ShaderSpecialization { |
|
public: |
|
/** |
|
* @brief Construct an integer specialization constant |
|
* @param id Specialization constant ID |
|
* @param value Specialized value |
|
*/ |
|
/*implicit*/ ShaderSpecialization(UnsignedInt id, Int value): _id{id}, _data{reinterpret_cast<const UnsignedInt&>(value)} {} |
|
|
|
/** |
|
* @brief Construct a float specialization constant |
|
* @param id Specialization constant ID |
|
* @param value Specialized value |
|
*/ |
|
/*implicit*/ ShaderSpecialization(UnsignedInt id, Float value): _id{id}, _data{reinterpret_cast<const UnsignedInt&>(value)} {} |
|
|
|
/** |
|
* @brief Construct a boolean specialization constant |
|
* @param id Specialization constant ID |
|
* @param value Specialized value |
|
*/ |
|
/*implicit*/ ShaderSpecialization(UnsignedInt id, bool value): _id{id}, _data{value} {} |
|
|
|
/** @brief Specialization constant ID */ |
|
UnsignedInt id() const { return _id; } |
|
|
|
/** |
|
* @brief Specialization value data |
|
* |
|
* The contents can be an integer, a float or a boolean extended to |
|
* four bytes based on what constructor got used. |
|
*/ |
|
UnsignedInt data() const { return _data; } |
|
|
|
private: |
|
UnsignedInt _id; |
|
|
|
/* It would be great if this was explicitly said in either the SPIR-V |
|
or Vulkan spec, but AFAICT, specialization is only possible for |
|
booleans (which have to be four bytes), ints and floats, not |
|
composite types (and at least in the GL_KHR_vulkan_glsl spec these |
|
are enumerated as the only allowed types). Looking at the SPIR-V |
|
spec, OpSpecConstant gets turned into OpConstant and that can only |
|
be an int or float as well. |
|
|
|
In conclusion, I don't see why there has to be the size specified |
|
if it's required to be always 4 bytes. Maybe future-proofing blah |
|
blah, which may as well never happen. Here I'm making my life |
|
simpler by explicitly supporting only the three allowed types, |
|
putting them all into an int. */ |
|
UnsignedInt _data; |
|
}; |
|
|
|
/** |
|
@brief Shader set |
|
@m_since_latest |
|
|
|
A collection of @ref Shader instances together with populated |
|
@type_vk_keyword{PipelineShaderStageCreateInfo} structures for use in a |
|
pipeline. |
|
|
|
@section Vk-ShaderSet-usage Usage |
|
|
|
Based on whether the shader set is for a rasterization, compute or ray tracing |
|
pipeline, you'll call @ref addShader() with all @ref Shader stages that the |
|
pipeline needs. At the very least you need to specify what stage is the shader |
|
for and the entrypoint name --- usually it'd be @cpp main() @ce, but there can |
|
be also SPIR-V shader modules with multiple entry points, which is why this |
|
parameter is needed. |
|
|
|
@snippet Vk.cpp ShaderSet-usage |
|
|
|
<b></b> |
|
|
|
@m_class{m-note m-success} |
|
|
|
@par |
|
The above code uses the @link Corrade::Containers::Literals::StringLiterals::operator""_s() Containers::Literals::operator""_s() @endlink |
|
literal, which lets the library know that given string is global and |
|
null-terminated. Such strings then don't need to be copied internally to |
|
keep them in scope until they're consumed by Vulkan APIs. |
|
|
|
@subsection Vk-ShaderSet-usage-specializations Specialization constants |
|
|
|
If the shader module exposes specialization constants, those can be specialized |
|
via an additional parameter, taking a list of @ref ShaderSpecialization |
|
instances. The constant can be an integer, float or a boolean; constant IDs not |
|
present in the SPIR-V module are ignored. |
|
|
|
@snippet Vk.cpp ShaderSet-usage-specializations |
|
|
|
@subsection Vk-ShaderSet-usage-ownership-transfer Shader ownership transfer |
|
|
|
To create a self-contained shader set it's possible to move the @ref Shader |
|
instances into the class using the @ref addShader(ShaderStage, Shader&&, Containers::StringView, Containers::ArrayView<const ShaderSpecialization>) |
|
overload. If you have a multi-entrypoint shader, move only the last specified |
|
stage, for example: |
|
|
|
@snippet Vk.cpp ShaderSet-usage-ownership-transfer |
|
*/ |
|
class MAGNUM_VK_EXPORT ShaderSet { |
|
public: |
|
/** |
|
* @brief Constructor |
|
* |
|
* Creates an empty shader set. At least one shader has to be present, |
|
* call @ref addShader() to add it. |
|
*/ |
|
explicit ShaderSet(); |
|
|
|
/** @brief Copying is not allowed */ |
|
ShaderSet(const ShaderSet&) = delete; |
|
|
|
/** @brief Move constructor */ |
|
ShaderSet(ShaderSet&& other) noexcept; |
|
|
|
/** |
|
* @brief Destructor |
|
* |
|
* If any shaders were added using @ref addShader(ShaderStage, Shader&&, Containers::StringView, Containers::ArrayView<const ShaderSpecialization>), |
|
* their owned instances are destructed at this point. |
|
*/ |
|
~ShaderSet(); |
|
|
|
/** @brief Copying is not allowed */ |
|
ShaderSet& operator=(const ShaderSet&) = delete; |
|
|
|
/** @brief Move assignment */ |
|
ShaderSet& operator=(ShaderSet&& other) noexcept; |
|
|
|
/** |
|
* @brief Add a shader |
|
* @param stage Shader stage |
|
* @param shader A @ref Shader or a raw Vulkan shader handle |
|
* @param entrypoint Entrypoint name |
|
* @param specializations Specialization constant values |
|
* @return Reference to self (for method chaining) |
|
* |
|
* The function makes a copy of @p entrypoint if it's not global or |
|
* null-terminated, use the @link Corrade::Containers::Literals::StringLiterals::operator""_s() Containers::Literals::operator""_s() @endlink |
|
* literal to prevent that where possible. |
|
* |
|
* The populated @type_vk{VkPipelineShaderStageCreateInfo} is |
|
* subsequently available through @ref stages() for direct editing. The |
|
* following fields are pre-filled in addition to `sType`, everything |
|
* else is zero-filled: |
|
* |
|
* - `stage` |
|
* - `module` to @p shader |
|
* - `pName` to @p entrypoint |
|
* - `pSpecializationInfo`, if @p specializations are non-empty |
|
* - @cpp pSpecializationInfo->mapEntryCount @ce, |
|
* @cpp pSpecializationInfo->pMapEntries @ce, |
|
* @cpp pSpecializationInfo->pMapEntries[i].constantID @ce, |
|
* @cpp pSpecializationInfo->pMapEntries[i].offset @ce, |
|
* @cpp pSpecializationInfo->pMapEntries[i].size @ce, |
|
* @cpp pSpecializationInfo->dataSize @ce and |
|
* @cpp pSpecializationInfo->pData @ce to processed and linearized |
|
* contents of @p specializations |
|
*/ |
|
ShaderSet& addShader(ShaderStage stage, VkShaderModule shader, Containers::StringView entrypoint, Containers::ArrayView<const ShaderSpecialization> specializations); |
|
|
|
/** @overload */ |
|
/* Having a default here to avoid having to include ArrayView or have |
|
two addShader() implementations, one with and one without */ |
|
ShaderSet& addShader(ShaderStage stage, VkShaderModule shader, Containers::StringView entrypoint, std::initializer_list<ShaderSpecialization> specializations = {}); |
|
|
|
/** |
|
* @brief Add a shader and take over its ownership |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Compared to @ref addShader(ShaderStage, VkShaderModule, Containers::StringView, Containers::ArrayView<const ShaderSpecialization>) |
|
* the @p shader instance ownership is transferred to the class and |
|
* thus doesn't have to be managed separately. |
|
*/ |
|
ShaderSet& addShader(ShaderStage stage, Shader&& shader, Containers::StringView entrypoint, Containers::ArrayView<const ShaderSpecialization> specializations); |
|
|
|
/** @overload */ |
|
/* Having a default here to avoid having to include ArrayView or have |
|
two addShader() implementations, one with and one without */ |
|
ShaderSet& addShader(ShaderStage stage, Shader&& shader, Containers::StringView entrypoint, std::initializer_list<ShaderSpecialization> specializations = {}); |
|
|
|
/** |
|
* @brief Shader stages |
|
* |
|
* Exposes all data added with @ref addShader() calls. If |
|
* @ref addShader() was not called yet, the returned view is empty. |
|
*/ |
|
Containers::ArrayView<VkPipelineShaderStageCreateInfo> stages(); |
|
/** @overload */ |
|
Containers::ArrayView<const VkPipelineShaderStageCreateInfo> stages() const; |
|
|
|
private: |
|
VkPipelineShaderStageCreateInfo _stages[6]; |
|
VkSpecializationInfo _specializations[6]; |
|
std::size_t _stageCount; |
|
|
|
struct State; |
|
Containers::Pointer<State> _state; |
|
}; |
|
|
|
}} |
|
|
|
#endif
|
|
|