Latest chapter from vkguide but doesn't work yet.
This commit is contained in:
parent
40717cf8e4
commit
a5c13d8654
10 changed files with 321 additions and 7 deletions
5
Makefile
5
Makefile
|
|
@ -9,6 +9,9 @@ else
|
|||
sh -x ./scripts/reset_build.sh
|
||||
endif
|
||||
|
||||
shaders:
|
||||
glslangValidator -V gradient.comp -o gradient.comp.spv
|
||||
|
||||
%.cpp : %.rl
|
||||
ragel -I $(ROOT_DIR) -G1 -o $@ $<
|
||||
|
||||
|
|
@ -18,7 +21,7 @@ endif
|
|||
%.png: %.dot
|
||||
dot -Tpng $< -o $@
|
||||
|
||||
build:
|
||||
build:
|
||||
meson compile -j 10 -C $(ROOT_DIR)/builddir
|
||||
|
||||
release_build:
|
||||
|
|
|
|||
28
gradient.comp
Normal file
28
gradient.comp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//GLSL version to use
|
||||
#version 460
|
||||
|
||||
//size of a workgroup for compute
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
|
||||
//descriptor bindings for the pipeline
|
||||
layout(rgba16f,set = 0, binding = 0) uniform image2D image;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texelCoord = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 size = imageSize(image);
|
||||
|
||||
if(texelCoord.x < size.x && texelCoord.y < size.y)
|
||||
{
|
||||
vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
if(gl_LocalInvocationID.x != 0 && gl_LocalInvocationID.y != 0)
|
||||
{
|
||||
color.x = float(texelCoord.x)/(size.x);
|
||||
color.y = float(texelCoord.y)/(size.y);
|
||||
}
|
||||
|
||||
imageStore(image, texelCoord, color);
|
||||
}
|
||||
}
|
||||
BIN
gradient.comp.spv
Normal file
BIN
gradient.comp.spv
Normal file
Binary file not shown.
|
|
@ -95,6 +95,8 @@ sources = [
|
|||
'vk_initializers.cpp',
|
||||
'vk_engine.cpp',
|
||||
'vk_images.cpp',
|
||||
'vk_descriptors.cpp',
|
||||
'vk_pipelines.cpp',
|
||||
'main.cpp',
|
||||
]
|
||||
|
||||
|
|
|
|||
92
vk_descriptors.cpp
Normal file
92
vk_descriptors.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#include "vk_descriptors.h"
|
||||
|
||||
void DescriptorLayoutBuilder::add_binding(uint32_t binding, VkDescriptorType type)
|
||||
{
|
||||
|
||||
VkDescriptorSetLayoutBinding newbind {};
|
||||
newbind.binding = binding;
|
||||
newbind.descriptorCount = 1;
|
||||
newbind.descriptorType = type;
|
||||
|
||||
bindings.push_back(newbind);
|
||||
}
|
||||
|
||||
void DescriptorLayoutBuilder::clear()
|
||||
{
|
||||
bindings.clear();
|
||||
}
|
||||
|
||||
VkDescriptorSetLayout DescriptorLayoutBuilder::build(VkDevice device,
|
||||
VkShaderStageFlags shaderStages,
|
||||
void* pNext,
|
||||
VkDescriptorSetLayoutCreateFlags flags)
|
||||
{
|
||||
for(auto& b : bindings) {
|
||||
b.stageFlags |= shaderStages;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
|
||||
};
|
||||
info.pNext = pNext;
|
||||
|
||||
info.pBindings = bindings.data();
|
||||
info.bindingCount = (uint32_t)bindings.size();
|
||||
info.flags = flags;
|
||||
|
||||
VkDescriptorSetLayout set;
|
||||
VK_CHECK(vkCreateDescriptorSetLayout(device,
|
||||
&info, nullptr, &set));
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
void DescriptorAllocator::init_pool(VkDevice device, uint32_t maxSets,
|
||||
std::span<PoolSizeRatio> poolRatios)
|
||||
{
|
||||
std::vector<VkDescriptorPoolSize> poolSizes;
|
||||
for(PoolSizeRatio ratio : poolRatios) {
|
||||
poolSizes.push_back(VkDescriptorPoolSize{
|
||||
.type = ratio.type,
|
||||
.descriptorCount = uint32_t(ratio.ratio * maxSets)
|
||||
});
|
||||
}
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO
|
||||
};
|
||||
pool_info.flags = 0;
|
||||
pool_info.maxSets = maxSets;
|
||||
pool_info.poolSizeCount = (uint32_t)poolSizes.size();
|
||||
pool_info.pPoolSizes = poolSizes.data();
|
||||
|
||||
vkCreateDescriptorPool(device, &pool_info, nullptr, &pool);
|
||||
}
|
||||
|
||||
void DescriptorAllocator::clear_descriptors(VkDevice device)
|
||||
{
|
||||
vkResetDescriptorPool(device, pool, 0);
|
||||
}
|
||||
|
||||
void DescriptorAllocator::destroy_pool(VkDevice device)
|
||||
{
|
||||
vkDestroyDescriptorPool(device, pool, nullptr);
|
||||
}
|
||||
|
||||
VkDescriptorSet DescriptorAllocator::allocate(VkDevice device, VkDescriptorSetLayout layout)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO
|
||||
};
|
||||
|
||||
allocInfo.pNext = nullptr;
|
||||
allocInfo.descriptorPool = pool;
|
||||
allocInfo.descriptorSetCount = 1;
|
||||
allocInfo.pSetLayouts = &layout;
|
||||
|
||||
VkDescriptorSet ds;
|
||||
VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &ds));
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
35
vk_descriptors.h
Normal file
35
vk_descriptors.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include "vk_types.h"
|
||||
#include <vector>
|
||||
|
||||
struct DescriptorLayoutBuilder {
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
||||
|
||||
void add_binding(uint32_t binding, VkDescriptorType type);
|
||||
void clear();
|
||||
|
||||
VkDescriptorSetLayout build(VkDevice device,
|
||||
VkShaderStageFlags shaderStages,
|
||||
void* pNext = nullptr,
|
||||
VkDescriptorSetLayoutCreateFlags flags = 0);
|
||||
};
|
||||
|
||||
struct DescriptorAllocator {
|
||||
|
||||
struct PoolSizeRatio {
|
||||
VkDescriptorType type;
|
||||
float ratio;
|
||||
};
|
||||
|
||||
VkDescriptorPool pool;
|
||||
|
||||
void init_pool(VkDevice device, uint32_t maxSets,
|
||||
std::span<PoolSizeRatio> poolRatios);
|
||||
|
||||
void clear_descriptors(VkDevice device);
|
||||
void destroy_pool(VkDevice device);
|
||||
|
||||
VkDescriptorSet allocate(VkDevice device, VkDescriptorSetLayout layout);
|
||||
|
||||
};
|
||||
104
vk_engine.cpp
104
vk_engine.cpp
|
|
@ -1,5 +1,6 @@
|
|||
#include "vk_engine.h"
|
||||
#include "vk_images.h"
|
||||
#include "vk_pipelines.h"
|
||||
#include <print>
|
||||
|
||||
#include <SDL.h>
|
||||
|
|
@ -15,7 +16,7 @@
|
|||
#define VMA_IMPLEMENTATION
|
||||
#include "vk_mem_alloc.h"
|
||||
|
||||
constexpr bool bUseValidationLayers = false;
|
||||
constexpr bool bUseValidationLayers = true;
|
||||
|
||||
VulkanEngine* loadedEngine = nullptr;
|
||||
|
||||
|
|
@ -45,6 +46,8 @@ void VulkanEngine::init()
|
|||
init_swapchain();
|
||||
init_commands();
|
||||
init_sync_structures();
|
||||
init_descriptors();
|
||||
init_pipelines();
|
||||
|
||||
//everything went fine
|
||||
_isInitialized = true;
|
||||
|
|
@ -358,11 +361,100 @@ void VulkanEngine::init_sync_structures() {
|
|||
|
||||
void VulkanEngine::draw_background(VkCommandBuffer cmd)
|
||||
{
|
||||
VkClearColorValue clearValue;
|
||||
float flash = std::abs(std::sin(float(_frameNumber) / 120.0f));
|
||||
clearValue = { { 0.0f, 0.0f, flash, 1.0f} };
|
||||
// bind the gradient drawing compute pipeline
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, _gradientPipeline);
|
||||
|
||||
VkImageSubresourceRange clearRange = vkinit::image_subresource_range(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
// bind the descriptor set containing the draw image for the compute pipeline
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, _gradientPipelineLayout, 0, 1, &_drawImageDescriptors, 0, nullptr);
|
||||
|
||||
vkCmdClearColorImage(cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &clearRange);
|
||||
// execute the compute pipeline dispatch. We are using 16x16 workgroup size so we need to divide by it
|
||||
vkCmdDispatch(cmd, std::ceil(_drawExtent.width / 16.0), std::ceil(_drawExtent.height / 16.0), 1);
|
||||
}
|
||||
|
||||
|
||||
void VulkanEngine::init_descriptors() {
|
||||
std::vector<DescriptorAllocator::PoolSizeRatio> sizes =
|
||||
{
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 }
|
||||
};
|
||||
|
||||
globalDescriptorAllocator.init_pool(_device, 10, sizes);
|
||||
|
||||
// make the descriptor set layout for our compute draw
|
||||
{
|
||||
DescriptorLayoutBuilder builder;
|
||||
builder.add_binding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
_drawImageDescriptorLayout = builder.build(_device, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
}
|
||||
|
||||
// other code
|
||||
//allocate a descriptor set for our draw image
|
||||
_drawImageDescriptors = globalDescriptorAllocator.allocate(_device,_drawImageDescriptorLayout);
|
||||
|
||||
VkDescriptorImageInfo imgInfo{};
|
||||
imgInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgInfo.imageView = _drawImage.imageView;
|
||||
|
||||
VkWriteDescriptorSet drawImageWrite = {};
|
||||
drawImageWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
drawImageWrite.pNext = nullptr;
|
||||
|
||||
drawImageWrite.dstBinding = 0;
|
||||
drawImageWrite.dstSet = _drawImageDescriptors;
|
||||
drawImageWrite.descriptorCount = 1;
|
||||
drawImageWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
drawImageWrite.pImageInfo = &imgInfo;
|
||||
|
||||
vkUpdateDescriptorSets(_device, 1, &drawImageWrite, 0, nullptr);
|
||||
|
||||
//make sure both the descriptor allocator and the new layout get cleaned up properly
|
||||
_mainDeletionQueue.push_function([&]() {
|
||||
globalDescriptorAllocator.destroy_pool(_device);
|
||||
|
||||
vkDestroyDescriptorSetLayout(_device, _drawImageDescriptorLayout, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
void VulkanEngine::init_pipelines()
|
||||
{
|
||||
init_background_pipelines();
|
||||
}
|
||||
|
||||
void VulkanEngine::init_background_pipelines()
|
||||
{
|
||||
VkPipelineLayoutCreateInfo computeLayout{};
|
||||
computeLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
computeLayout.pNext = nullptr;
|
||||
computeLayout.pSetLayouts = &_drawImageDescriptorLayout;
|
||||
computeLayout.setLayoutCount = 1;
|
||||
|
||||
VK_CHECK(vkCreatePipelineLayout(_device, &computeLayout, nullptr, &_gradientPipelineLayout));
|
||||
|
||||
VkShaderModule computeDrawShader;
|
||||
|
||||
if(!vkutil::load_shader_module("gradient.comp.spv", _device, &computeDrawShader)) {
|
||||
std::println("Error when building compute shader");
|
||||
}
|
||||
|
||||
VkPipelineShaderStageCreateInfo stageinfo{};
|
||||
stageinfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
stageinfo.pNext = nullptr;
|
||||
stageinfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
stageinfo.module = computeDrawShader;
|
||||
stageinfo.pName = "main";
|
||||
|
||||
VkComputePipelineCreateInfo computePipelineCreateInfo{};
|
||||
computePipelineCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
computePipelineCreateInfo.pNext = nullptr;
|
||||
computePipelineCreateInfo.layout = _gradientPipelineLayout;
|
||||
computePipelineCreateInfo.stage = stageinfo;
|
||||
|
||||
VK_CHECK(vkCreateComputePipelines(_device,VK_NULL_HANDLE,1, &computePipelineCreateInfo, nullptr, &_gradientPipeline));
|
||||
|
||||
vkDestroyShaderModule(_device, computeDrawShader, nullptr);
|
||||
|
||||
_mainDeletionQueue.push_function([&]() {
|
||||
vkDestroyPipelineLayout(_device, _gradientPipelineLayout, nullptr);
|
||||
vkDestroyPipeline(_device, _gradientPipeline, nullptr);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
11
vk_engine.h
11
vk_engine.h
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <vk_types.h>
|
||||
#include <vk_descriptors.h>
|
||||
|
||||
struct DeletionQueue {
|
||||
std::deque<std::function<void()>> deletors;
|
||||
|
|
@ -35,6 +36,13 @@ constexpr unsigned int FRAME_OVERLAP=2;
|
|||
|
||||
class VulkanEngine {
|
||||
public:
|
||||
VkPipeline _gradientPipeline;
|
||||
VkPipelineLayout _gradientPipelineLayout;
|
||||
|
||||
DescriptorAllocator globalDescriptorAllocator;
|
||||
VkDescriptorSet _drawImageDescriptors;
|
||||
VkDescriptorSetLayout _drawImageDescriptorLayout;
|
||||
|
||||
// device selection
|
||||
VkInstance _instance;
|
||||
VkDebugUtilsMessengerEXT _debug_messenger;
|
||||
|
|
@ -93,6 +101,9 @@ private:
|
|||
void init_swapchain();
|
||||
void init_commands();
|
||||
void init_sync_structures();
|
||||
void init_descriptors();
|
||||
void init_pipelines();
|
||||
void init_background_pipelines();
|
||||
|
||||
void create_swapchain(uint32_t width, uint32_t height);
|
||||
void destroy_swapchain();
|
||||
|
|
|
|||
42
vk_pipelines.cpp
Normal file
42
vk_pipelines.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#include "vk_pipelines.h"
|
||||
#include <fstream>
|
||||
#include "vk_initializers.h"
|
||||
#include <print>
|
||||
|
||||
bool vkutil::load_shader_module(const char* filePath,
|
||||
VkDevice device,
|
||||
VkShaderModule* outShaderModule)
|
||||
{
|
||||
std::ifstream file(filePath, std::ios::ate | std::ios::binary);
|
||||
|
||||
if(!file.is_open()) {
|
||||
std::println("failed to open file: {}", filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t fileSize = (size_t)file.tellg();
|
||||
|
||||
//spirv expects the buffer to uint32
|
||||
std::vector<uint32_t> buffer(fileSize / sizeof(uint32_t));
|
||||
file.seekg(0);
|
||||
file.read((char*)buffer.data(), fileSize);
|
||||
|
||||
file.close();
|
||||
|
||||
VkShaderModuleCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.pNext = nullptr;
|
||||
|
||||
// codeSize has to be in bytes
|
||||
createInfo.codeSize = buffer.size() * sizeof(uint32_t);
|
||||
createInfo.pCode = buffer.data();
|
||||
|
||||
VkShaderModule shaderModule;
|
||||
if(vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
|
||||
std::println("Error after vkCreateShaderModule");
|
||||
return false;
|
||||
}
|
||||
|
||||
*outShaderModule = shaderModule;
|
||||
return true;
|
||||
}
|
||||
9
vk_pipelines.h
Normal file
9
vk_pipelines.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "vk_types.h"
|
||||
|
||||
namespace vkutil {
|
||||
bool load_shader_module(const char* filePath,
|
||||
VkDevice device,
|
||||
VkShaderModule* outShaderModule);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue