Browse Source

Vk: implement binding a pipeline.

pull/494/head
Vladimír Vondruš 5 years ago
parent
commit
5604ccf3cd
  1. 11
      doc/snippets/MagnumVk.cpp
  2. 4
      doc/vulkan-mapping.dox
  3. 10
      src/Magnum/Vk/CommandBuffer.h
  4. 33
      src/Magnum/Vk/Pipeline.cpp
  5. 56
      src/Magnum/Vk/Pipeline.h
  6. 3
      src/Magnum/Vk/RenderPass.cpp
  7. 2
      src/Magnum/Vk/RenderPassCreateInfo.h
  8. 12
      src/Magnum/Vk/Test/PipelineTest.cpp
  9. 37
      src/Magnum/Vk/Test/PipelineVkTest.cpp
  10. 1
      src/Magnum/Vk/Vk.h

11
doc/snippets/MagnumVk.cpp

@ -830,6 +830,17 @@ Vk::Pipeline pipeline{device, Vk::ComputePipelineCreateInfo{
/* [Pipeline-creation-compute] */
}
{
Vk::CommandBuffer cmd{NoCreate};
/* [Pipeline-usage] */
Vk::Pipeline pipeline{DOXYGEN_IGNORE(NoCreate)};
DOXYGEN_IGNORE()
cmd.bindPipeline(pipeline);
/* [Pipeline-usage] */
}
{
Vk::Device device{NoCreate};
/* The include should be a no-op here since it was already included above */

4
doc/vulkan-mapping.dox

@ -114,7 +114,7 @@ Vulkan function | Matching API
@fn_vk{CmdBeginRenderPass}, \n @fn_vk{CmdBeginRenderPass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{CmdNextSubpass}, \n @fn_vk{CmdNextSubpass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{CmdEndRenderpass}, \n @fn_vk{CmdEndRenderpass2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref CommandBuffer::beginRenderPass(), \n @ref CommandBuffer::nextSubpass(), \n @ref CommandBuffer::endRenderPass()
@fn_vk{CmdBindDescriptorSets} | |
@fn_vk{CmdBindIndexBuffer} | |
@fn_vk{CmdBindPipeline} | |
@fn_vk{CmdBindPipeline} | @ref CommandBuffer::bindPipeline()
@fn_vk{CmdBindVertexBuffers}, \n @fn_vk{CmdBindVertexBuffers2EXT} @m_class{m-label m-flat m-warning} **EXT** | |
@fn_vk{CmdBlitImage}, \n @fn_vk{CmdBlitImage2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdBuildAccelerationStructuresIndirectKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@ -915,7 +915,7 @@ Vulkan enum | Matching API
--------------------------------------- | ------------
@type_vk{PeerMemoryFeatureFlagBits} @m_class{m-label m-flat m-success} **KHR, 1.1**, \n @type_vk{PeerMemoryFeatureFlags} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@type_vk{PhysicalDeviceType} | @ref DeviceType
@type_vk{PipelineBindPoint} | |
@type_vk{PipelineBindPoint} | @ref PipelineBindPoint
@type_vk{PipelineCacheCreateFlagBits}, \n @type_vk{PipelineCacheCreateFlags} | |
@type_vk{PipelineCacheHeaderVersion} | |
@type_vk{PipelineCacheCreateFlagBits}, \n @type_vk{PipelineCacheCreateFlags} | |

10
src/Magnum/Vk/CommandBuffer.h

@ -357,6 +357,16 @@ class MAGNUM_VK_EXPORT CommandBuffer {
CommandBuffer& endRenderPass();
#endif
/**
* @brief Bind a pipeline
* @return Reference to self (for method chaining)
*
* Can be called both inside and outside a render pass. See
* @ref Vk-Pipeline-usage for a usage example.
* @see @fn_vk_keyword{CmdBindPipeline}
*/
CommandBuffer& bindPipeline(Pipeline& pipeline);
/**
* @brief Insert an execution barrier with optional memory dependencies
* @param sourceStages Source stages. Has to contain at least

33
src/Magnum/Vk/Pipeline.cpp

@ -277,10 +277,11 @@ ComputePipelineCreateInfo::ComputePipelineCreateInfo(const VkComputePipelineCrea
member instead of doing a copy */
_info(info) {}
Pipeline Pipeline::wrap(Device& device, const VkPipeline handle, const HandleFlags flags) {
Pipeline Pipeline::wrap(Device& device, const PipelineBindPoint bindPoint, const VkPipeline handle, const HandleFlags flags) {
Pipeline out{NoCreate};
out._device = &device;
out._handle = handle;
out._bindPoint = bindPoint;
out._flags = flags;
return out;
}
@ -291,6 +292,7 @@ Pipeline::Pipeline(Device& device, const RasterizationPipelineCreateInfo& info):
/* Otherwise vkDestroyPipeline() crashes when we hit the assert */
_handle{},
#endif
_bindPoint{PipelineBindPoint::Rasterization},
_flags{HandleFlag::DestroyOnDestruction}
{
/* Doesn't check that the viewport is really a dynamic state, but should
@ -301,13 +303,13 @@ 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}, _flags{HandleFlag::DestroyOnDestruction} {
Pipeline::Pipeline(Device& device, const ComputePipelineCreateInfo& info): _device{&device}, _bindPoint{PipelineBindPoint::Compute}, _flags{HandleFlag::DestroyOnDestruction} {
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateComputePipelines(device, {}, 1, info, nullptr, &_handle));
}
Pipeline::Pipeline(NoCreateT): _device{}, _handle{} {}
Pipeline::Pipeline(NoCreateT): _device{}, _handle{}, _bindPoint{} {}
Pipeline::Pipeline(Pipeline&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} {
Pipeline::Pipeline(Pipeline&& other) noexcept: _device{other._device}, _handle{other._handle}, _bindPoint{other._bindPoint}, _flags{other._flags} {
other._handle = {};
}
@ -320,6 +322,7 @@ Pipeline& Pipeline::operator=(Pipeline&& other) noexcept {
using std::swap;
swap(other._device, _device);
swap(other._handle, _handle);
swap(other._bindPoint, _bindPoint);
swap(other._flags, _flags);
return *this;
}
@ -382,6 +385,11 @@ ImageMemoryBarrier::ImageMemoryBarrier(const VkImageMemoryBarrier& barrier):
member instead of doing a copy */
_barrier(barrier) {}
CommandBuffer& CommandBuffer::bindPipeline(Pipeline& pipeline) {
(**_device).CmdBindPipeline(_handle, VkPipelineBindPoint(pipeline.bindPoint()), pipeline);
return *this;
}
CommandBuffer& CommandBuffer::pipelineBarrier(const PipelineStages sourceStages, const PipelineStages destinationStages, const Containers::ArrayView<const MemoryBarrier> memoryBarriers, const Containers::ArrayView<const BufferMemoryBarrier> bufferMemoryBarriers, const Containers::ArrayView<const ImageMemoryBarrier> imageMemoryBarriers, const DependencyFlags dependencyFlags) {
/* Once these grow (VkSampleLocationsInfoEXT?), they will need to be
linearized into a separate array first */
@ -426,4 +434,21 @@ CommandBuffer& CommandBuffer::pipelineBarrier(const PipelineStages sourceStages,
return pipelineBarrier(sourceStages, destinationStages, Containers::arrayView(imageMemoryBarriers), dependencyFlags);
}
Debug& operator<<(Debug& debug, const PipelineBindPoint value) {
debug << "Vk::PipelineBindPoint" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(value) case Vk::PipelineBindPoint::value: return debug << "::" << Debug::nospace << #value;
_c(Rasterization)
_c(RayTracing)
_c(Compute)
#undef _c
/* LCOV_EXCL_STOP */
}
/* Vulkan docs have the values in decimal, so not converting to hex */
return debug << "(" << Debug::nospace << Int(value) << Debug::nospace << ")";
}
}}

56
src/Magnum/Vk/Pipeline.h

@ -26,7 +26,7 @@
*/
/** @file
* @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
* @brief Class @ref Magnum::Vk::Pipeline, @ref Magnum::Vk::MemoryBarrier, @ref Magnum::Vk::BufferMemoryBarrier, @ref Magnum::Vk::ImageMemoryBarrier, enum @ref Magnum::Vk::PipelineBindPoint, @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,37 @@
namespace Magnum { namespace Vk {
/**
@brief Pipeline bind point
@m_since_latest
Wraps a @type_vk_keyword{PipelineBindPoint}.
@see @ref Pipeline::bindPoint()
@m_enum_values_as_keywords
*/
enum class PipelineBindPoint: Int {
/**
* Rasterization pipeline
* @see @ref RasterizationPipelineCreateInfo
*/
Rasterization = VK_PIPELINE_BIND_POINT_GRAPHICS,
/** Ray tracing pipeline */
RayTracing = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
/**
* Compute pipeline
* @see @ref ComputePipelineCreateInfo
*/
Compute = VK_PIPELINE_BIND_POINT_COMPUTE
};
/**
@debugoperatorenum{PipelineBindPoint}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, PipelineBindPoint value);
/**
@brief Pipeline
@m_since_latest
@ -68,12 +99,22 @@ a @ref ShaderSet containing a single @ref ShaderStage::Compute shader and a
@link PipelineLayout @endlink:
@snippet MagnumVk.cpp Pipeline-creation-compute
@section Vk-Pipeline-usage Pipeline usage
A pipeline is bound to a compatible command buffer using
@ref CommandBuffer::bindPipeline(), which replaces any pipeline bound
previously to the same @ref bindPoint():
@snippet MagnumVk.cpp Pipeline-usage
*/
class MAGNUM_VK_EXPORT Pipeline {
public:
/**
* @brief Wrap existing Vulkan handle
* @param device Vulkan device the pipeline is created on
* @param bindPoint Pipeline bind point. Available through
* @ref bindPoint() afterwards.
* @param handle The @type_vk{Pipeline} handle
* @param flags Handle flags
*
@ -83,13 +124,14 @@ class MAGNUM_VK_EXPORT Pipeline {
* different behavior.
* @see @ref release()
*/
static Pipeline wrap(Device& device, VkPipeline handle, HandleFlags flags = {});
static Pipeline wrap(Device& device, PipelineBindPoint bindPoint, VkPipeline handle, HandleFlags flags = {});
/**
* @brief Construct a rasterization pipeline
* @param device Vulkan device to create the pipeline on
* @param info Rasterization pipeline creation info
*
* THe @ref bindPoint() is set to @ref PipelineBindPoint::Rasterization.
* @see @fn_vk_keyword{CreateGraphicsPipelines}
*/
explicit Pipeline(Device& device, const RasterizationPipelineCreateInfo& info);
@ -99,6 +141,7 @@ class MAGNUM_VK_EXPORT Pipeline {
* @param device Vulkan device to create the pipeline on
* @param info Compite pipeline creation info
*
* THe @ref bindPoint() is set to @ref PipelineBindPoint::Compute.
* @see @fn_vk_keyword{CreateComputePipelines}
*/
explicit Pipeline(Device& device, const ComputePipelineCreateInfo& info);
@ -142,6 +185,14 @@ class MAGNUM_VK_EXPORT Pipeline {
/** @brief Handle flags */
HandleFlags handleFlags() const { return _flags; }
/**
* @brief Pipeline bind point
*
* Either set implicitly based on what constructor was used, or coming
* from the @ref wrap() call.
*/
PipelineBindPoint bindPoint() const { return _bindPoint; }
/**
* @brief Release the underlying Vulkan pipeline
*
@ -157,6 +208,7 @@ class MAGNUM_VK_EXPORT Pipeline {
Device* _device;
VkPipeline _handle;
PipelineBindPoint _bindPoint;
HandleFlags _flags;
};

3
src/Magnum/Vk/RenderPass.cpp

@ -38,6 +38,7 @@
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/Image.h"
#include "Magnum/Vk/Integration.h"
#include "Magnum/Vk/Pipeline.h"
#include "Magnum/Vk/PixelFormat.h"
#include "Magnum/Vk/Implementation/DeviceState.h"
@ -175,7 +176,7 @@ struct SubpassDescription::State {
SubpassDescription::SubpassDescription(const Flags flags): _description{} {
_description.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
_description.flags = VkSubpassDescriptionFlags(flags);
_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
_description.pipelineBindPoint = VkPipelineBindPoint(PipelineBindPoint::Rasterization);
}
SubpassDescription::SubpassDescription(NoInitT) noexcept {}

2
src/Magnum/Vk/RenderPassCreateInfo.h

@ -506,7 +506,7 @@ class MAGNUM_VK_EXPORT SubpassDescription {
* in addition to `sType`, everything else is zero-filled:
*
* - `flags`
* - `pipelineBindPoint` to @val_vk{PIPELINE_BIND_POINT_GRAPHICS,PipelineBindPoint}
* - `pipelineBindPoint` to @ref PipelineBindPoint::Rasterization
*
* Use @ref setInputAttachments(), @ref setColorAttachments(),
* @ref setDepthStencilAttachment() and @ref setPreserveAttachments()

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

@ -82,6 +82,8 @@ struct PipelineTest: TestSuite::Tester {
void imageMemoryBarrierConstructImplicitAspect();
void imageMemoryBarrierConstructNoInit();
void imageMemoryBarrierConstructFromVk();
void debugBindPoint();
};
PipelineTest::PipelineTest() {
@ -120,7 +122,9 @@ PipelineTest::PipelineTest() {
&PipelineTest::imageMemoryBarrierConstruct,
&PipelineTest::imageMemoryBarrierConstructImplicitAspect,
&PipelineTest::imageMemoryBarrierConstructNoInit,
&PipelineTest::imageMemoryBarrierConstructFromVk});
&PipelineTest::imageMemoryBarrierConstructFromVk,
&PipelineTest::debugBindPoint});
}
using namespace Containers::Literals;
@ -711,6 +715,12 @@ void PipelineTest::imageMemoryBarrierConstructFromVk() {
CORRADE_COMPARE(barrier->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void PipelineTest::debugBindPoint() {
std::ostringstream out;
Debug{&out} << PipelineBindPoint::Compute << PipelineBindPoint(-10007655);
CORRADE_COMPARE(out.str(), "Vk::PipelineBindPoint::Compute Vk::PipelineBindPoint(-10007655)\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::PipelineTest)

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

@ -64,6 +64,8 @@ struct PipelineVkTest: VulkanTester {
void wrap();
void cmdBind();
void cmdBarrier();
void cmdBarrierExecutionOnly();
void cmdBarrierGlobalMemory();
@ -81,6 +83,8 @@ PipelineVkTest::PipelineVkTest() {
&PipelineVkTest::wrap,
&PipelineVkTest::cmdBind,
&PipelineVkTest::cmdBarrier,
&PipelineVkTest::cmdBarrierExecutionOnly,
&PipelineVkTest::cmdBarrierGlobalMemory,
@ -133,6 +137,7 @@ void PipelineVkTest::constructRasterization() {
};
CORRADE_VERIFY(pipeline.handle());
CORRADE_COMPARE(pipeline.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(pipeline.bindPoint(), PipelineBindPoint::Rasterization);
}
/* Shouldn't crash or anything */
@ -289,6 +294,7 @@ void PipelineVkTest::constructMove() {
CORRADE_VERIFY(!a.handle());
CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(b.bindPoint(), PipelineBindPoint::Compute);
Pipeline c{NoCreate};
c = std::move(b);
@ -296,6 +302,7 @@ void PipelineVkTest::constructMove() {
CORRADE_COMPARE(b.handleFlags(), HandleFlags{});
CORRADE_COMPARE(c.handle(), handle);
CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(c.bindPoint(), PipelineBindPoint::Compute);
CORRADE_VERIFY(std::is_nothrow_move_constructible<Pipeline>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<Pipeline>::value);
@ -316,8 +323,9 @@ void PipelineVkTest::wrap() {
ComputePipelineCreateInfo{shaderSet, pipelineLayout},
nullptr, &pipeline)), Result::Success);
auto wrapped = Pipeline::wrap(device(), pipeline, HandleFlag::DestroyOnDestruction);
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);
@ -325,6 +333,33 @@ void PipelineVkTest::wrap() {
device()->DestroyPipeline(device(), pipeline, nullptr);
}
void PipelineVkTest::cmdBind() {
CommandPool pool{device(), CommandPoolCreateInfo{
/* This might blow up if queue() isn't the one matching this family */
device().properties().pickQueueFamily(QueueFlag::Graphics|QueueFlag::Compute)}};
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
}};
pool.allocate()
.begin()
.bindPipeline(pipeline)
.end();
/* Does not do anything visible, so just test that it didn't blow up */
CORRADE_VERIFY(true);
}
void PipelineVkTest::cmdBarrier() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};

1
src/Magnum/Vk/Vk.h

@ -100,6 +100,7 @@ typedef Containers::EnumSet<MemoryHeapFlag> MemoryHeapFlags;
class MeshLayout;
enum class MeshPrimitive: Int;
class Pipeline;
enum class PipelineBindPoint: Int;
class PipelineLayout;
class PipelineLayoutCreateInfo;
enum class PipelineStage: UnsignedInt;

Loading…
Cancel
Save