Browse Source

Vk: initial rasterization pipeline creation.

I named it RasterizationPipelineCreateInfo and not
GraphicsPipelineCreateInfo because there's now a
RayTracingPipelineCreateInfo as well, which is *also* graphics, and it
would be confusing for everyone except people already drowned in Vulkan
naming quirks.
pull/494/head
Vladimír Vondruš 5 years ago
parent
commit
f84a385fea
  1. 22
      doc/snippets/MagnumVk.cpp
  2. 26
      doc/vulkan-mapping.dox
  3. 4
      src/Magnum/Vk/CMakeLists.txt
  4. 15
      src/Magnum/Vk/DeviceFeatures.h
  5. 49
      src/Magnum/Vk/Implementation/dynamicRasterizationStateMapping.hpp
  6. 5
      src/Magnum/Vk/MeshLayout.h
  7. 277
      src/Magnum/Vk/Pipeline.cpp
  8. 105
      src/Magnum/Vk/Pipeline.h
  9. 2
      src/Magnum/Vk/PipelineLayout.h
  10. 534
      src/Magnum/Vk/RasterizationPipelineCreateInfo.h
  11. 5
      src/Magnum/Vk/Test/CMakeLists.txt
  12. 462
      src/Magnum/Vk/Test/PipelineTest.cpp
  13. 298
      src/Magnum/Vk/Test/PipelineVkTest.cpp
  14. 4
      src/Magnum/Vk/Vk.h

22
doc/snippets/MagnumVk.cpp

