Commit f6111135 authored by Tobias Frisch's avatar Tobias Frisch
Browse files

Merge branch '65-compute-pipeline' into 'develop'

Resolve "Compute Pipeline"

Closes #65

See merge request !58
parents 326c8c04 820a1981
Pipeline #25667 failed with stages
in 2 minutes and 31 seconds
......@@ -157,6 +157,19 @@ namespace vkcv
[[nodiscard]]
PipelineHandle createGraphicsPipeline(const PipelineConfig &config);
/**
* Creates a basic vulkan compute pipeline using @p shader program and returns it using the @p handle.
* Fixed Functions for pipeline are set with standard values.
*
* @param shader program that hold the compiles compute shader
* @param handle a handle to return the created vulkan handle
* @return True if pipeline creation was successful, False if not
*/
[[nodiscard]]
PipelineHandle createComputePipeline(
const ShaderProgram &config,
const std::vector<vk::DescriptorSetLayout> &descriptorSetLayouts);
/**
* Creates a basic vulkan render pass using @p config from the render pass config class and returns it using the @p handle.
* Fixed Functions for pipeline are set with standard values.
......@@ -211,7 +224,7 @@ namespace vkcv
*/
[[nodiscard]]
DescriptorSetHandle createDescriptorSet(const std::vector<DescriptorBinding> &bindings);
void writeResourceDescription(DescriptorSetHandle handle, size_t setIndex, const DescriptorWrites& writes);
void writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites& writes);
DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const;
......@@ -228,6 +241,13 @@ namespace vkcv
const std::vector<DrawcallInfo> &drawcalls,
const std::vector<ImageHandle> &renderTargets);
void recordComputeDispatchToCmdStream(
CommandStreamHandle cmdStream,
PipelineHandle computePipeline,
const uint32_t dispatchCount[3],
const std::vector<DescriptorSetUsage> &descriptorSetUsages,
const PushConstantData& pushConstantData);
/**
* @brief end recording and present image
*/
......
......@@ -207,7 +207,7 @@ int main(int argc, const char** argv) {
vkcv::SamplerDescriptorWrite(1, sampler),
vkcv::SamplerDescriptorWrite(4, shadowSampler) };
setWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(2, lightBuffer.getHandle()) };
core.writeResourceDescription(descriptorSet, 0, setWrites);
core.writeDescriptorSet(descriptorSet, setWrites);
auto start = std::chrono::system_clock::now();
const auto appStartTime = start;
......
......@@ -130,9 +130,9 @@ int main(int argc, const char** argv) {
};
vkcv::DescriptorWrites setWrites;
setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) };
setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) };
core.writeResourceDescription(descriptorSet, 0, setWrites);
setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) };
setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) };
core.writeDescriptorSet(descriptorSet, setWrites);
vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle();
......
%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv
%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv
%VULKAN_SDK%\Bin32\glslc.exe shader.comp -o comp.spv
pause
\ No newline at end of file
#version 440
layout(std430, binding = 0) buffer testBuffer
{
float test1[10];
float test2[10];
float test3[10];
};
layout( push_constant ) uniform constants{
float pushConstant;
};
layout(local_size_x = 5) in;
void main(){
if(gl_GlobalInvocationID.x >= 10){
return;
}
test1[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x;
test2[gl_GlobalInvocationID.x] = 69; // nice!
test3[gl_GlobalInvocationID.x] = pushConstant;
}
\ No newline at end of file
......@@ -92,6 +92,7 @@ int main(int argc, const char** argv) {
return EXIT_FAILURE;
}
// Graphics Pipeline
vkcv::ShaderProgram triangleShaderProgram{};
triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/vert.spv"));
triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("shaders/frag.spv"));
......@@ -115,6 +116,30 @@ int main(int argc, const char** argv) {
return EXIT_FAILURE;
}
// Compute Pipeline
vkcv::ShaderProgram computeShaderProgram{};
computeShaderProgram.addShader(vkcv::ShaderStage::COMPUTE, std::filesystem::path("shaders/comp.spv"));
computeShaderProgram.reflectShader(vkcv::ShaderStage::COMPUTE);
// take care, assuming shader has exactly one descriptor set
vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeShaderProgram.getReflectedDescriptors()[0]);
vkcv::PipelineHandle computePipeline = core.createComputePipeline(
computeShaderProgram,
{ core.getDescriptorSet(computeDescriptorSet).layout });
struct ComputeTestBuffer {
float test1[10];
float test2[10];
float test3[10];
};
vkcv::Buffer computeTestBuffer = core.createBuffer<ComputeTestBuffer>(vkcv::BufferType::STORAGE, 1);
vkcv::DescriptorWrites computeDescriptorWrites;
computeDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, computeTestBuffer.getHandle()) };
core.writeDescriptorSet(computeDescriptorSet, computeDescriptorWrites);
/*
* BufferHandle triangleVertices = core.createBuffer(vertices);
* BufferHandle triangleIndices = core.createBuffer(indices);
......@@ -164,6 +189,17 @@ int main(int argc, const char** argv) {
pushConstantData,
{ drawcall },
{ swapchainInput });
const uint32_t dispatchSize[3] = { 2, 1, 1 };
const float theMeaningOfLife = 42;
core.recordComputeDispatchToCmdStream(
cmdStream,
computePipeline,
dispatchSize,
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(computeDescriptorSet).vulkanHandle) },
vkcv::PushConstantData((void*)&theMeaningOfLife, sizeof(theMeaningOfLife)));
core.prepareSwapchainImageForPresent(cmdStream);
core.submitCommandStream(cmdStream);
......
......@@ -103,6 +103,13 @@ namespace vkcv
return m_PipelineManager->createPipeline(config, *m_PassManager);
}
PipelineHandle Core::createComputePipeline(
const ShaderProgram &shaderProgram,
const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts)
{
return m_PipelineManager->createComputePipeline(shaderProgram, descriptorSetLayouts);
}
PassHandle Core::createPass(const PassConfig &config)
{
......@@ -300,6 +307,40 @@ namespace vkcv
recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
}
void Core::recordComputeDispatchToCmdStream(
CommandStreamHandle cmdStreamHandle,
PipelineHandle computePipeline,
const uint32_t dispatchCount[3],
const std::vector<DescriptorSetUsage>& descriptorSetUsages,
const PushConstantData& pushConstantData) {
auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
const auto pipelineLayout = m_PipelineManager->getVkPipelineLayout(computePipeline);
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, m_PipelineManager->getVkPipeline(computePipeline));
for (const auto& usage : descriptorSetUsages) {
cmdBuffer.bindDescriptorSets(
vk::PipelineBindPoint::eCompute,
pipelineLayout,
usage.setLocation,
{ usage.vulkanHandle },
{});
}
if (pushConstantData.sizePerDrawcall > 0) {
cmdBuffer.pushConstants(
pipelineLayout,
vk::ShaderStageFlagBits::eCompute,
0,
pushConstantData.sizePerDrawcall,
pushConstantData.data);
}
cmdBuffer.dispatch(dispatchCount[0], dispatchCount[1], dispatchCount[2]);
};
recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr);
}
void Core::endFrame() {
if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
return;
......@@ -404,10 +445,9 @@ namespace vkcv
return m_DescriptorManager->createDescriptorSet(bindings);
}
void Core::writeResourceDescription(DescriptorSetHandle handle, size_t setIndex, const DescriptorWrites &writes) {
m_DescriptorManager->writeResourceDescription(
handle,
setIndex,
void Core::writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites &writes) {
m_DescriptorManager->writeDescriptorSet(
handle,
writes,
*m_ImageManager,
*m_BufferManager,
......
......@@ -92,9 +92,8 @@ namespace vkcv
vk::DescriptorType type;
};
void DescriptorManager::writeResourceDescription(
void DescriptorManager::writeDescriptorSet(
const DescriptorSetHandle &handle,
size_t setIndex,
const DescriptorWrites &writes,
const ImageManager &imageManager,
const BufferManager &bufferManager,
......
......@@ -23,9 +23,8 @@ namespace vkcv
DescriptorSetHandle createDescriptorSet(const std::vector<DescriptorBinding> &descriptorBindings);
void writeResourceDescription(
void writeDescriptorSet(
const DescriptorSetHandle &handle,
size_t setIndex,
const DescriptorWrites &writes,
const ImageManager &imageManager,
const BufferManager &bufferManager,
......
......@@ -193,6 +193,7 @@ namespace vkcv
{},
(config.m_DescriptorLayouts),
(pushConstantRange));
vk::PipelineLayout vkPipelineLayout{};
if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess)
{
......@@ -325,4 +326,65 @@ namespace vkcv
return m_Configs.at(id);
}
PipelineHandle PipelineManager::createComputePipeline(
const ShaderProgram &shaderProgram,
const std::vector<vk::DescriptorSetLayout> &descriptorSetLayouts) {
// Temporally handing over the Shader Program instead of a pipeline config
vk::ShaderModule computeModule{};
if (createShaderModule(computeModule, shaderProgram, ShaderStage::COMPUTE) != vk::Result::eSuccess)
return PipelineHandle();
vk::PipelineShaderStageCreateInfo pipelineComputeShaderStageInfo(
{},
vk::ShaderStageFlagBits::eCompute,
computeModule,
"main",
nullptr
);
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo({}, descriptorSetLayouts);
const size_t pushConstantSize = shaderProgram.getPushConstantSize();
vk::PushConstantRange pushConstantRange(vk::ShaderStageFlagBits::eCompute, 0, pushConstantSize);
if (pushConstantSize > 0) {
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRange);
}
vk::PipelineLayout vkPipelineLayout{};
if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess)
{
m_Device.destroy(computeModule);
return PipelineHandle();
}
vk::ComputePipelineCreateInfo computePipelineCreateInfo{};
computePipelineCreateInfo.stage = pipelineComputeShaderStageInfo;
computePipelineCreateInfo.layout = vkPipelineLayout;
vk::Pipeline vkPipeline;
if (m_Device.createComputePipelines(nullptr, 1, &computePipelineCreateInfo, nullptr, &vkPipeline)!= vk::Result::eSuccess)
{
m_Device.destroy(computeModule);
return PipelineHandle();
}
m_Device.destroy(computeModule);
const uint64_t id = m_Pipelines.size();
m_Pipelines.push_back({ vkPipeline, vkPipelineLayout });
return PipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); });
}
// There is an issue for refactoring the Pipeline Manager.
// While including Compute Pipeline Creation, some private helper functions where introduced:
vk::Result PipelineManager::createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, const ShaderStage stage)
{
std::vector<char> code = shaderProgram.getShader(stage).shaderCode;
vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data()));
return m_Device.createShaderModule(&moduleInfo, nullptr, &module);
}
}
\ No newline at end of file
......@@ -21,7 +21,9 @@ namespace vkcv
std::vector<PipelineConfig> m_Configs;
void destroyPipelineById(uint64_t id);
vk::Result createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, ShaderStage stage);
public:
PipelineManager() = delete; // no default ctor
explicit PipelineManager(vk::Device device) noexcept; // ctor
......@@ -35,6 +37,10 @@ namespace vkcv
PipelineHandle createPipeline(const PipelineConfig &config, PassManager& passManager);
PipelineHandle createComputePipeline(
const ShaderProgram& shaderProgram,
const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts);
[[nodiscard]]
vk::Pipeline getVkPipeline(const PipelineHandle &handle) const;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment