Browse Source

Vk: store the set of dynamic states in a Pipeline instance.

Will be subsequently useful for command buffers.
pull/495/head
Vladimír Vondruš 5 years ago
parent
commit
9e71e5ab0e
  1. 43
      src/Magnum/Vk/Pipeline.cpp
  2. 18
      src/Magnum/Vk/Pipeline.h
  3. 2
      src/Magnum/Vk/RasterizationPipelineCreateInfo.h
  4. 78
      src/Magnum/Vk/Test/PipelineVkTest.cpp

43
src/Magnum/Vk/Pipeline.cpp

@ -43,7 +43,12 @@ namespace Magnum { namespace Vk {
struct RasterizationPipelineCreateInfo::State {
Containers::Array<VkPipelineColorBlendAttachmentState> colorBlendAttachments;
Containers::Array<VkDynamicState> dynamicStates;
/* The enum is saved as well to be subsequently available through
Pipeline::dynamicRasterizationStates() */
DynamicRasterizationStates dynamicStates;
Containers::Array<VkDynamicState> dynamicStateList;
/** @todo make an array once we support multiview */
VkViewport viewport;
VkRect2D scissor;
@ -242,21 +247,24 @@ constexpr VkDynamicState DynamicRasterizationStateMapping[]{
}
RasterizationPipelineCreateInfo& RasterizationPipelineCreateInfo::setDynamicStates(const DynamicRasterizationStates& states) {
/* Save the enum so we can store it in the created Pipeline object later */
_state->dynamicStates = 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};
_state->dynamicStateList = 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];
_state->dynamicStateList[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;
_dynamicInfo.pDynamicStates = _state->dynamicStateList;
_info.pDynamicState = &_dynamicInfo;
return *this;
}
@ -278,15 +286,20 @@ ComputePipelineCreateInfo::ComputePipelineCreateInfo(const VkComputePipelineCrea
member instead of doing a copy */
_info(info) {}
Pipeline Pipeline::wrap(Device& device, const PipelineBindPoint bindPoint, const VkPipeline handle, const HandleFlags flags) {
Pipeline Pipeline::wrap(Device& device, const PipelineBindPoint bindPoint, const VkPipeline handle, const DynamicRasterizationStates& dynamicStates, const HandleFlags flags) {
Pipeline out{NoCreate};
out._device = &device;
out._handle = handle;
out._bindPoint = bindPoint;
out._flags = flags;
out._dynamicStates.rasterization = dynamicStates;
return out;
}
Pipeline Pipeline::wrap(Device& device, const PipelineBindPoint bindPoint, const VkPipeline handle, const HandleFlags flags) {
return wrap(device, bindPoint, handle, DynamicRasterizationStates{}, flags);
}
Pipeline::Pipeline(Device& device, const RasterizationPipelineCreateInfo& info):
_device{&device},
#ifdef CORRADE_GRACEFUL_ASSERT
@ -294,7 +307,8 @@ Pipeline::Pipeline(Device& device, const RasterizationPipelineCreateInfo& info):
_handle{},
#endif
_bindPoint{PipelineBindPoint::Rasterization},
_flags{HandleFlag::DestroyOnDestruction}
_flags{HandleFlag::DestroyOnDestruction},
_dynamicStates{info._state->dynamicStates}
{
/* Doesn't check that the viewport is really a dynamic state, but should
catch most cases without false positives */
@ -304,13 +318,17 @@ Pipeline::Pipeline(Device& device, const RasterizationPipelineCreateInfo& info):
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateGraphicsPipelines(device, {}, 1, info, nullptr, &_handle));
}
Pipeline::Pipeline(Device& device, const ComputePipelineCreateInfo& info): _device{&device}, _bindPoint{PipelineBindPoint::Compute}, _flags{HandleFlag::DestroyOnDestruction} {
Pipeline::Pipeline(Device& device, const ComputePipelineCreateInfo& info): _device{&device}, _bindPoint{PipelineBindPoint::Compute}, _flags{HandleFlag::DestroyOnDestruction}, _dynamicStates{} {
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateComputePipelines(device, {}, 1, info, nullptr, &_handle));
}
Pipeline::Pipeline(NoCreateT): _device{}, _handle{}, _bindPoint{} {}
Pipeline::Pipeline(NoCreateT): _device{}, _handle{}, _bindPoint{}, _dynamicStates{} {}
Pipeline::Pipeline(Pipeline&& other) noexcept: _device{other._device}, _handle{other._handle}, _bindPoint{other._bindPoint}, _flags{other._flags} {
Pipeline::Pipeline(Pipeline&& other) noexcept: _device{other._device}, _handle{other._handle}, _bindPoint{other._bindPoint}, _flags{other._flags},
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_dynamicStates(other._dynamicStates)
{
other._handle = {};
}
@ -325,9 +343,16 @@ Pipeline& Pipeline::operator=(Pipeline&& other) noexcept {
swap(other._handle, _handle);
swap(other._bindPoint, _bindPoint);
swap(other._flags, _flags);
swap(other._dynamicStates, _dynamicStates);
return *this;
}
DynamicRasterizationStates Pipeline::dynamicRasterizationStates() const {
CORRADE_ASSERT(_bindPoint == PipelineBindPoint::Rasterization,
"Vk::Pipeline::dynamicRasterizationStates(): not a rasterization pipeline", {});
return _dynamicStates.rasterization;
}
VkPipeline Pipeline::release() {
const VkPipeline handle = _handle;
_handle = {};

18
src/Magnum/Vk/Pipeline.h

@ -30,6 +30,7 @@
* @m_since_latest
*/
#include <Corrade/Containers/BigEnumSet.h>
#include <Corrade/Containers/EnumSet.h>
#include "Magnum/Magnum.h"
@ -116,6 +117,9 @@ class MAGNUM_VK_EXPORT Pipeline {
* @param bindPoint Pipeline bind point. Available through
* @ref bindPoint() afterwards.
* @param handle The @type_vk{Pipeline} handle
* @param dynamicStates Dynamic states enabled on the rasterization
* pipeline. Available through @ref dynamicRasterizationStates()
* afterwards.
* @param flags Handle flags
*
* The @p handle is expected to be originating from @p device. Unlike
@ -124,6 +128,8 @@ class MAGNUM_VK_EXPORT Pipeline {
* different behavior.
* @see @ref release()
*/
static Pipeline wrap(Device& device, PipelineBindPoint bindPoint, VkPipeline handle, const DynamicRasterizationStates& dynamicStates, HandleFlags flags = {});
/** @overload */
static Pipeline wrap(Device& device, PipelineBindPoint bindPoint, VkPipeline handle, HandleFlags flags = {});
/**
@ -193,6 +199,15 @@ class MAGNUM_VK_EXPORT Pipeline {
*/
PipelineBindPoint bindPoint() const { return _bindPoint; }
/**
* @brief Dynamic rasterization states enabled in this pipeline
*
* Contains the states passed to @ref RasterizationPipelineCreateInfo::setDynamicStates()
* or to the @ref wrap() call. Expects that @ref bindPoint() is
* @ref PipelineBindPoint::Rasterization.
*/
DynamicRasterizationStates dynamicRasterizationStates() const;
/**
* @brief Release the underlying Vulkan pipeline
*
@ -210,6 +225,9 @@ class MAGNUM_VK_EXPORT Pipeline {
VkPipeline _handle;
PipelineBindPoint _bindPoint;
HandleFlags _flags;
union {
DynamicRasterizationStates rasterization;
} _dynamicStates;
};
/**

2
src/Magnum/Vk/RasterizationPipelineCreateInfo.h

@ -524,6 +524,8 @@ class MAGNUM_VK_EXPORT RasterizationPipelineCreateInfo {
operator const VkGraphicsPipelineCreateInfo*() const { return &_info; }
private:
friend Pipeline;
VkGraphicsPipelineCreateInfo _info;
VkPipelineViewportStateCreateInfo _viewportInfo;
VkPipelineRasterizationStateCreateInfo _rasterizationInfo;

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

@ -62,7 +62,10 @@ struct PipelineVkTest: VulkanTester {
void constructCompute();
void constructMove();
void wrap();
void wrapRasterization();
void wrapCompute();
void dynamicRasterizationStatesNotRasterization();
void cmdBind();
@ -81,7 +84,10 @@ PipelineVkTest::PipelineVkTest() {
&PipelineVkTest::constructCompute,
&PipelineVkTest::constructMove,
&PipelineVkTest::wrap,
&PipelineVkTest::wrapRasterization,
&PipelineVkTest::wrapCompute,
&PipelineVkTest::dynamicRasterizationStatesNotRasterization,
&PipelineVkTest::cmdBind,
@ -134,10 +140,12 @@ void PipelineVkTest::constructRasterization() {
Pipeline pipeline{device(), RasterizationPipelineCreateInfo{
shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1}
.setViewport({{}, {200, 200}})
.setDynamicStates(DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias)
};
CORRADE_VERIFY(pipeline.handle());
CORRADE_COMPARE(pipeline.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(pipeline.bindPoint(), PipelineBindPoint::Rasterization);
CORRADE_COMPARE(pipeline.dynamicRasterizationStates(), DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias);
}
/* Shouldn't crash or anything */
@ -241,16 +249,16 @@ void PipelineVkTest::constructRasterizationViewportNotSetDynamic() {
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);
.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 */
/* The main thing I want to verify is that this doesn't crash or assert */
CORRADE_VERIFY(pipeline.handle());
CORRADE_COMPARE(pipeline.dynamicRasterizationStates(), DynamicRasterizationState::Viewport|DynamicRasterizationState::Scissor);
}
void PipelineVkTest::constructCompute() {
@ -311,6 +319,7 @@ void PipelineVkTest::constructMove() {
Pipeline a{device(), RasterizationPipelineCreateInfo{
shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1}
.setViewport({{}, {200, 200}})
.setDynamicStates(DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias)
};
VkPipeline handle = a.handle();
@ -319,6 +328,7 @@ void PipelineVkTest::constructMove() {
CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(b.bindPoint(), PipelineBindPoint::Rasterization);
CORRADE_COMPARE(b.dynamicRasterizationStates(), DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias);
Pipeline c{NoCreate};
c = std::move(b);
@ -327,12 +337,13 @@ void PipelineVkTest::constructMove() {
CORRADE_COMPARE(c.handle(), handle);
CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(c.bindPoint(), PipelineBindPoint::Rasterization);
CORRADE_COMPARE(c.dynamicRasterizationStates(), DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias);
CORRADE_VERIFY(std::is_nothrow_move_constructible<Pipeline>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<Pipeline>::value);
}
void PipelineVkTest::wrap() {
void PipelineVkTest::wrapRasterization() {
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
AttachmentDescription{PixelFormat::RGBA8Unorm,
@ -368,12 +379,39 @@ void PipelineVkTest::wrap() {
VkPipeline pipeline{};
CORRADE_COMPARE(Result(device()->CreateGraphicsPipelines(device(), {}, 1,
RasterizationPipelineCreateInfo{shaderSet, meshLayout, pipelineLayout, renderPass, 0, 1}
.setViewport({{}, {200, 200}}),
.setViewport({{}, {200, 200}})
.setDynamicStates(DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias),
nullptr, &pipeline)), Result::Success);
auto wrapped = Pipeline::wrap(device(), PipelineBindPoint::Rasterization, pipeline, HandleFlag::DestroyOnDestruction);
auto wrapped = Pipeline::wrap(device(), PipelineBindPoint::Rasterization, pipeline, DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias, HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(wrapped.handle(), pipeline);
CORRADE_COMPARE(wrapped.bindPoint(), PipelineBindPoint::Rasterization);
CORRADE_COMPARE(wrapped.dynamicRasterizationStates(), DynamicRasterizationState::LineWidth|DynamicRasterizationState::DepthBias);
/* Release the handle again, destroy by hand */
CORRADE_COMPARE(wrapped.release(), pipeline);
CORRADE_VERIFY(!wrapped.handle());
device()->DestroyPipeline(device(), pipeline, nullptr);
}
void PipelineVkTest::wrapCompute() {
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
Shader shader{device(), ShaderCreateInfo{
Utility::Directory::read(Utility::Directory::join(VK_TEST_DIR, "compute-noop.spv"))
}};
ShaderSet shaderSet;
shaderSet.addShader(ShaderStage::Compute, shader, "main"_s);
VkPipeline pipeline{};
CORRADE_COMPARE(Result(device()->CreateComputePipelines(device(), {}, 1,
ComputePipelineCreateInfo{shaderSet, pipelineLayout},
nullptr, &pipeline)), Result::Success);
auto wrapped = Pipeline::wrap(device(), PipelineBindPoint::Compute, pipeline, HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(wrapped.handle(), pipeline);
CORRADE_COMPARE(wrapped.bindPoint(), PipelineBindPoint::Compute);
/* Release the handle again, destroy by hand */
CORRADE_COMPARE(wrapped.release(), pipeline);
@ -381,6 +419,30 @@ void PipelineVkTest::wrap() {
device()->DestroyPipeline(device(), pipeline, nullptr);
}
void PipelineVkTest::dynamicRasterizationStatesNotRasterization() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
PipelineLayout pipelineLayout{device(), PipelineLayoutCreateInfo{}};
Shader shader{device(), ShaderCreateInfo{
Utility::Directory::read(Utility::Directory::join(VK_TEST_DIR, "compute-noop.spv"))
}};
ShaderSet shaderSet;
shaderSet.addShader(ShaderStage::Compute, shader, "main"_s);
Pipeline pipeline{device(), ComputePipelineCreateInfo{
shaderSet, pipelineLayout
}};
std::ostringstream out;
Error redirectError{&out};
pipeline.dynamicRasterizationStates();
CORRADE_COMPARE(out.str(), "Vk::Pipeline::dynamicRasterizationStates(): not a rasterization pipeline\n");
}
void PipelineVkTest::cmdBind() {
CommandPool pool{device(), CommandPoolCreateInfo{
/* This might blow up if queue() isn't the one matching this family */

Loading…
Cancel
Save