@ -52,8 +52,10 @@
#include "Magnum/Vk/MemoryAllocateInfo.h"
#include "Magnum/Vk/MeshLayout.h"
#include "Magnum/Vk/Pipeline.h"
#include "Magnum/Vk/PipelineLayout.h"
#include "Magnum/Vk/PixelFormat.h"
#include "Magnum/Vk/Queue.h"
#include "Magnum/Vk/RasterizationPipelineCreateInfo.h"
#include "Magnum/Vk/RenderPassCreateInfo.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/ShaderCreateInfo.h"
@ -790,6 +792,26 @@ meshLayout
/* [MeshLayout-usage] */
}
{
Vk::Device device{NoCreate};
/* The include should be a no-op here since it was already included above */
/* [Pipeline-creation-rasterization] */
#include <Magnum/Vk/RasterizationPipelineCreateInfo.h>
DOXYGEN_IGNORE()
Vk::ShaderSet shaderSet{DOXYGEN_IGNORE()};
Vk::MeshLayout meshLayout{DOXYGEN_IGNORE(MeshPrimitive{})};
Vk::PipelineLayout pipelineLayout{DOXYGEN_IGNORE(NoCreate)};
Vk::RenderPass renderPass{DOXYGEN_IGNORE(NoCreate)};
Vk::Pipeline pipeline{device, Vk::RasterizationPipelineCreateInfo{
shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1}
.setViewport({{}, {800.0f, 600.0f}})
};
/* [Pipeline-creation-rasterization] */
}
{
Vk::Device device{NoCreate};
/* The include should be a no-op here since it was already included above */

26
doc/vulkan-mapping.dox

@ -70,7 +70,7 @@ Vulkan handle | Matching API
@type_vk{ImageView} | @ref ImageView
@type_vk{Instance} | @ref Instance
@type_vk{PhysicalDevice} | @ref DeviceProperties
@type_vk{Pipeline} | |
@type_vk{Pipeline} | @ref Pipeline
@type_vk{PipelineLayout} | @ref PipelineLayout
@type_vk{QueryPool} | |
@type_vk{Queue} | @ref Queue
@ -186,7 +186,6 @@ Vulkan function | Matching API
@fn_vk{CreateBuffer}, \n @fn_vk{DestroyBuffer} | @ref Buffer constructor and destructor
@fn_vk{CreateBufferView}, \n @fn_vk{DestroyBufferView} | |
@fn_vk{CreateCommandPool}, \n @fn_vk{DestroyCommandPool} | @ref CommandPool constructor and destructor
@fn_vk{CreateComputePipelines}, \n @fn_vk{DestroyComputePipelines} | |
@fn_vk{CreateDebugReportCallbackEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT**, \n @fn_vk{DestroyDebugReportCallbackEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT** | |
@fn_vk{CreateDebugUtilsMessengerEXT} @m_class{m-label m-flat m-warning} **EXT**, \n @fn_vk{DestroyDebugUtilsMessengerEXT} @m_class{m-label m-flat m-warning} **EXT** | |
@fn_vk{CreateDeferredOperationKHR} @m_class{m-label m-flat m-warning} **KHR**, \n @fn_vk{DestroyDeferredOperationKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@ -200,11 +199,10 @@ Vulkan function | Matching API
@fn_vk{CreateImage}, \n @fn_vk{DestroyImage} | @ref Image constructor and destructor
@fn_vk{CreateImageView}, \n @fn_vk{DestroyImageView} | @ref ImageView constructor and destructor
@fn_vk{CreateInstance}, \n @fn_vk{DestroyInstance} | @ref Instance constructor and destructor
@fn_vk{CreatePipeline}, \n @fn_vk{DestroyPipeline} | |
@fn_vk{CreateGraphicsPipelines}, \n @fn_vk{CreateComputePipelines}, \n @fn_vk{CreateRayTracingPipelinesKHR} @m_class{m-label m-flat m-warning} **KHR**, \n @fn_vk{DestroyPipeline} | @ref Pipeline constructor and destructor
@fn_vk{CreatePipelineCache}, \n @fn_vk{DestroyPipelineCache} | |
@fn_vk{CreatePipelineLayout}, \n @fn_vk{DestroyPipelineLayout} | @ref PipelineLayout constructor and destructor
@fn_vk{CreateQueryPool}, \n @fn_vk{DestroyQueryPool} | |
@fn_vk{CreateRayTracingPipelinesKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CreateRenderPass}, \n @fn_vk{CreateRenderPass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{DestroyRenderPass} | @ref RenderPass constructor and destructor
@fn_vk{CreateSampler}, \n @fn_vk{DestroySampler} | |
@fn_vk{CreateSamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** , \n @fn_vk{DestroySamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@ -530,7 +528,7 @@ Vulkan structure | Matching API
Vulkan structure | Matching API
--------------------------------------- | ------------
@type_vk{GraphicsPipelineCreateInfo} | |
@type_vk{GraphicsPipelineCreateInfo} | @ref RasterizationPipelineCreateInfo
@subsection vulkan-mapping-structures-i I
@ -655,21 +653,21 @@ Vulkan structure | Matching API
@type_vk{PhysicalDeviceVulkan12Properties} @m_class{m-label m-flat m-success} **1.2** | ignored for compatibility reasons
@type_vk{PhysicalDeviceVulkanMemoryModelFeatures} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref DeviceFeatures
@type_vk{PipelineCacheCreateInfo} | |
@type_vk{PipelineColorBlendAttachmentState} | |
@type_vk{PipelineColorBlendStateCreateInfo} | |
@type_vk{PipelineDepthStencilStateCreateInfo} | |
@type_vk{PipelineDynamicStateCreateInfo} | |
@type_vk{PipelineColorBlendAttachmentState} | @ref RasterizationPipelineCreateInfo
@type_vk{PipelineColorBlendStateCreateInfo} | @ref RasterizationPipelineCreateInfo
@type_vk{PipelineDepthStencilStateCreateInfo} | @ref RasterizationPipelineCreateInfo
@type_vk{PipelineDynamicStateCreateInfo} | @ref RasterizationPipelineCreateInfo
@type_vk{PipelineInputAssemblyStateCreateInfo} | @ref MeshLayout
@type_vk{PipelineLayoutCreateInfo} | @ref PipelineLayoutCreateInfo
@type_vk{PipelineLibraryCreateInfoKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{PipelineMultisampleStateCreateInfo} | |
@type_vk{PipelineRasterizationStateCreateInfo} | |
@type_vk{PipelineMultisampleStateCreateInfo} | @ref RasterizationPipelineCreateInfo
@type_vk{PipelineRasterizationStateCreateInfo} | @ref RasterizationPipelineCreateInfo
@type_vk{PipelineShaderStageCreateInfo} | @ref ShaderSet
@type_vk{PipelineTessellationStateCreateInfo} | |
@type_vk{PipelineTessellationDomainOriginStateCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@type_vk{PipelineVertexInputDivisorStateCreateInfoEXT} @m_class{m-label m-flat m-warning} **EXT** | @ref MeshLayout
@type_vk{PipelineVertexInputStateCreateInfo} | @ref MeshLayout
@type_vk{PipelineViewportStateCreateInfo} | |
@type_vk{PipelineViewportStateCreateInfo} | @ref RasterizationPipelineCreateInfo
@type_vk{ProtectedSubmitInfo} | |
@type_vk{PushConstantRange} | |
@ -831,7 +829,7 @@ Vulkan enum | Matching API
@type_vk{DescriptorType} | |
@type_vk{DeviceQueueCreateFlagBits}, \n @type_vk{DeviceQueueCreateFlags} | |
@type_vk{DriverId} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{DynamicState} | |
@type_vk{DynamicState} | @ref DynamicRasterizationState
@subsection vulkan-mapping-enums-e E
@ -921,7 +919,7 @@ Vulkan enum | Matching API
@type_vk{PipelineCacheCreateFlagBits}, \n @type_vk{PipelineCacheCreateFlags} | |
@type_vk{PipelineCacheHeaderVersion} | |
@type_vk{PipelineCacheCreateFlagBits}, \n @type_vk{PipelineCacheCreateFlags} | |
@type_vk{PipelineCreateFlagBits}, \n @type_vk{PipelineCreateFlags} | |
@type_vk{PipelineCreateFlagBits}, \n @type_vk{PipelineCreateFlags} | @ref RasterizationPipelineCreateInfo::Flag, \n @ref RasterizationPipelineCreateInfo::Flags
@type_vk{PipelineShaderStageCreateFlagBits}, \n @type_vk{PipelineShaderStageCreateFlags} | |
@type_vk{PipelineStageFlagBits}, \n @type_vk{PipelineStageFlags} | @ref PipelineStage, \n @ref PipelineStages
@type_vk{PointClippingBehavior} @m_class{m-label m-flat m-success} **KHR, 1.1** | |

4
src/Magnum/Vk/CMakeLists.txt

@ -33,7 +33,6 @@ set(MagnumVk_SRCS
Fence.cpp
Framebuffer.cpp
Handle.cpp
Pipeline.cpp
PipelineLayout.cpp
Queue.cpp
Result.cpp
@ -58,6 +57,7 @@ set(MagnumVk_GracefulAssert_SRCS
LayerProperties.cpp
MeshLayout.cpp
Memory.cpp
Pipeline.cpp
PixelFormat.cpp
RenderPass.cpp
ShaderSet.cpp
@ -98,6 +98,7 @@ set(MagnumVk_HEADERS
PipelineLayoutCreateInfo.h
PixelFormat.h
Queue.h
RasterizationPipelineCreateInfo.h
RenderPass.h
RenderPassCreateInfo.h
Result.h
@ -121,6 +122,7 @@ set(MagnumVk_PRIVATE_HEADERS
Implementation/compressedPixelFormatMapping.hpp
Implementation/deviceFeatureMapping.hpp
Implementation/dynamicRasterizationStateMapping.hpp
Implementation/pixelFormatMapping.hpp
Implementation/structureHelpers.h
Implementation/vertexFormatMapping.hpp)

15
src/Magnum/Vk/DeviceFeatures.h

@ -1275,9 +1275,20 @@ enum class DeviceFeature: UnsignedShort {
/* VkPhysicalDeviceExtendedDynamicStateFeaturesEXT, #268 */
/**
* Extended dynamic state is supported.
* The @ref DynamicRasterizationState::CullMode,
* @relativeref{DynamicRasterizationState,FrontFace},
* @relativeref{DynamicRasterizationState,PrimitiveTopology},
* @relativeref{DynamicRasterizationState,ViewportWithCount},
* @relativeref{DynamicRasterizationState,ScissorWithCount},
* @relativeref{DynamicRasterizationState,VertexInputBindingStride},
* @relativeref{DynamicRasterizationState,DepthTestEnable},
* @relativeref{DynamicRasterizationState,DepthWriteEnable},
* @relativeref{DynamicRasterizationState,DepthCompareOperation},
* @relativeref{DynamicRasterizationState,DepthBoundsTestEnable},
* @relativeref{DynamicRasterizationState,StencilTestEnable} and
* @relativeref{DynamicRasterizationState,StencilOperation} extended
* dynamic state is supported.
* @requires_vk_extension Extension @vk_extension{EXT,extended_dynamic_state}
* @todoc list the actual DynamicState values once the enum exists
*/
ExtendedDynamicState,

49
src/Magnum/Vk/Implementation/dynamicRasterizationStateMapping.hpp

@ -0,0 +1,49 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 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.
*/
/* See Magnum/Vk/RasterizationPipelineCreateInfo.cpp */
#ifdef _c
_c(Viewport, VIEWPORT)
_c(Scissor, SCISSOR)
_c(LineWidth, LINE_WIDTH)
_c(DepthBias, DEPTH_BIAS)
_c(BlendConstants, BLEND_CONSTANTS)
_c(DepthBounds, DEPTH_BOUNDS)
_c(StencilCompareMask, STENCIL_COMPARE_MASK)
_c(StencilWriteMask, STENCIL_WRITE_MASK)
_c(StencilReference, STENCIL_REFERENCE)
_c(CullMode, CULL_MODE_EXT)
_c(FrontFace, FRONT_FACE_EXT)
_c(PrimitiveTopology, PRIMITIVE_TOPOLOGY_EXT)
_c(ViewportWithCount, VIEWPORT_WITH_COUNT_EXT)
_c(ScissorWithCount, SCISSOR_WITH_COUNT_EXT)
_c(VertexInputBindingStride, VERTEX_INPUT_BINDING_STRIDE_EXT)
_c(DepthTestEnable, DEPTH_TEST_ENABLE_EXT)
_c(DepthWriteEnable, DEPTH_WRITE_ENABLE_EXT)
_c(DepthCompareOperation, DEPTH_COMPARE_OP_EXT)
_c(DepthBoundsTestEnable, DEPTH_BOUNDS_TEST_ENABLE_EXT)
_c(StencilTestEnable, STENCIL_TEST_ENABLE_EXT)
_c(StencilOperation, STENCIL_OP_EXT)
#endif

5
src/Magnum/Vk/MeshLayout.h

@ -179,7 +179,8 @@ Wraps a
@m_class{m-noindent}
describing how vertex attributes are organized in buffers and what's the layout
of each attribute.
of each attribute. Used as an input for creating a
@ref Vk-Pipeline-creation-rasterization "rasterization pipeline".
@section Vk-MeshLayout-usage Usage
@ -195,7 +196,7 @@ vertex buffer when drawing.
@subsection Vk-MeshLayout-usage-comparison Layout comparison
Because a pipeline is tied to a particular mesh layout (apart from certain
Because a @ref Pipeline is tied to a particular mesh layout (apart from certain
aspects that can be controlled via dynamic state), new pipelines should be
created only when the layout is actually different. For that, the class
provides a @ref operator==(), which returns @cpp true @ce when the two layouts

277
src/Magnum/Vk/Pipeline.cpp

@ -24,15 +24,290 @@
*/
#include "Pipeline.h"
#include "RasterizationPipelineCreateInfo.h"
#include "CommandBuffer.h"
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Array.h>
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/Image.h"
#include "Magnum/Vk/Integration.h"
#include "Magnum/Vk/MeshLayout.h"
#include "Magnum/Vk/ShaderSet.h"
namespace Magnum { namespace Vk {
struct RasterizationPipelineCreateInfo::State {
Containers::Array<VkPipelineColorBlendAttachmentState> colorBlendAttachments;
Containers::Array<VkDynamicState> dynamicStates;
/** @todo make an array once we support multiview */
VkViewport viewport;
VkRect2D scissor;
};
RasterizationPipelineCreateInfo::RasterizationPipelineCreateInfo(const ShaderSet& shaderSet, const MeshLayout& meshLayout, const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass, const UnsignedInt subpass, const UnsignedInt subpassColorAttachmentCount, Flags flags): _info{}, _viewportInfo{}, _rasterizationInfo{}, _multisampleInfo{}, _depthStencilInfo{}, _colorBlendInfo{}, _dynamicInfo{}, _state{Containers::InPlaceInit} {
_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
_info.flags = VkPipelineCreateFlags(flags);
_info.stageCount = shaderSet.stages().size();
_info.pStages = shaderSet.stages();
_info.pVertexInputState = meshLayout;
_info.pInputAssemblyState = meshLayout;
/* pTesselationState is fine to be null */
/** @todo add it if we get passed a tessellation shader? or should the
shader wrapper include it? */
/* Leaving pViewportState null as that gets (but doesn't have to, if
rasterization is disabled) set by setViewport() */
_rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
_rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL;
_rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
_rasterizationInfo.lineWidth = 1.0f;
_info.pRasterizationState = &_rasterizationInfo;
_multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
_multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
_info.pMultisampleState = &_multisampleInfo;
_depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
_info.pDepthStencilState = &_depthStencilInfo;
_state->colorBlendAttachments = Containers::Array<VkPipelineColorBlendAttachmentState>{Containers::ValueInit, subpassColorAttachmentCount};
for(VkPipelineColorBlendAttachmentState& i: _state->colorBlendAttachments) {
i.colorWriteMask = VK_COLOR_COMPONENT_R_BIT|
VK_COLOR_COMPONENT_G_BIT|
VK_COLOR_COMPONENT_B_BIT|
VK_COLOR_COMPONENT_A_BIT;
}
_colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
_colorBlendInfo.attachmentCount = subpassColorAttachmentCount;
_colorBlendInfo.pAttachments = _state->colorBlendAttachments;
_info.pColorBlendState = &_colorBlendInfo;
/* pDynamicState left null, gets set by setDynamicStates() if needed */
_info.layout = pipelineLayout;
_info.renderPass = renderPass;
_info.subpass = subpass;
}
RasterizationPipelineCreateInfo::RasterizationPipelineCreateInfo(NoInitT) noexcept {}
RasterizationPipelineCreateInfo::RasterizationPipelineCreateInfo(const VkGraphicsPipelineCreateInfo& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info)
{
/* Copy and reroute all top-level nested structs as well */
if(info.pViewportState)
_info.pViewportState = &(_viewportInfo = *info.pViewportState);
if(info.pRasterizationState)
_info.pRasterizationState = &(_rasterizationInfo = *info.pRasterizationState);
if(info.pMultisampleState)
_info.pMultisampleState = &(_multisampleInfo = *info.pMultisampleState);
if(info.pDepthStencilState)
_info.pDepthStencilState = &(_depthStencilInfo = *info.pDepthStencilState);
if(info.pColorBlendState)
_info.pColorBlendState = &(_colorBlendInfo = *info.pColorBlendState);
if(info.pDynamicState)
_info.pDynamicState = &(_dynamicInfo = *info.pDynamicState);
}
RasterizationPipelineCreateInfo::RasterizationPipelineCreateInfo(RasterizationPipelineCreateInfo&& other) noexcept:
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(other._info),
_viewportInfo(other._viewportInfo),
_rasterizationInfo(other._rasterizationInfo),
_multisampleInfo(other._multisampleInfo),
_depthStencilInfo(other._depthStencilInfo),
_colorBlendInfo(other._colorBlendInfo),
_dynamicInfo(other._dynamicInfo),
_state{std::move(other._state)}
{
/* Reroute the pointers */
if(_info.pViewportState == &other._viewportInfo)
_info.pViewportState = &_viewportInfo;
if(_info.pRasterizationState == &other._rasterizationInfo)
_info.pRasterizationState = &_rasterizationInfo;
if(_info.pMultisampleState == &other._multisampleInfo)
_info.pMultisampleState = &_multisampleInfo;
if(_info.pDepthStencilState == &other._depthStencilInfo)
_info.pDepthStencilState = &_depthStencilInfo;
if(_info.pColorBlendState == &other._colorBlendInfo)
_info.pColorBlendState = &_colorBlendInfo;
if(_info.pDynamicState == &other._dynamicInfo)
_info.pDynamicState = &_dynamicInfo;
/* Ensure the previous instance doesn't reference state that's now ours */
/** @todo this is now more like a destructible move, do it more selectively
and clear only what's really ours and not external? */
other._info.pNext = nullptr;
other._info.stageCount = 0;
other._info.pStages = nullptr;
other._info.pVertexInputState = nullptr;
other._info.pInputAssemblyState = nullptr;
other._info.pTessellationState = nullptr;
other._info.pViewportState = nullptr;
other._info.pRasterizationState = nullptr;
other._info.pMultisampleState = nullptr;
other._info.pDepthStencilState = nullptr;
other._info.pColorBlendState = nullptr;
other._info.pDynamicState = nullptr;
}
RasterizationPipelineCreateInfo::~RasterizationPipelineCreateInfo() = default;
RasterizationPipelineCreateInfo& RasterizationPipelineCreateInfo::operator=(RasterizationPipelineCreateInfo&& other) noexcept {
using std::swap;
swap(other._info, _info);
swap(other._viewportInfo, _viewportInfo);
swap(other._rasterizationInfo, _rasterizationInfo);
swap(other._multisampleInfo, _multisampleInfo);
swap(other._depthStencilInfo, _depthStencilInfo);
swap(other._colorBlendInfo, _colorBlendInfo);
swap(other._dynamicInfo, _dynamicInfo);
swap(other._state, _state);
/* Reroute the pointers */
if(_info.pViewportState == &other._viewportInfo)
_info.pViewportState = &_viewportInfo;
if(_info.pRasterizationState == &other._rasterizationInfo)
_info.pRasterizationState = &_rasterizationInfo;
if(_info.pMultisampleState == &other._multisampleInfo)
_info.pMultisampleState = &_multisampleInfo;
if(_info.pDepthStencilState == &other._depthStencilInfo)
_info.pDepthStencilState = &_depthStencilInfo;
if(_info.pColorBlendState == &other._colorBlendInfo)
_info.pColorBlendState = &_colorBlendInfo;
if(_info.pDynamicState == &other._dynamicInfo)
_info.pDynamicState = &_dynamicInfo;
/* And other way around as well */
if(other._info.pViewportState == &_viewportInfo)
other._info.pViewportState = &other._viewportInfo;
if(other._info.pRasterizationState == &_rasterizationInfo)
other._info.pRasterizationState = &other._rasterizationInfo;
if(other._info.pMultisampleState == &_multisampleInfo)
other._info.pMultisampleState = &other._multisampleInfo;
if(other._info.pDepthStencilState == &_depthStencilInfo)
other._info.pDepthStencilState = &other._depthStencilInfo;
if(other._info.pColorBlendState == &_colorBlendInfo)
other._info.pColorBlendState = &other._colorBlendInfo;
if(other._info.pDynamicState == &_dynamicInfo)
other._info.pDynamicState = &other._dynamicInfo;
return *this;
}
RasterizationPipelineCreateInfo& RasterizationPipelineCreateInfo::setViewport(const Range3D& viewport, const Range2Di& scissor) {
_state->viewport = VkViewport(viewport);
_state->scissor = VkRect2D(scissor);
_viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
_viewportInfo.viewportCount = 1;
_viewportInfo.pViewports = &_state->viewport;
_viewportInfo.scissorCount = 1;
_viewportInfo.pScissors = &_state->scissor;
_info.pViewportState = &_viewportInfo;
return *this;
}
RasterizationPipelineCreateInfo& RasterizationPipelineCreateInfo::setViewport(const Range3D& viewport) {
return setViewport(viewport, Range2Di{viewport.xy()});
}
RasterizationPipelineCreateInfo& RasterizationPipelineCreateInfo::setViewport(const Range2D& viewport, const Range2Di& scissor) {
return setViewport(Range3D{{viewport.min(), 0.0f}, {viewport.max(), 1.0f}}, scissor);
}
RasterizationPipelineCreateInfo& RasterizationPipelineCreateInfo::setViewport(const Range2D& viewport) {
return setViewport(viewport, Range2Di{viewport});
}
namespace {
constexpr VkDynamicState DynamicRasterizationStateMapping[]{
#define _c(value, vkValue) VK_DYNAMIC_STATE_ ## vkValue,
#include "Magnum/Vk/Implementation/dynamicRasterizationStateMapping.hpp"
#undef _c
};
}
RasterizationPipelineCreateInfo& RasterizationPipelineCreateInfo::setDynamicStates(const DynamicRasterizationStates& states) {
/* Count the number of states set, allocate for that */
std::size_t count = 0;
for(std::size_t i = 0; i != DynamicRasterizationStates::Size; ++i)
count += Math::popcount(states.data()[i]);
_state->dynamicStates = Containers::Array<VkDynamicState>{Containers::NoInit, count};
std::size_t offset = 0;
for(std::uint64_t i = 0; i != Containers::arraySize(DynamicRasterizationStateMapping); ++i)
if(states & DynamicRasterizationState(i))
_state->dynamicStates[offset++] = DynamicRasterizationStateMapping[i];
CORRADE_INTERNAL_ASSERT(offset == count);
_dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
_dynamicInfo.dynamicStateCount = count;
_dynamicInfo.pDynamicStates = _state->dynamicStates;
_info.pDynamicState = &_dynamicInfo;
return *this;
}
Pipeline Pipeline::wrap(Device& device, const VkPipeline handle, const HandleFlags flags) {
Pipeline out{NoCreate};
out._device = &device;
out._handle = handle;
out._flags = flags;
return out;
}
Pipeline::Pipeline(Device& device, const RasterizationPipelineCreateInfo& info):
_device{&device},
#ifdef CORRADE_GRACEFUL_ASSERT
/* Otherwise vkDestroyPipeline() crashes when we hit the assert */
_handle{},
#endif
_flags{HandleFlag::DestroyOnDestruction}
{
/* Doesn't check that the viewport is really a dynamic state, but should
catch most cases without false positives */
CORRADE_ASSERT(info->pViewportState || info->pRasterizationState->rasterizerDiscardEnable || info->pDynamicState,
"Vk::Pipeline: if rasterization discard is not enabled, the viewport has to be either dynamic or set via setViewport()", );
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateGraphicsPipelines(device, {}, 1, info, nullptr, &_handle));
}
Pipeline::Pipeline(NoCreateT): _device{}, _handle{} {}
Pipeline::Pipeline(Pipeline&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} {
other._handle = {};
}
Pipeline::~Pipeline() {
if(_handle && (_flags & HandleFlag::DestroyOnDestruction))
(**_device).DestroyPipeline(*_device, _handle, nullptr);
}
Pipeline& Pipeline::operator=(Pipeline&& other) noexcept {
using std::swap;
swap(other._device, _device);
swap(other._handle, _handle);
swap(other._flags, _flags);
return *this;
}
VkPipeline Pipeline::release() {
const VkPipeline handle = _handle;
_handle = {};
return handle;
}
MemoryBarrier::MemoryBarrier(const Accesses sourceAccesses, const Accesses destinationAccesses): _barrier{} {
_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
_barrier.srcAccessMask = VkAccessFlags(sourceAccesses);

105
src/Magnum/Vk/Pipeline.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Class @ref Magnum::Vk::MemoryBarrier, @ref Magnum::Vk::BufferMemoryBarrier, @ref Magnum::Vk::ImageMemoryBarrier, enum @ref Magnum::Vk::PipelineStage, @ref Magnum::Vk::Access, @ref Magnum::Vk::DependencyFlag, enum set @ref Magnum::Vk::PipelineStages, @ref Magnum::Vk::Accesses, @ref Magnum::Vk::DependencyFlags
* @brief Class @ref Magnum::Vk::Pipeline, @ref Magnum::Vk::MemoryBarrier, @ref Magnum::Vk::BufferMemoryBarrier, @ref Magnum::Vk::ImageMemoryBarrier, enum @ref Magnum::Vk::PipelineStage, @ref Magnum::Vk::Access, @ref Magnum::Vk::DependencyFlag, enum set @ref Magnum::Vk::PipelineStages, @ref Magnum::Vk::Accesses, @ref Magnum::Vk::DependencyFlags
* @m_since_latest
*/
@ -40,6 +40,109 @@
namespace Magnum { namespace Vk {
/**
@brief Pipeline
@m_since_latest
Wraps a @type_vk_keyword{Pipeline}.
@section Vk-Pipeline-creation-rasterization Rasterization pipeline creation
A @ref RasterizationPipelineCreateInfo is constructed from a @ref ShaderSet,
@ref MeshLayout, @ref PipelineLayout and a @ref RenderPass together with
subpass index and the count of color attachments. Apart from that you need to
set a viewport using @ref RasterizationPipelineCreateInfo::setViewport()
and you end up with a minimal setup needed for color-only rendering:
@snippet MagnumVk.cpp Pipeline-creation-rasterization
Certain aspects of the pipeline can be set as dynamic using
@relativeref{RasterizationPipelineCreateInfo,setDynamicStates()} --- in that
case a subset of the values passed to the constructor will be ignored. See the
particular @ref DynamicRasterizationState values for more information.
*/
class MAGNUM_VK_EXPORT Pipeline {
public:
/**
* @brief Wrap existing Vulkan handle
* @param device Vulkan device the pipeline is created on
* @param handle The @type_vk{Pipeline} handle
* @param flags Handle flags
*
* The @p handle is expected to be originating from @p device. Unlike
* a pipeline layout created using a constructor, the Vulkan pipeline
* layout is by default not deleted on destruction, use @p flags for
* different behavior.
* @see @ref release()
*/
static Pipeline wrap(Device& device, VkPipeline handle, HandleFlags flags = {});
/**
* @brief Construct a rasterization pipeline
* @param device Vulkan device to create the pipeline on
* @param info Rasterization pipeline creation info
*
* @see @fn_vk_keyword{CreateGraphicsPipelines}
*/
explicit Pipeline(Device& device, const RasterizationPipelineCreateInfo& info);
/**
* @brief Construct without creating the pipeline layout
*
* The constructed instance is equivalent to moved-from state. Useful
* in cases where you will overwrite the instance later anyway. Move
* another object over it to make it useful.
*/
explicit Pipeline(NoCreateT);
/** @brief Copying is not allowed */
Pipeline(const Pipeline&) = delete;
/** @brief Move constructor */
Pipeline(Pipeline&& other) noexcept;
/**
* @brief Destructor
*
* Destroys associated @type_vk{Pipeline} handle, unless the instance
* was created using @ref wrap() without
* @ref HandleFlag::DestroyOnDestruction specified.
* @see @fn_vk_keyword{DestroyPipeline}, @ref release()
*/
~Pipeline();
/** @brief Copying is not allowed */
Pipeline& operator=(const Pipeline&) = delete;
/** @brief Move assignment */
Pipeline& operator=(Pipeline&& other) noexcept;
/** @brief Underlying @type_vk{Pipeline} handle */
VkPipeline handle() { return _handle; }
/** @overload */
operator VkPipeline() { return _handle; }
/** @brief Handle flags */
HandleFlags handleFlags() const { return _flags; }
/**
* @brief Release the underlying Vulkan pipeline
*
* Releases ownership of the Vulkan pipeline and returns its
* handle so @fn_vk{DestroyPipeline} is not called on destruction. The
* internal state is then equivalent to moved-from state.
* @see @ref wrap()
*/
VkPipeline release();
private:
/* Can't be a reference because of the NoCreate constructor */
Device* _device;
VkPipeline _handle;
HandleFlags _flags;
};
/**
@brief Pipeline stage
@m_since_latest

2
src/Magnum/Vk/PipelineLayout.h

@ -43,7 +43,7 @@ namespace Magnum { namespace Vk {
@brief Pipeline layout
@m_since_latest
Wraps a @type_vk_keyword{PipelineLayout}.
Wraps a @type_vk_keyword{PipelineLayout}. Used in a @ref Pipeline.
*/
class MAGNUM_VK_EXPORT PipelineLayout {
public:

534
src/Magnum/Vk/RasterizationPipelineCreateInfo.h

@ -0,0 +1,534 @@
#ifndef Magnum_Vk_RasterizationPipelineCreateInfo_h
#define Magnum_Vk_RasterizationPipelineCreateInfo_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 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::RasterizationPipelineCreateInfo, enum @ref Magnum::Vk::DynamicRasterizationState, enum set @ref Magnum::Vk::DynamicRasterizationStates
* @m_since_latest
*/
#include <Corrade/Containers/BigEnumSet.h>
#include <Corrade/Containers/EnumSet.h>
#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 Dynamic rasterization state
@m_since_latest
Contains rasterization-related information from the
@type_vk_keyword{DynamicState} enum but with contiguos numbering to make it
usable as a set of @ref DynamicRasterizationStates.
@see @ref RasterizationPipelineCreateInfo::setDynamicStates()
*/
enum class DynamicRasterizationState: UnsignedByte {
/**
* Viewport range set in
* @ref RasterizationPipelineCreateInfo::setViewport() is ignored and is
* expected to be set dynamically using @fn_vk{CmdSetViewport}. Viewport
* count is still set in @ref RasterizationPipelineCreateInfo, see
* @ref DynamicRasterizationState::ViewportWithCount for having both
* dynamic.
* @m_keywords{VK_DYNAMIC_STATE_VIEWPORT}
* @todoc link the multi-view API instead when exposed
*/
Viewport,
/**
* Scissor rectangle set in
* @ref RasterizationPipelineCreateInfo::setViewport() is ignored and is
* expected to be set dynamically using @fn_vk{CmdSetScissor}. Scissor
* count is still set in @ref RasterizationPipelineCreateInfo, see
* @ref DynamicRasterizationState::ScissorWithCount for having both
* dynamic.
* @m_keywords{VK_DYNAMIC_STATE_SCISSOR}
* @todoc link the multi-view API instead when exposed
*/
Scissor,
/**
* Line width set in @ref RasterizationPipelineCreateInfo is ignored and is
* expected to be set dynamically using @fn_vk{CmdSetLineWidth}.
* @requires_vk_feature @ref DeviceFeature::WideLines
* @m_keywords{VK_DYNAMIC_STATE_LINE_WIDTH}
* @todoc link to the actual API when exposed
*/
LineWidth,
/**
* Depth bias constant factor, depth bias clamp and depth bias slope factor
* set in @ref RasterizationPipelineCreateInfo are ignored and expected to
* be set dynamically using @fn_vk{CmdSetDepthBias}.
* @m_keywords{VK_DYNAMIC_STATE_DEPTH_BIAS}
* @todoc link to the actual API when exposed
*/
DepthBias,
/**
* Blend constants set in @ref RasterizationPipelineCreateInfo are ignored
* and expected to be set dynamically using @fn_vk{CmdSetBlendConstants}.
* @m_keywords{VK_DYNAMIC_STATE_BLEND_CONSTANTS}
* @todoc link to the actual API when exposed
*/
BlendConstants,
/**
* Min and max depth bounds set in @ref RasterizationPipelineCreateInfo are
* ignored and expected to be set dynamically using
* @fn_vk{CmdSetDepthBounds}.
* @see @ref DynamicRasterizationState::DepthBoundsTestEnable
* @requires_vk_feature @ref DeviceFeature::DepthBounds
* @m_keywords{VK_DYNAMIC_STATE_DEPTH_BOUNDS}
* @todoc link to the actual API when exposed
*/
DepthBounds,
/**
* Stencil compare mask set in @ref RasterizationPipelineCreateInfo is
* ignored and expected to be set dynamically using
* @fn_vk{CmdSetStencilCompareMask}.
* @m_keywords{VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK}
* @todoc link to the actual API when exposed
*/
StencilCompareMask,
/**
* Stencil write mask set in @ref RasterizationPipelineCreateInfo is
* ignored and expected to be set dynamically using
* @fn_vk{CmdSetStencilWriteMask}.
* @m_keywords{VK_DYNAMIC_STATE_STENCIL_WRITE_MASK}
* @todoc link to the actual API when exposed
*/
StencilWriteMask,
/**
* Stencil reference set in @ref RasterizationPipelineCreateInfo is ignored
* and expected to be set dynamically using @fn_vk{CmdSetStencilReference}.
* @m_keywords{VK_DYNAMIC_STATE_STENCIL_REFERENCE}
* @todoc link to the actual API when exposed
*/
StencilReference,
/**
* Cull mode set in @ref RasterizationPipelineCreateInfo is ignored and
* expected to be set dynamically using @fn_vk{CmdSetCullModeEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_CULL_MODE_EXT}
* @todoc link to the actual API when exposed
*/
CullMode,
/**
* Front face set in @ref RasterizationPipelineCreateInfo is ignored and
* expected to be set dynamically using @fn_vk{CmdSetFrontFaceEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_FRONT_FACE_EXT}
* @todoc link to the actual API when exposed
*/
FrontFace,
/**
* Only the @ref MeshPrimitive topology class set in @ref MeshLayout and
* passed to @ref RasterizationPipelineCreateInfo is used and the specific
* topology order and adjacency is expected to be set dynamically using
* @fn_vk{CmdSetPrimitiveTopologyEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT}
*/
PrimitiveTopology,
/**
* Both the number of viewports and their ranges set in
* @ref RasterizationPipelineCreateInfo::setViewport() are ignored and
* expected to be set dynamically using @fn_vk{CmdSetViewportWithCountEXT}.
* A superset of @ref DynamicRasterizationState::Viewport.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT}
* @todoc link the multi-view API instead when exposed
*/
ViewportWithCount,
/**
* Both the number of scissors and their rectangles set in
* @ref RasterizationPipelineCreateInfo::setViewport() are ignored and
* expected to be set dynamically using @fn_vk{CmdSetScissorWithCountEXT}.
* A superset of @ref DynamicRasterizationState::Scissor.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT}
* @todoc link the multi-view API instead when exposed
*/
ScissorWithCount,
/**
* Stride set in @ref MeshLayout::addBinding() and passed to
* @ref RasterizationPipelineCreateInfo is ignored and expected to be set
* dynamically using @fn_vk{CmdBindVertexBuffers2EXT}
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT}
* @todoc link to the actual API when exposed
*/
VertexInputBindingStride,
/**
* Depth test enablement in @ref RasterizationPipelineCreateInfo is ignored
* and expected to be set dynamically using @fn_vk{CmdSetDepthTestEnableEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT}
* @todoc link to the actual API when exposed
*/
DepthTestEnable,
/**
* Depth write enablement in @ref RasterizationPipelineCreateInfo is
* ignored and expected to be set dynamically using
* @fn_vk{CmdSetDepthWriteEnableEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT}
* @todoc link to the actual API when exposed
*/
DepthWriteEnable,
/**
* Depth compare operation in @ref RasterizationPipelineCreateInfo is
* ignored and expected to be set dynamically using
* @fn_vk{CmdSetDepthCompareOpEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT}
* @todoc link to the actual API when exposed
*/
DepthCompareOperation,
/**
* Depth bounds test enablement in @ref RasterizationPipelineCreateInfo is
* ignored and expected to be set dynamically using
* @fn_vk{CmdSetDepthBoundsTestEnableEXT}.
* @requires_vk_feature @ref DeviceFeature::DepthBounds and
* @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT}
* @todoc link to the actual API when exposed
*/
DepthBoundsTestEnable,
/**
* Stencil test enablement in @ref RasterizationPipelineCreateInfo is
* ignored and expected to be set dynamically using
* @fn_vk{CmdSetStencilTestEnableEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT}
* @todoc link to the actual API when exposed
*/
StencilTestEnable,
/**
* Stencil operation in @ref RasterizationPipelineCreateInfo is ignored and
* expected to be set dynamically using @fn_vk{CmdSetStencilOpEXT}.
* @requires_vk_feature @ref DeviceFeature::ExtendedDynamicState
* @m_keywords{VK_DYNAMIC_STATE_STENCIL_OP_EXT}
* @todoc link to the actual API when exposed
*/
StencilOperation,
/** @todo RayTracingPipelineStackSize, or should that go into a dedicated
enum for RT pipeline? */
};
/**
@brief Dynamic rasterization states
@m_since_latest
A set of rasterization-related information from the
@type_vk_keyword{DynamicState} enum.
@see @ref RasterizationPipelineCreateInfo::setDynamicStates()
*/
typedef Containers::BigEnumSet<DynamicRasterizationState, 1> DynamicRasterizationStates;
CORRADE_ENUMSET_OPERATORS(DynamicRasterizationStates)
/**
@brief Rasterization pipeline creation info
@m_since_latest
@m_keywords{GraphicsPipelineCreateInfo}
Wraps a @type_vk_keyword{GraphicsPipelineCreateInfo}, along with
- @type_vk_keyword{PipelineViewportStateCreateInfo},
- @type_vk_keyword{PipelineRasterizationStateCreateInfo},
- @type_vk_keyword{PipelineMultisampleStateCreateInfo},
- @type_vk_keyword{PipelineDepthStencilStateCreateInfo},
- @type_vk_keyword{PipelineColorBlendStateCreateInfo} containing
@type_vk_keyword{PipelineColorBlendAttachmentState} and
- @type_vk_keyword{PipelineDynamicStateCreateInfo}.
See @ref Vk-Pipeline-creation-rasterization "Rasterization pipeline creation"
for usage information.
*/
class MAGNUM_VK_EXPORT RasterizationPipelineCreateInfo {
public:
/**
* @brief Rasterization pipeline creation flag
*
* Wraps the rasterization-related subset of
* @type_vk_keyword{PipelineCreateFlagBits}.
* @see @ref Flags, @ref RasterizationPipelineCreateInfo(const ShaderSet&, const MeshLayout&, VkPipelineLayout, VkRenderPass, UnsignedInt, UnsignedInt, Flags)
* @m_enum_values_as_keywords
*/
enum class Flag: UnsignedInt {
/**
* Create the pipeline without optimization.
*
* @m_class{m-note m-success}
*
* @par
* Setting this flag on single-use pipelines might help
* drivers pick a better tradeoff between CPU time spent
* optimizing the pipeline and GPU time spent executing it.
*/
DisableOptimization = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,
/**
* Allow derivatives to be subsequently created from this pipeline.
*/
AllowDerivatives = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT,
/** Derivative of a pipeline created earlier. */
Derivative = VK_PIPELINE_CREATE_DERIVATIVE_BIT
};
/**
* @brief Rasterization pipeline creation flags
*
* Type-safe wrapper for the rasterization-related subset of
* @type_vk_keyword{PipelineCreateFlags}.
* @see @ref RasterizationPipelineCreateInfo(const ShaderSet&, const MeshLayout&, VkPipelineLayout, VkRenderPass, UnsignedInt, UnsignedInt, Flags)
*/
typedef Containers::EnumSet<Flag> Flags;
/**
* @brief Constructor
* @param shaderSet Set of shaders to use for this pipeline
* @param meshLayout Mesh layout to use in this pipeline
* @param pipelineLayout A @ref PipelineLayout or a raw Vulkan
* pipeline layout handle
* @param renderPass A @ref RenderPass or a raw Vulkan render
* pass handle
* @param subpass Subpass index
* @param subpassColorAttachmentCount Number of color attachments the
* @p subpass uses
* @param flags Rasterization pipeline creation flags
*
* Note that the @p shaderSet and @p meshLayout structure internals are
* referenced, not copied, and thus have to stay in scope until the
* @ref Pipeline object is created.
*
* The following @type_vk{GraphicsPipelineCreateInfo} and substructure
* fields are pre-filled in addition to `sType` of all referenced
* structures, everything else is zero-filled:
*
* - `flags`
* - `stageCount` and `pStages` to @p shaderSet
* - `pVertexInputState` and `pInputAssemblyState` to @p meshLayout
* - `pRasterizationState`
* - @cpp pRasterizationState->polygonMode @ce to
* @val_vk{POLYGON_MODE_FILL,PolygonMode}
* - @cpp pRasterizationState->frontFace @ce to
* @val_vk{FRONT_FACE_COUNTER_CLOCKWISE,FrontFace}
* - @cpp pRasterizationState->lineWidth @ce to @cpp 1.0f @ce
* - `pMultisampleState`
* - @cpp pMultisampleState->rasterizationSamples @ce to
* @val_vk{SAMPLE_COUNT_1_BIT,SampleCountFlagBits}
* - `pDepthStencilState`
* - `pColorBlendState`
* - @cpp pColorBlendState->attachmentCount @ce to
* @p subpassColorAttachmentCount
* - @cpp pColorBlendState->pAttachments @ce <b></b>
* - @cpp pColorBlendState->pAttachments[i].colorWriteMask @ce to
* @val_vk{COLOR_COMPONENT_R_BIT,ColorComponentFlagBits},
* @val_vk{COLOR_COMPONENT_G_BIT,ColorComponentFlagBits},
* @val_vk{COLOR_COMPONENT_B_BIT,ColorComponentFlagBits} and
* @val_vk{COLOR_COMPONENT_A_BIT,ColorComponentFlagBits}
* - `layout` to @p pipelineLayout
* - `renderPass`
* - `subpass`
*
* You need to call at least @ref setViewport() or specifying
* @ref DynamicRasterizationState::Viewport in
* @ref setDynamicStates() for a valid setup.
*/
explicit RasterizationPipelineCreateInfo(const ShaderSet& shaderSet, const MeshLayout& meshLayout, VkPipelineLayout pipelineLayout, VkRenderPass renderPass, UnsignedInt subpass, UnsignedInt subpassColorAttachmentCount, Flags flags = {});
/**
* @brief Construct without initializing the contents
*
* Note that not even the `sType` field nor the nested structure
* pointers are set --- the structure has to be fully initialized
* afterwards in order to be usable.
*/
explicit RasterizationPipelineCreateInfo(NoInitT) noexcept;
/**
* @brief Construct from existing data
*
* Copies the existing values *including* the pointed-to
*
* - @type_vk{PipelineViewportStateCreateInfo},
* - @type_vk{PipelineRasterizationStateCreateInfo},
* - @type_vk{PipelineMultisampleStateCreateInfo},
* - @type_vk{PipelineDepthStencilStateCreateInfo},
* - @type_vk{PipelineColorBlendStateCreateInfo} and
* - @type_vk{PipelineDynamicStateCreateInfo}
*
* @m_class{m-noindent}
*
* structures verbatim, remaining pointers are kept unchanged without
* taking over the ownership. Modifying the newly created instance will
* not modify the original data nor the pointed-to data.
*/
explicit RasterizationPipelineCreateInfo(const VkGraphicsPipelineCreateInfo& info);
/** @brief Copying is not allowed */
RasterizationPipelineCreateInfo(const RasterizationPipelineCreateInfo&) = delete;
/** @brief Move constructor */
RasterizationPipelineCreateInfo(RasterizationPipelineCreateInfo&& other) noexcept;
~RasterizationPipelineCreateInfo();
/** @brief Copying is not allowed */
RasterizationPipelineCreateInfo& operator=(const RasterizationPipelineCreateInfo&) = delete;
/** @brief Move assignment */
RasterizationPipelineCreateInfo& operator=(RasterizationPipelineCreateInfo&& other) noexcept;
/**
* @brief Set viewport and scissor rectangle
* @param viewport Viewport rectangle and depth range
* @param scissor Scissor rectangle
* @return Reference to self (for method chaining)
*
* While the @p scissor rectangle is full pixels, the @p viewport XY
* range can have sub-pixel precision. The depth should be in range
* @f$ [0.0, 1.0] @f$.
*
* The following @type_vk{GraphicsPipelineCreateInfo} and substructure
* fields are modified, in addition to `sType` of newly referenced
* structures:
*
* - `pViewportState`
* - @cpp pViewportState->viewportCount @ce to @cpp 1 @ce
* - @cpp pViewportState->pViewports[0] @ce to @p viewport
* - @cpp pViewportState->scissorCount @ce to @cpp 1 @ce
* - @cpp pViewportState->pScissors[0] @ce to @p scissor
*
* @see @ref setViewport(const Range3D&)
*
* @requires_vk11 With the @vk_extension{KHR,maintenance1} extension
* it's possible to switch the origin from top left and Y down to
* bottom left and Y up (matching OpenGL) by supplying negative
* height and an adjusted Y offset
*/
RasterizationPipelineCreateInfo& setViewport(const Range3D& viewport, const Range2Di& scissor);
/**
* @brief Set viewport with an implicit scissor rectangle
*
* Equivalent to calling @ref setViewport(const Range3D&, const Range2Di&)
* with @p scissor set to the @ref Range3D::xy() part of @p viewport.
*/
RasterizationPipelineCreateInfo& setViewport(const Range3D& viewport);
/**
* @brief Set viewport with an implicit depth range
*
* Equivalent to calling @ref setViewport(const Range3D&, const Range2Di&)
* with depth from @cpp 0.0f @ce to @cpp 1.0f @ce.
*/
RasterizationPipelineCreateInfo& setViewport(const Range2D& viewport, const Range2Di& scissor);
/**
* @brief Set viewport with an implicit depth range and scissor rectangle
*
* Equivalent to calling @ref setViewport(const Range3D&, const Range2Di&)
* with depth from @cpp 0.0f @ce to @cpp 1.0f @ce and @p scissor same
* as @p viewport.
*/
RasterizationPipelineCreateInfo& setViewport(const Range2D& viewport);
/**
* @brief Set dynamic states
*
* The following @type_vk{GraphicsPipelineCreateInfo} and substructure
* fields are modified, in addition to `sType` of newly referenced
* structures:
*
* - `pDynamicState`
* - @cpp pDynamicState->dynamicStateCount @ce to count of values
* enabled in @p states
* - @cpp pDynamicState->pDynamicStates @ce to a list of
* @type_vk{DynamicState} corresponding to
* @ref DynamicRasterizationState values enabled in @p states
*/
RasterizationPipelineCreateInfo& setDynamicStates(const DynamicRasterizationStates& states);
/** @brief Underlying @type_vk{GraphicsPipelineCreateInfo} structure */
VkGraphicsPipelineCreateInfo& operator*() { return _info; }
/** @overload */
const VkGraphicsPipelineCreateInfo& operator*() const { return _info; }
/** @overload */
VkGraphicsPipelineCreateInfo* operator->() { return &_info; }
/** @overload */
const VkGraphicsPipelineCreateInfo* operator->() const { return &_info; }
/** @overload */
operator const VkGraphicsPipelineCreateInfo*() const { return &_info; }
private:
VkGraphicsPipelineCreateInfo _info;
VkPipelineViewportStateCreateInfo _viewportInfo;
VkPipelineRasterizationStateCreateInfo _rasterizationInfo;
VkPipelineMultisampleStateCreateInfo _multisampleInfo;
VkPipelineDepthStencilStateCreateInfo _depthStencilInfo;
VkPipelineColorBlendStateCreateInfo _colorBlendInfo;
VkPipelineDynamicStateCreateInfo _dynamicInfo;
struct State;
Containers::Pointer<State> _state;
};
CORRADE_ENUMSET_OPERATORS(RasterizationPipelineCreateInfo::Flags)
}}
/* Make the definition complete -- it doesn't make sense to have a CreateInfo
without the corresponding object anyway. */
#include "Magnum/Vk/Pipeline.h"
#endif

5
src/Magnum/Vk/Test/CMakeLists.txt

@ -176,7 +176,10 @@ if(BUILD_VK_TESTS)
corrade_add_test(VkImageViewVkTest ImageViewVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkInstanceVkTest InstanceVkTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkMemoryVkTest MemoryVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkPipelineVkTest PipelineVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkPipelineVkTest PipelineVkTest.cpp
LIBRARIES MagnumVkTestLib MagnumVulkanTester
FILES triangle-shaders.spv)
target_include_directories(VkPipelineVkTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
corrade_add_test(VkPipelineLayoutVkTest PipelineLayoutVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkQueueVkTest QueueVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkRenderPassVkTest RenderPassVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)

462
src/Magnum/Vk/Test/PipelineTest.cpp

@ -24,18 +24,42 @@
*/
#include <new>
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Math/Range.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Image.h"
#include "Magnum/Vk/MeshLayout.h"
#include "Magnum/Vk/Pipeline.h"
#include "Magnum/Vk/PixelFormat.h"
#include "Magnum/Vk/RasterizationPipelineCreateInfo.h"
#include "Magnum/Vk/ShaderSet.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct PipelineTest: TestSuite::Tester {
explicit PipelineTest();
void dynamicRasterizationStateMapping();
void rasterizationCreateInfoConstruct();
void rasterizationCreateInfoConstructNoInit();
void rasterizationCreateInfoConstructFromVk();
void rasterizationCreateInfoConstructCopy();
void rasterizationCreateInfoConstructMove();
void rasterizationCreateInfoConstructMoveExternalPointers();
void rasterizationCreateInfoViewportScissor();
void rasterizationCreateInfoViewport2DScissor();
void rasterizationCreateInfoViewportImplicitScissor();
void rasterizationCreateInfoViewport2DImplicitScissor();
void rasterizationCreateInfoDynamicState();
void constructNoCreate();
void constructCopy();
void memoryBarrierConstruct();
void memoryBarrierConstructNoInit();
void memoryBarrierConstructFromVk();
@ -51,7 +75,25 @@ struct PipelineTest: TestSuite::Tester {
};
PipelineTest::PipelineTest() {
addTests({&PipelineTest::memoryBarrierConstruct,
addTests({&PipelineTest::dynamicRasterizationStateMapping,
&PipelineTest::rasterizationCreateInfoConstruct,
&PipelineTest::rasterizationCreateInfoConstructNoInit,
&PipelineTest::rasterizationCreateInfoConstructFromVk,
&PipelineTest::rasterizationCreateInfoConstructCopy,
&PipelineTest::rasterizationCreateInfoConstructMove,
&PipelineTest::rasterizationCreateInfoConstructMoveExternalPointers,
&PipelineTest::rasterizationCreateInfoViewportScissor,
&PipelineTest::rasterizationCreateInfoViewport2DScissor,
&PipelineTest::rasterizationCreateInfoViewportImplicitScissor,
&PipelineTest::rasterizationCreateInfoViewport2DImplicitScissor,
&PipelineTest::rasterizationCreateInfoDynamicState,
&PipelineTest::constructNoCreate,
&PipelineTest::constructCopy,
&PipelineTest::memoryBarrierConstruct,
&PipelineTest::memoryBarrierConstructNoInit,
&PipelineTest::memoryBarrierConstructFromVk,
@ -65,6 +107,424 @@ PipelineTest::PipelineTest() {
&PipelineTest::imageMemoryBarrierConstructFromVk});
}
void PipelineTest::dynamicRasterizationStateMapping() {
/* Same table is in Pipeline.cpp, here just to have something to test the
order with -- without this, correct order can't be verified */
constexpr VkDynamicState mapping[]{
#define _c(state, vkState) VK_DYNAMIC_STATE_ ## vkState,
#include "Magnum/Vk/Implementation/dynamicRasterizationStateMapping.hpp"
#undef _c
};
/* This goes through all 8 bits of the enum range */
UnsignedInt firstUnhandled = 0xff;
UnsignedInt nextHandled = 0;
for(UnsignedInt i = 0; i <= 0xff; ++i) {
const auto state = DynamicRasterizationState(i);
/* Each case verifies:
- that the entries are ordered by number by comparing a function to
expected result (so insertion here is done in proper place)
- that there was no gap (unhandled value inside the range) */
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wswitch"
#endif
switch(state) {
#define _c(state, vkState) \
case DynamicRasterizationState::state: { \
CORRADE_ITERATION(#state); \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xff); \
CORRADE_COMPARE(mapping[i], VK_DYNAMIC_STATE_ ## vkState); \
++nextHandled; \
continue; \
}
#include "Magnum/Vk/Implementation/dynamicRasterizationStateMapping.hpp"
#undef _c
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/* Not handled by any value, remember -- we might either be at the end
of the enum range (which is okay) or some value might be unhandled
here */
firstUnhandled = i;
}
CORRADE_COMPARE(firstUnhandled, 0xff);
}
void PipelineTest::rasterizationCreateInfoConstruct() {
ShaderSet shaderSet;
shaderSet
.addShader({}, {}, {})
.addShader({}, {}, {});
MeshLayout meshLayout{MeshPrimitive::Triangles};
RasterizationPipelineCreateInfo info{shaderSet, meshLayout, reinterpret_cast<VkPipelineLayout>(0xdead), reinterpret_cast<VkRenderPass>(0xbeef), 15, 3, RasterizationPipelineCreateInfo::Flag::DisableOptimization|RasterizationPipelineCreateInfo::Flag::AllowDerivatives};
CORRADE_COMPARE(info->flags, VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT|VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT);
CORRADE_COMPARE(info->stageCount, 2);
CORRADE_COMPARE(info->pStages, shaderSet.stages());
CORRADE_COMPARE(info->pVertexInputState, &meshLayout.vkPipelineVertexInputStateCreateInfo());
CORRADE_COMPARE(info->pInputAssemblyState, &meshLayout.vkPipelineInputAssemblyStateCreateInfo());
CORRADE_VERIFY(!info->pViewportState);
CORRADE_VERIFY(info->pRasterizationState);
/* Not testing the default-filled pRasterizationState properties, feels as
excessive as verifying sType would */
CORRADE_VERIFY(info->pMultisampleState);
/* Not testing the default-filled pMultisampleState nested properties,
feels as excessive as verifying sType would */
CORRADE_VERIFY(info->pDepthStencilState);
/* Not testing the default-filled pDepthStencilState nested properties,
feels as excessive as verifying sType would */
CORRADE_VERIFY(info->pColorBlendState);
CORRADE_COMPARE(info->pColorBlendState->attachmentCount, 3);
CORRADE_VERIFY(info->pColorBlendState->pAttachments);
for(std::size_t i = 0; i != 3; ++i) {
CORRADE_ITERATION(i);
CORRADE_COMPARE(info->pColorBlendState->pAttachments[i].colorWriteMask, VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT);
}
CORRADE_VERIFY(!info->pDynamicState);
CORRADE_COMPARE(info->layout, reinterpret_cast<VkPipelineLayout>(0xdead));
CORRADE_COMPARE(info->renderPass, reinterpret_cast<VkRenderPass>(0xbeef));
CORRADE_COMPARE(info->subpass, 15);
}
void PipelineTest::rasterizationCreateInfoConstructNoInit() {
RasterizationPipelineCreateInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) RasterizationPipelineCreateInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<RasterizationPipelineCreateInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, RasterizationPipelineCreateInfo>::value));
}
void PipelineTest::rasterizationCreateInfoConstructFromVk() {
/* These keep referenced */
int next{};
VkPipelineShaderStageCreateInfo shaderSet{};
VkPipelineVertexInputStateCreateInfo vertexInput{};
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
VkPipelineTessellationStateCreateInfo tessellation{};
/* These get copied. Use deliberately wrong sType fields to check the
contents are copied verbatim. */
VkPipelineViewportStateCreateInfo viewport{};
viewport.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
VkPipelineRasterizationStateCreateInfo rasterization{};
rasterization.sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR;
VkPipelineMultisampleStateCreateInfo multisample{};
multisample.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
VkPipelineColorBlendStateCreateInfo colorBlend{};
colorBlend.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
VkPipelineDynamicStateCreateInfo dynamic{};
dynamic.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
VkGraphicsPipelineCreateInfo vkInfo{};
vkInfo.sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO;
vkInfo.pNext = &next;
vkInfo.pStages = &shaderSet;
vkInfo.pVertexInputState = &vertexInput;
vkInfo.pInputAssemblyState = &inputAssembly;
vkInfo.pTessellationState = &tessellation;
vkInfo.pViewportState = &viewport;
vkInfo.pRasterizationState = &rasterization;
vkInfo.pMultisampleState = &multisample;
vkInfo.pDepthStencilState = &depthStencil;
vkInfo.pColorBlendState = &colorBlend;
vkInfo.pDynamicState = &dynamic;
RasterizationPipelineCreateInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO);
CORRADE_COMPARE(info->pNext, &next);
CORRADE_COMPARE(info->pStages, &shaderSet);
CORRADE_COMPARE(info->pVertexInputState, &vertexInput);
CORRADE_COMPARE(info->pInputAssemblyState, &inputAssembly);
CORRADE_COMPARE(info->pTessellationState, &tessellation);
CORRADE_VERIFY(info->pViewportState);
CORRADE_VERIFY(info->pViewportState != &viewport);
CORRADE_COMPARE(info->pViewportState->sType, VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2);
CORRADE_VERIFY(info->pRasterizationState);
CORRADE_VERIFY(info->pRasterizationState != &rasterization);
CORRADE_COMPARE(info->pRasterizationState->sType, VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR);
CORRADE_VERIFY(info->pMultisampleState);
CORRADE_VERIFY(info->pMultisampleState != &multisample);
CORRADE_COMPARE(info->pMultisampleState->sType, VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2);
CORRADE_VERIFY(info->pDepthStencilState);
CORRADE_VERIFY(info->pDepthStencilState != &depthStencil);
CORRADE_COMPARE(info->pDepthStencilState->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY(info->pColorBlendState);
CORRADE_VERIFY(info->pColorBlendState != &colorBlend);
CORRADE_COMPARE(info->pColorBlendState->sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES);
CORRADE_VERIFY(info->pDynamicState);
CORRADE_VERIFY(info->pDynamicState != &dynamic);
CORRADE_COMPARE(info->pDynamicState->sType, VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT);
}
void PipelineTest::rasterizationCreateInfoConstructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<RasterizationPipelineCreateInfo>{});
CORRADE_VERIFY(!std::is_copy_assignable<RasterizationPipelineCreateInfo>{});
}
void PipelineTest::rasterizationCreateInfoConstructMove() {
ShaderSet shaderSet;
shaderSet
.addShader({}, {}, {})
.addShader({}, {}, {});
MeshLayout meshLayout{MeshPrimitive::Triangles};
Containers::Pointer<RasterizationPipelineCreateInfo> a{Containers::InPlaceInit, shaderSet, meshLayout, VkPipelineLayout{}, VkRenderPass{}, 0u, 3u};
(*a).setViewport(Range3D{})
.setDynamicStates(DynamicRasterizationState::CullMode);
Containers::Pointer<RasterizationPipelineCreateInfo> b{Containers::InPlaceInit, std::move(*a)};
CORRADE_COMPARE((**a).stageCount, 0);
CORRADE_VERIFY(!(**a).pStages);
CORRADE_VERIFY(!(**a).pVertexInputState);
CORRADE_VERIFY(!(**a).pInputAssemblyState);
CORRADE_VERIFY(!(**a).pViewportState);
CORRADE_VERIFY(!(**a).pRasterizationState);
CORRADE_VERIFY(!(**a).pMultisampleState);
CORRADE_VERIFY(!(**a).pDepthStencilState);
CORRADE_VERIFY(!(**a).pColorBlendState);
CORRADE_VERIFY(!(**a).pDynamicState);
/* Clear the original instance to verify we don't reference any of its
members */
a.reset();
CORRADE_COMPARE((**b).stageCount, 2);
CORRADE_COMPARE((**b).pStages, shaderSet.stages());
CORRADE_COMPARE((**b).pVertexInputState, &meshLayout.vkPipelineVertexInputStateCreateInfo());
CORRADE_COMPARE((**b).pInputAssemblyState, &meshLayout.vkPipelineInputAssemblyStateCreateInfo());
CORRADE_VERIFY((**b).pViewportState);
CORRADE_COMPARE((**b).pViewportState->sType, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO);
CORRADE_VERIFY((**b).pRasterizationState);
CORRADE_COMPARE((**b).pRasterizationState->sType, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO);
CORRADE_VERIFY((**b).pMultisampleState);
CORRADE_COMPARE((**b).pMultisampleState->sType, VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO);
CORRADE_VERIFY((**b).pDepthStencilState);
CORRADE_COMPARE((**b).pDepthStencilState->sType, VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO);
CORRADE_VERIFY((**b).pColorBlendState);
CORRADE_COMPARE((**b).pColorBlendState->sType, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO);
CORRADE_COMPARE((**b).pColorBlendState->attachmentCount, 3);
CORRADE_COMPARE((**b).pColorBlendState->pAttachments[2].colorWriteMask, VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT);
CORRADE_VERIFY((**b).pDynamicState);
CORRADE_COMPARE((**b).pDynamicState->sType, VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO);
Containers::Pointer<RasterizationPipelineCreateInfo> c{Containers::InPlaceInit, VkGraphicsPipelineCreateInfo{}};
*c = std::move(*b);
CORRADE_COMPARE((**b).stageCount, 0);
CORRADE_VERIFY(!(**b).pStages);
CORRADE_VERIFY(!(**b).pVertexInputState);
CORRADE_VERIFY(!(**b).pInputAssemblyState);
CORRADE_VERIFY(!(**b).pViewportState);
CORRADE_VERIFY(!(**b).pRasterizationState);
CORRADE_VERIFY(!(**b).pMultisampleState);
CORRADE_VERIFY(!(**b).pDepthStencilState);
CORRADE_VERIFY(!(**b).pColorBlendState);
CORRADE_VERIFY(!(**b).pDynamicState);
/* Clear the original instance to verify we don't reference any of its
members */
b.reset();
CORRADE_COMPARE((**c).stageCount, 2);
CORRADE_COMPARE((**c).pStages, shaderSet.stages());
CORRADE_COMPARE((**c).pVertexInputState, &meshLayout.vkPipelineVertexInputStateCreateInfo());
CORRADE_COMPARE((**c).pInputAssemblyState, &meshLayout.vkPipelineInputAssemblyStateCreateInfo());
CORRADE_VERIFY((**c).pViewportState);
CORRADE_COMPARE((**c).pViewportState->sType, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO);
CORRADE_VERIFY((**c).pRasterizationState);
CORRADE_COMPARE((**c).pRasterizationState->sType, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO);
CORRADE_VERIFY((**c).pMultisampleState);
CORRADE_COMPARE((**c).pMultisampleState->sType, VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO);
CORRADE_VERIFY((**c).pDepthStencilState);
CORRADE_COMPARE((**c).pDepthStencilState->sType, VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO);
CORRADE_VERIFY((**c).pColorBlendState);
CORRADE_COMPARE((**c).pColorBlendState->sType, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO);
CORRADE_COMPARE((**c).pColorBlendState->attachmentCount, 3);
CORRADE_COMPARE((**c).pColorBlendState->pAttachments[2].colorWriteMask, VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT);
CORRADE_VERIFY((**c).pDynamicState);
CORRADE_COMPARE((**c).pDynamicState->sType, VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO);
CORRADE_VERIFY(std::is_nothrow_move_constructible<RasterizationPipelineCreateInfo>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<RasterizationPipelineCreateInfo>::value);
}
void PipelineTest::rasterizationCreateInfoConstructMoveExternalPointers() {
VkPipelineViewportStateCreateInfo viewport{};
VkPipelineRasterizationStateCreateInfo rasterization{};
VkPipelineMultisampleStateCreateInfo multisample{};
VkPipelineDepthStencilStateCreateInfo depthStencil{};
VkPipelineColorBlendStateCreateInfo colorBlend{};
VkPipelineDynamicStateCreateInfo dynamic{};
ShaderSet shaderSet;
shaderSet
.addShader({}, {}, {})
.addShader({}, {}, {});
MeshLayout meshLayout{MeshPrimitive::Triangles};
/* Reroute the substructure pointers to external data */
RasterizationPipelineCreateInfo a{shaderSet, meshLayout, {}, {}, 0, 0};
a->pViewportState = &viewport;
a->pRasterizationState = &rasterization;
a->pMultisampleState = &multisample;
a->pDepthStencilState = &depthStencil;
a->pColorBlendState = &colorBlend;
a->pDynamicState = &dynamic;
/* The external pointers should stay external, not rerouted to internal */
RasterizationPipelineCreateInfo b = std::move(a);
CORRADE_COMPARE(b->pViewportState, &viewport);
CORRADE_COMPARE(b->pRasterizationState, &rasterization);
CORRADE_COMPARE(b->pMultisampleState, &multisample);
CORRADE_COMPARE(b->pDepthStencilState, &depthStencil);
CORRADE_COMPARE(b->pColorBlendState, &colorBlend);
CORRADE_COMPARE(b->pDynamicState, &dynamic);
RasterizationPipelineCreateInfo c{VkGraphicsPipelineCreateInfo{}};
c = std::move(b);
CORRADE_COMPARE(c->pViewportState, &viewport);
CORRADE_COMPARE(c->pRasterizationState, &rasterization);
CORRADE_COMPARE(c->pMultisampleState, &multisample);
CORRADE_COMPARE(c->pDepthStencilState, &depthStencil);
CORRADE_COMPARE(c->pColorBlendState, &colorBlend);
CORRADE_COMPARE(c->pDynamicState, &dynamic);
}
void PipelineTest::rasterizationCreateInfoViewportScissor() {
ShaderSet shaderSet;
MeshLayout meshLayout{MeshPrimitive::Triangles};
RasterizationPipelineCreateInfo info{shaderSet, meshLayout, {}, {}, 0, 1};
info.setViewport({{1.5f, 3.5f, 5.5f}, {8, 12, 14}}, {{15, 34}, {84, 72}});
CORRADE_VERIFY(info->pViewportState);
CORRADE_COMPARE(info->pViewportState->viewportCount, 1);
CORRADE_VERIFY(info->pViewportState->pViewports);
CORRADE_COMPARE(info->pViewportState->pViewports[0].x, 1.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].y, 3.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].minDepth, 5.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].width, 6.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].height, 8.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].maxDepth, 14.0f);
CORRADE_COMPARE(info->pViewportState->scissorCount, 1);
CORRADE_VERIFY(info->pViewportState->pScissors);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.x, 15);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.y, 34);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.width, 69);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.height, 38);
}
void PipelineTest::rasterizationCreateInfoViewport2DScissor() {
ShaderSet shaderSet;
MeshLayout meshLayout{MeshPrimitive::Triangles};
RasterizationPipelineCreateInfo info{shaderSet, meshLayout, {}, {}, 0, 1};
info.setViewport({{1.5f, 3.5f}, {8, 12}}, {{15, 34}, {84, 72}});
CORRADE_VERIFY(info->pViewportState);
CORRADE_COMPARE(info->pViewportState->viewportCount, 1);
CORRADE_VERIFY(info->pViewportState->pViewports);
CORRADE_COMPARE(info->pViewportState->pViewports[0].x, 1.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].y, 3.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].minDepth, 0.0f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].width, 6.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].height, 8.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].maxDepth, 1.0f);
CORRADE_COMPARE(info->pViewportState->scissorCount, 1);
CORRADE_VERIFY(info->pViewportState->pScissors);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.x, 15);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.y, 34);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.width, 69);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.height, 38);
}
void PipelineTest::rasterizationCreateInfoViewportImplicitScissor() {
ShaderSet shaderSet;
MeshLayout meshLayout{MeshPrimitive::Triangles};
RasterizationPipelineCreateInfo info{shaderSet, meshLayout, {}, {}, 0, 1};
info.setViewport({{1.5f, 3.5f, 5.5f}, {8, 12, 14}});
CORRADE_VERIFY(info->pViewportState);
CORRADE_COMPARE(info->pViewportState->viewportCount, 1);
CORRADE_VERIFY(info->pViewportState->pViewports);
CORRADE_COMPARE(info->pViewportState->pViewports[0].x, 1.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].y, 3.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].minDepth, 5.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].width, 6.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].height, 8.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].maxDepth, 14.0f);
CORRADE_COMPARE(info->pViewportState->scissorCount, 1);
CORRADE_VERIFY(info->pViewportState->pScissors);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.x, 1);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.y, 3);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.width, 7);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.height, 9);
}
void PipelineTest::rasterizationCreateInfoViewport2DImplicitScissor() {
ShaderSet shaderSet;
MeshLayout meshLayout{MeshPrimitive::Triangles};
RasterizationPipelineCreateInfo info{shaderSet, meshLayout, {}, {}, 0, 1};
info.setViewport({{1.5f, 3.5f}, {8, 12}});
CORRADE_VERIFY(info->pViewportState);
CORRADE_COMPARE(info->pViewportState->viewportCount, 1);
CORRADE_VERIFY(info->pViewportState->pViewports);
CORRADE_COMPARE(info->pViewportState->pViewports[0].x, 1.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].y, 3.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].minDepth, 0.0f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].width, 6.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].height, 8.5f);
CORRADE_COMPARE(info->pViewportState->pViewports[0].maxDepth, 1.0f);
CORRADE_COMPARE(info->pViewportState->scissorCount, 1);
CORRADE_VERIFY(info->pViewportState->pScissors);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.x, 1);
CORRADE_COMPARE(info->pViewportState->pScissors[0].offset.y, 3);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.width, 7);
CORRADE_COMPARE(info->pViewportState->pScissors[0].extent.height, 9);
}
void PipelineTest::rasterizationCreateInfoDynamicState() {
MeshLayout meshLayout{MeshPrimitive::Triangles};
RasterizationPipelineCreateInfo info{ShaderSet{}, meshLayout, VkPipelineLayout{}, VkRenderPass{}, 0, 0};
CORRADE_VERIFY(!info->pDynamicState);
info.setDynamicStates(
DynamicRasterizationState::CullMode|
DynamicRasterizationState::DepthBoundsTestEnable|
DynamicRasterizationState::ScissorWithCount);
CORRADE_VERIFY(info->pDynamicState);
CORRADE_COMPARE(info->pDynamicState->dynamicStateCount, 3);
CORRADE_VERIFY(info->pDynamicState->pDynamicStates);
CORRADE_COMPARE(info->pDynamicState->pDynamicStates[0], VK_DYNAMIC_STATE_CULL_MODE_EXT);
CORRADE_COMPARE(info->pDynamicState->pDynamicStates[1], VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
CORRADE_COMPARE(info->pDynamicState->pDynamicStates[2], VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
}
void PipelineTest::constructNoCreate() {
{
Pipeline pipeline{NoCreate};
CORRADE_VERIFY(!pipeline.handle());
}
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoCreateT, Pipeline>::value));
}
void PipelineTest::constructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<Pipeline>{});
CORRADE_VERIFY(!std::is_copy_assignable<Pipeline>{});
}
void PipelineTest::memoryBarrierConstruct() {
MemoryBarrier barrier{Access::ColorAttachmentWrite|Access::DepthStencilAttachmentWrite, Access::TransferRead};
CORRADE_COMPARE(barrier->srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT|VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);

298
src/Magnum/Vk/Test/PipelineVkTest.cpp

@ -23,20 +23,45 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/Directory.h>
#include "Magnum/Math/Range.h"
#include "Magnum/Vk/BufferCreateInfo.h"
#include "Magnum/Vk/CommandBuffer.h"
#include "Magnum/Vk/CommandPoolCreateInfo.h"
#include "Magnum/Vk/DeviceProperties.h"
#include "Magnum/Vk/ImageCreateInfo.h"
#include "Magnum/Vk/MeshLayout.h"
#include "Magnum/Vk/Pipeline.h"
#include "Magnum/Vk/PipelineLayoutCreateInfo.h"
#include "Magnum/Vk/PixelFormat.h"
#include "Magnum/Vk/RasterizationPipelineCreateInfo.h"
#include "Magnum/Vk/RenderPassCreateInfo.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/ShaderCreateInfo.h"
#include "Magnum/Vk/ShaderSet.h"
#include "Magnum/Vk/VertexFormat.h"
#include "Magnum/Vk/VulkanTester.h"
#include "configure.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct PipelineVkTest: VulkanTester {
explicit PipelineVkTest();
void constructRasterization();
void constructRasterizationViewportNotSet();
void constructRasterizationViewportNotSetDiscardEnabled();
void constructRasterizationViewportNotSetDynamic();
void constructMove();
void wrap();
void pipelineBarrier();
void pipelineBarrierExecutionOnly();
void pipelineBarrierGlobalMemory();
@ -45,13 +70,284 @@ struct PipelineVkTest: VulkanTester {
};
PipelineVkTest::PipelineVkTest() {
addTests({&PipelineVkTest::pipelineBarrier,
addTests({&PipelineVkTest::constructRasterization,
&PipelineVkTest::constructRasterizationViewportNotSet,
&PipelineVkTest::constructRasterizationViewportNotSetDiscardEnabled,
&PipelineVkTest::constructRasterizationViewportNotSetDynamic,
&PipelineVkTest::constructMove,
&PipelineVkTest::wrap,
&PipelineVkTest::pipelineBarrier,
&PipelineVkTest::pipelineBarrierExecutionOnly,
&PipelineVkTest::pipelineBarrierGlobalMemory,
&PipelineVkTest::pipelineBarrierBufferMemory,
&PipelineVkTest::pipelineBarrierImageMemory});
}
using namespace Containers::Literals;
void PipelineVkTest::constructRasterization() {
/* Wonderful, this contains basically EVERYTHING ELSE that got implemented
until now. */
{
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
AttachmentDescription{PixelFormat::RGBA8Unorm,
AttachmentLoadOperation::Clear,
AttachmentStoreOperation::Store,
ImageLayout::Undefined,
ImageLayout::ColorAttachment}
})
.addSubpass(SubpassDescription{}.setColorAttachments({
AttachmentReference{0, ImageLayout::ColorAttachment}
}))
};
/* Not sure if this is really needed, but the shader needs those inputs
so playing it safe */
MeshLayout meshLayout{MeshPrimitive::Triangles};
meshLayout
.addBinding(0, 2*4*4)
.addAttribute(0, 0, Vk::VertexFormat::Vector4, 0)
.addAttribute(1, 0, Vk::VertexFormat::Vector4, 4*4);
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
Shader shader{device(), ShaderCreateInfo{
Utility::Directory::read(Utility::Directory::join(VK_TEST_DIR, "triangle-shaders.spv"))
}};
ShaderSet shaderSet;
shaderSet
.addShader(ShaderStage::Vertex, shader, "ver"_s)
.addShader(ShaderStage::Fragment, shader, "fra"_s);
Pipeline pipeline{device(), RasterizationPipelineCreateInfo{
shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1}
.setViewport({{}, {200, 200}})
};
CORRADE_VERIFY(pipeline.handle());
CORRADE_COMPARE(pipeline.handleFlags(), HandleFlag::DestroyOnDestruction);
}
/* Shouldn't crash or anything */
CORRADE_VERIFY(true);
}
void PipelineVkTest::constructRasterizationViewportNotSet() {
MeshLayout meshLayout{MeshPrimitive::Triangles};
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
ShaderSet shaderSet;
RasterizationPipelineCreateInfo info{
shaderSet, meshLayout, pipelineLayout, {}, 0, 1
};
CORRADE_VERIFY(!info->pViewportState);
std::ostringstream out;
Error redirectError{&out};
Pipeline pipeline{device(), info};
CORRADE_COMPARE(out.str(), "Vk::Pipeline: if rasterization discard is not enabled, the viewport has to be either dynamic or set via setViewport()\n");
}
void PipelineVkTest::constructRasterizationViewportNotSetDiscardEnabled() {
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
AttachmentDescription{PixelFormat::RGBA8Unorm,
AttachmentLoadOperation::Clear,
AttachmentStoreOperation::Store,
ImageLayout::Undefined,
ImageLayout::ColorAttachment}
})
.addSubpass(SubpassDescription{}.setColorAttachments({
AttachmentReference{0, ImageLayout::ColorAttachment}
}))
};
/* Not sure if this is really needed, but the shader needs those inputs so
playing it safe */
MeshLayout meshLayout{MeshPrimitive::Triangles};
meshLayout
.addBinding(0, 2*4*4)
.addAttribute(0, 0, Vk::VertexFormat::Vector4, 0)
.addAttribute(1, 0, Vk::VertexFormat::Vector4, 4*4);
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
Shader shader{device(), ShaderCreateInfo{
Utility::Directory::read(Utility::Directory::join(VK_TEST_DIR, "triangle-shaders.spv"))
}};
ShaderSet shaderSet;
shaderSet
.addShader(ShaderStage::Vertex, shader, "ver"_s)
.addShader(ShaderStage::Fragment, shader, "fra"_s);
RasterizationPipelineCreateInfo info{shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1};
CORRADE_VERIFY(!info->pViewportState);
/** @todo switch to Magnum API once exposed */
const_cast<VkPipelineRasterizationStateCreateInfo*>(info->pRasterizationState)->rasterizerDiscardEnable = true;
Pipeline pipeline{device(), info};
/* The only thing I want to verify is that this doesn't crash or assert */
CORRADE_VERIFY(pipeline.handle());
}
void PipelineVkTest::constructRasterizationViewportNotSetDynamic() {
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
AttachmentDescription{PixelFormat::RGBA8Unorm,
AttachmentLoadOperation::Clear,
AttachmentStoreOperation::Store,
ImageLayout::Undefined,
ImageLayout::ColorAttachment}
})
.addSubpass(SubpassDescription{}.setColorAttachments({
AttachmentReference{0, ImageLayout::ColorAttachment}
}))
};
/* Not sure if this is really needed, but the shader needs those inputs
so playing it safe */
MeshLayout meshLayout{MeshPrimitive::Triangles};
meshLayout
.addBinding(0, 2*4*4)
.addAttribute(0, 0, Vk::VertexFormat::Vector4, 0)
.addAttribute(1, 0, Vk::VertexFormat::Vector4, 4*4);
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
Shader shader{device(), ShaderCreateInfo{
Utility::Directory::read(Utility::Directory::join(VK_TEST_DIR, "triangle-shaders.spv"))
}};
ShaderSet shaderSet;
shaderSet
.addShader(ShaderStage::Vertex, shader, "ver"_s)
.addShader(ShaderStage::Fragment, shader, "fra"_s);
RasterizationPipelineCreateInfo info{
shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1};
info.setViewport(Range3D{}) /* Has to be set because the count is used */
.setDynamicStates(DynamicRasterizationState::Viewport|
DynamicRasterizationState::Scissor);
/* But the data don't have to be there */
const_cast<VkPipelineViewportStateCreateInfo*>(info->pViewportState)->pViewports = nullptr;
const_cast<VkPipelineViewportStateCreateInfo*>(info->pViewportState)->pScissors = nullptr;
Pipeline pipeline{device(), info};
/* The only thing I want to verify is that this doesn't crash or assert */
CORRADE_VERIFY(pipeline.handle());
}
void PipelineVkTest::constructMove() {
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
AttachmentDescription{PixelFormat::RGBA8Unorm,
AttachmentLoadOperation::Clear,
AttachmentStoreOperation::Store,
ImageLayout::Undefined,
ImageLayout::ColorAttachment}
})
.addSubpass(SubpassDescription{}.setColorAttachments({
AttachmentReference{0, ImageLayout::ColorAttachment}
}))
};
/* Not sure if this is really needed, but the shader needs those inputs so
playing it safe */
MeshLayout meshLayout{MeshPrimitive::Triangles};
meshLayout
.addBinding(0, 2*4*4)
.addAttribute(0, 0, Vk::VertexFormat::Vector4, 0)
.addAttribute(1, 0, Vk::VertexFormat::Vector4, 4*4);
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
Shader shader{device(), ShaderCreateInfo{
Utility::Directory::read(Utility::Directory::join(VK_TEST_DIR, "triangle-shaders.spv"))
}};
ShaderSet shaderSet;
shaderSet
.addShader(ShaderStage::Vertex, shader, "ver"_s)
.addShader(ShaderStage::Fragment, shader, "fra"_s);
Pipeline a{device(), RasterizationPipelineCreateInfo{
shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1}
.setViewport({{}, {200, 200}})
};
VkPipeline handle = a.handle();
Pipeline b = std::move(a);
CORRADE_VERIFY(!a.handle());
CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
Pipeline c{NoCreate};
c = std::move(b);
CORRADE_VERIFY(!b.handle());
CORRADE_COMPARE(b.handleFlags(), HandleFlags{});
CORRADE_COMPARE(c.handle(), handle);
CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_VERIFY(std::is_nothrow_move_constructible<Pipeline>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<Pipeline>::value);
}
void PipelineVkTest::wrap() {
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
AttachmentDescription{PixelFormat::RGBA8Unorm,
AttachmentLoadOperation::Clear,
AttachmentStoreOperation::Store,
ImageLayout::Undefined,
ImageLayout::ColorAttachment}
})
.addSubpass(SubpassDescription{}.setColorAttachments({
AttachmentReference{0, ImageLayout::ColorAttachment}
}))
};
/* Not sure if this is really needed, but the shader needs those inputs so
playing it safe */
MeshLayout meshLayout{MeshPrimitive::Triangles};
meshLayout
.addBinding(0, 2*4*4)
.addAttribute(0, 0, Vk::VertexFormat::Vector4, 0)
.addAttribute(1, 0, Vk::VertexFormat::Vector4, 4*4);
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
Shader shader{device(), ShaderCreateInfo{
Utility::Directory::read(Utility::Directory::join(VK_TEST_DIR, "triangle-shaders.spv"))
}};
ShaderSet shaderSet;
shaderSet
.addShader(ShaderStage::Vertex, shader, "ver"_s)
.addShader(ShaderStage::Fragment, shader, "fra"_s);
VkPipeline pipeline{};
CORRADE_COMPARE(Result(device()->CreateGraphicsPipelines(device(), {}, 1,
RasterizationPipelineCreateInfo{shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1}
.setViewport({{}, {200, 200}}),
nullptr, &pipeline)), Result::Success);
auto wrapped = Pipeline::wrap(device(), pipeline, HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(wrapped.handle(), pipeline);
/* Release the handle again, destroy by hand */
CORRADE_COMPARE(wrapped.release(), pipeline);
CORRADE_VERIFY(!wrapped.handle());
device()->DestroyPipeline(device(), pipeline, nullptr);
}
void PipelineVkTest::pipelineBarrier() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};

4
src/Magnum/Vk/Vk.h

@ -62,6 +62,8 @@ enum class DeviceFeature: UnsignedShort;
typedef Containers::BigEnumSet<DeviceFeature, 4> DeviceFeatures;
class DeviceProperties;
enum class DeviceType: Int;
enum class DynamicRasterizationState: UnsignedByte;
typedef Containers::BigEnumSet<DynamicRasterizationState, 1> DynamicRasterizationStates;
class Extension;
class ExtensionProperties;
class Fence;
@ -96,6 +98,7 @@ enum class MemoryHeapFlag: UnsignedInt;
typedef Containers::EnumSet<MemoryHeapFlag> MemoryHeapFlags;
class MeshLayout;
enum class MeshPrimitive: Int;
class Pipeline;
class PipelineLayout;
class PipelineLayoutCreateInfo;
enum class PipelineStage: UnsignedInt;
@ -104,6 +107,7 @@ enum class PixelFormat: Int;
class Queue;
enum class QueueFlag: UnsignedInt;
typedef Containers::EnumSet<QueueFlag> QueueFlags;
class RasterizationPipelineCreateInfo;
class RenderPass;
class RenderPassBeginInfo;
class RenderPassCreateInfo;

Loading…
Cancel
Save