This commit is contained in:
Martin Slachta
2026-07-18 14:31:15 +02:00
commit a04f0dc262
3343 changed files with 1140208 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
#include <stdexcept>
#include "FramebufferBuilder.hpp"
Framebuffer::Framebuffer(VkFramebuffer framebuffer) :
framebuffer(framebuffer) {
}
Framebuffer::Framebuffer(const Gpu* gpu, const VkRenderPass renderpass, const VkExtent2D extent,
const std::vector<VkImageView>& attachments) {
VkFramebufferCreateInfo framebufferInfo = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = renderpass,
.attachmentCount = (uint32_t)attachments.size(),
.pAttachments = attachments.data(),
.width = extent.width,
.height = extent.height,
.layers = 1,
};
if(vkCreateFramebuffer(gpu->dev(), &framebufferInfo, nullptr, &framebuffer)) {
throw std::runtime_error("Failed to create framebuffer");
}
}
FramebufferBuilder::FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent) :
FramebufferBuilder(renderpass, extent, 4) {
}
FramebufferBuilder::FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent, uint32_t numAttachments) :
m_renderpass(renderpass), m_extent(extent), m_attachments(numAttachments) {
}
FramebufferBuilder::FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent, std::vector<ImageView> attachments) :
m_renderpass(renderpass), m_extent(extent), m_attachments(attachments) {
}
Framebuffer FramebufferBuilder::build(const Gpu* gpu) {
VkFramebufferCreateInfo framebufferInfo = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = m_renderpass,
.attachmentCount = (uint32_t)m_attachments.size(),
.pAttachments = (VkImageView*)m_attachments.data(),
.width = m_extent.width,
.height = m_extent.height,
.layers = 1,
};
VkFramebuffer framebuffer;
if(vkCreateFramebuffer(gpu->dev(), &framebufferInfo, nullptr, &framebuffer)) {
throw std::runtime_error("Failed to create framebuffer");
}
return {framebuffer};
}
FramebufferBuilder &FramebufferBuilder::set_attachment(uint32_t idx, VkImageView view) {
m_attachments[idx] = ImageView(view);
return *this;
}
+339
View File
@@ -0,0 +1,339 @@
#include "Gpu.hpp"
#include "resources/DefaultAllocator.h"
#include "result.hpp"
#include "result.hpp"
#include <vector>
#include <iostream>
#include <memory>
#include <cstring>
static const char *DEVICE_EXTENSIONS[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME,
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME,
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME
};
static const int NUM_DEVICE_EXTENSIONS = sizeof(DEVICE_EXTENSIONS) / sizeof(*DEVICE_EXTENSIONS);
#if VK_LAYERS_ENABLE
static const char* LAYERS[] = {
"VK_LAYER_KHRONOS_validation"
};
static const int NUM_LAYERS = sizeof(LAYERS) / sizeof(*LAYERS);
#else
#define LAYERS nullptr
static const int NUM_LAYERS = 0;
#endif
int32_t get_graphics_score(VkQueueFamilyProperties props) {
bool isSupported = props.queueFlags | VK_QUEUE_GRAPHICS_BIT;
return isSupported;
}
int32_t get_transfer_score(VkQueueFamilyProperties props) {
bool isSupported = props.queueFlags | VK_QUEUE_TRANSFER_BIT;
bool isDedicated = props.queueFlags & ~(VK_QUEUE_GRAPHICS_BIT);
return (isDedicated << 1) * isSupported;
}
int32_t get_present_score(VkQueueFamilyProperties props, bool isPresentSupported) {
return isPresentSupported;
}
std::vector<int32_t> Gpu::get_queues(std::optional<Surface*> surface) {
uint32_t numQueues = 0;
vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &numQueues, 0x0);
auto properties = std::vector<VkQueueFamilyProperties>(numQueues);
vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &numQueues,
properties.data());
if(numQueues == 0) {
throw std::runtime_error("Failed to find any queue family");
}
int32_t graphicsQueue = -1;
int32_t transferQueue = -1;
int32_t transferScore = 0;
int32_t presentQueue = -1;
int32_t presentScore = 0;
uint32_t i = 0;
for(auto& prop : properties) {
VkBool32 isPresentSupported = false;
if(surface.has_value()) {
vkGetPhysicalDeviceSurfaceSupportKHR(m_gpu, i, surface.value()->surface(), &isPresentSupported);
} else {
isPresentSupported = true;
}
bool isTaken = false;
int32_t iterGraphicsScore = get_graphics_score(prop) * (graphicsQueue == -1);
int32_t iterTransferScore = get_transfer_score(prop);
int32_t iterPresentScore = get_present_score(prop, isPresentSupported);
if(iterGraphicsScore > 0) {
graphicsQueue = i;
isTaken = true;
}
if((iterTransferScore | (!isTaken << 2)) > transferScore) {
transferQueue = i;
transferScore = (iterTransferScore & (!isTaken << 2));
isTaken = true;
}
if((iterPresentScore | (!isTaken << 2)) > presentScore) {
presentQueue = i;
presentScore = (iterPresentScore & (!isTaken << 2));
isTaken = true;
}
}
return { graphicsQueue, transferQueue, presentQueue };
}
ResultCode Gpu::create_logical_device(std::optional<Surface*> supportedSurface) {
auto queueFamilies = get_queues(supportedSurface);
std::vector<VkDeviceQueueCreateInfo> queueInfos(queueFamilies.size());
float priority = 1.0f;
int32_t x = 0;
for(int32_t i = 0; i < queueFamilies.size(); i++) {
bool isDuplicate = false;
for(int32_t y = i - 1; y >= 0; y--) {
if(queueFamilies[i] == queueFamilies[y]) {
isDuplicate = true;
break;
}
}
if(isDuplicate) continue;
queueInfos[x] = {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = (uint32_t)queueFamilies[x],
.queueCount = 1,
.pQueuePriorities = &priority
};
x++;
}
VkPhysicalDeviceFeatures gpuFeatures = { };
vkGetPhysicalDeviceFeatures(m_gpu, &gpuFeatures);
VkPhysicalDeviceSynchronization2Features syncFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
.pNext = nullptr,
.synchronization2 = true,
};
VkPhysicalDeviceRobustness2FeaturesEXT robustness = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
.pNext = &syncFeatures,
.robustBufferAccess2 = true,
.robustImageAccess2 = true,
.nullDescriptor = true
};
VkPhysicalDeviceCoherentMemoryFeaturesAMD coherentMemoryFeatures {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD,
.pNext = &robustness,
.deviceCoherentMemory = true
};
VkDeviceCreateInfo deviceInfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = &coherentMemoryFeatures,
.queueCreateInfoCount = (uint32_t)x,
.pQueueCreateInfos = queueInfos.data(),
.enabledLayerCount = NUM_LAYERS,
.ppEnabledLayerNames = LAYERS,
.enabledExtensionCount = NUM_DEVICE_EXTENSIONS,
.ppEnabledExtensionNames = DEVICE_EXTENSIONS,
.pEnabledFeatures = &gpuFeatures,
};
if(vkCreateDevice(m_gpu, &deviceInfo, NULL, &m_dev)) {
return RESULT_GPU_DEVICE_CREATION_FAILED;
}
VkCommandPoolCreateInfo poolInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
.queueFamilyIndex = (uint32_t)queueFamilies[0],
};
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_graphicsCommandPool)) {
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
}
vkGetDeviceQueue(m_dev, queueFamilies[0], 0, &m_graphicsQueue);
if(queueFamilies[0] == queueFamilies[1]) {
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_transferCommandPool)) {
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
}
m_transferQueue = m_graphicsQueue;
} else {
poolInfo.queueFamilyIndex = (uint32_t)queueFamilies[1];
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_transferCommandPool)) {
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
}
vkGetDeviceQueue(m_dev, queueFamilies[1], 0, &m_transferQueue);
}
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_presentCommandPool)) {
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
}
if(queueFamilies[0] == queueFamilies[2]) {
m_presentQueue = m_graphicsQueue;
} else if(queueFamilies[1] == queueFamilies[2]) {
m_presentQueue = m_transferQueue;
} if(queueFamilies[2] != queueFamilies[1] &&
queueFamilies[2] != queueFamilies[0]) {
vkGetDeviceQueue(m_dev, queueFamilies[2], 0, &m_presentQueue);
}
m_graphicsQueueIdx = queueFamilies[0];
m_transferQueueIdx = queueFamilies[1];
m_presentQueueIdx = queueFamilies[2];
return RESULT_OK;
}
ResultCode Gpu::choose_gpu(VkPhysicalDevice *pOut) {
uint32_t numDevices = 0;
vkEnumeratePhysicalDevices(m_instance->instance(), &numDevices, nullptr);
if(numDevices == 0) {
throw std::runtime_error("No GPU supporting Vulkan was found. Try installing Vulkan drivers. Remember that some GPUs does not need to support Vulkan.");
}
auto devices = std::vector<VkPhysicalDevice>(numDevices);
vkEnumeratePhysicalDevices(m_instance->instance(), &numDevices, devices.data());
VkPhysicalDevice chosen = VK_NULL_HANDLE;
for(auto& device : devices) {
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(device, &props);
uint32_t numExtensions;
vkEnumerateDeviceExtensionProperties(device, nullptr, &numExtensions, nullptr);
std::vector<VkExtensionProperties> extensions(numExtensions);
vkEnumerateDeviceExtensionProperties(device, nullptr, &numExtensions, extensions.data());
for(int x = 0; x < NUM_DEVICE_EXTENSIONS; x++) {
bool isFound = false;
for(int y = 0; y < numExtensions; y++) {
if(!strcmp(extensions[y].extensionName, DEVICE_EXTENSIONS[x])) {
isFound = true;
break;
}
}
if(!isFound) {
lft::log::fail("Device %s does not support required device extension: (%s)",
props.deviceName, DEVICE_EXTENSIONS[x]);
continue;
}
}
chosen = device;
}
if(chosen == VK_NULL_HANDLE) {
throw std::runtime_error("No GPU supporting all required features was found. Try updating your graphics card driver. This however might not help on older devices.");
}
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(chosen, &props);
lft::log::info("Selected GPU: (%s)", props.deviceName);
*pOut = chosen;
return RESULT_OK;
}
ResultCode Gpu::create_descriptor_pool() {
VkDescriptorPoolSize poolSizes[] =
{
{
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1000,
}, {
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1000
}, {
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1000
}
};
VkDescriptorPoolCreateInfo poolInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = 1000,
.poolSizeCount = sizeof(poolSizes) / sizeof(*poolSizes),
.pPoolSizes = poolSizes,
};
if (vkCreateDescriptorPool(dev(), &poolInfo, nullptr, &m_descriptorPool)) {
return RESULT_GPU_DESCRIPTOR_POOL_CREATION_FAILED;
}
return RESULT_OK;
}
Gpu::Gpu(const Instance* instance, std::optional<Surface*> supportedSurface) :
m_instance(instance), m_pAllocator(nullptr) {
if(choose_gpu(&m_gpu)) {
throw std::runtime_error("Failed to choose gpu");
}
if(create_logical_device(supportedSurface)) {
throw std::runtime_error("Failed to create logical device");
}
if(create_descriptor_pool()) {
throw std::runtime_error("Failed to create descriptor pool");
}
m_pAllocator = std::make_unique<DefaultAllocator>(DefaultAllocator(this));
}
Gpu::~Gpu() {
vkDestroyDescriptorPool(m_dev, m_descriptorPool, nullptr);
vkDestroyCommandPool(m_dev, m_graphicsCommandPool, nullptr);
vkDestroyCommandPool(m_dev, m_transferCommandPool, nullptr);
vkDestroyCommandPool(m_dev, m_presentCommandPool, nullptr);
vkDestroyDevice(m_dev, nullptr);
}
void Gpu::enqueue_present(VkPresentInfoKHR *pPresentInfo) const {
if(vkQueuePresentKHR(m_presentQueue, pPresentInfo)) {
throw std::runtime_error("Failed to present");
}
}
void Gpu::enqueue_graphics(VkSubmitInfo2 *pSubmitInfo, VkFence fence) const {
if(vkQueueSubmit2KHR(m_graphicsQueue, 1, pSubmitInfo, fence)) {
throw std::runtime_error("Failed to submit to graphics queue");
}
}
void Gpu::enqueue_transfer(VkSubmitInfo *pSubmitInfo, VkFence fence) const {
vkQueueSubmit(m_transferQueue, 1, pSubmitInfo, fence);
}
+172
View File
@@ -0,0 +1,172 @@
#include <iostream>
#include <numeric>
#include <sstream>
#include <cstring>
#include <stdexcept>
#include <iterator>
#include "Instance.hpp"
#include "result.hpp"
#include "debug/Debug.hpp"
#if LOFT_DEBUG && VK_LAYERS_ENABLE
static const char* LAYERS[] = {
"VK_LAYER_KHRONOS_validation"
};
static const int NUM_LAYERS = sizeof(LAYERS) / sizeof(*LAYERS);
#else
#define LAYERS nullptr
static const int NUM_LAYERS = 0;
#endif
static const char* EXTENSIONS[] = {
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
};
static const int NUM_EXTENSIONS = sizeof(EXTENSIONS) / sizeof(*EXTENSIONS);
static const char *DEVICE_EXTENSIONS[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
};
static const int NUM_DEVICE_EXTENSIONS = sizeof(DEVICE_EXTENSIONS) / sizeof(*DEVICE_EXTENSIONS);
static bool IS_INITIALIZED = false;
lft::dbg::lft_log_callback g_logCallback = nullptr;
VkBool32
vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* pData,
void *pUserData) {
if(g_logCallback != nullptr) {
g_logCallback(lft::dbg::LogMessageSeverity::error,
lft::dbg::LogMessageType::general,
pData->pMessage, {});
} else {
std::cout << pData->pMessage << std::endl;
}
return VK_FALSE;
}
std::string get_unsupported_layers_error_mesg(std::vector<std::string> unsupported_layers) {
std::stringstream str;
std::copy(unsupported_layers.begin(), unsupported_layers.end(),
std::ostream_iterator<std::string>(str, "\n"));
return "Unsupported layers: \n" + str.str();
}
std::string get_unsupported_extensions_error_mesg(std::vector<std::string> unsupported_extensions) {
std::stringstream str;
std::copy(unsupported_extensions.begin(), unsupported_extensions.end(),
std::ostream_iterator<std::string>(str, "\n"));
return "Unsupported extensions: \n" + str.str();
}
std::vector<char*> transform_strings_to_c_strings(std::vector<std::string> strings) {
std::vector<char*> result(strings.size());
std::transform(strings.begin(), strings.end(),
result.begin(),
[](const std::string& str) {
return strndup(str.c_str(), str.length());
});
return result;
}
Instance::Instance(const std::string applicationName,
const std::string engineName,
std::vector<std::string> extensions,
std::vector<std::string> layers,
lft::dbg::lft_log_callback callback) {
if(volkInitialize()) {
throw std::runtime_error("Failed to initialize volk");
}
// check unsupported extensions
auto unsupportedExtensions = check_extensions(extensions);
auto unsupportedLayers = find_unsupported_layers(layers);
if(!unsupportedExtensions.empty()) {
throw std::runtime_error(get_unsupported_extensions_error_mesg(unsupportedExtensions));
}
if(!unsupportedLayers.empty()) {
throw std::runtime_error(get_unsupported_layers_error_mesg(unsupportedLayers));
}
// EXPECT(!unsupportedExtensions.empty(), "Unsupported extensions");
if(callback) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
VkApplicationInfo appInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pApplicationName = "test", // strdup(applicationName.c_str()),
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "test",// strdup(engineName.c_str()),
.apiVersion = VK_API_VERSION_1_1
};
VkDebugUtilsMessengerCreateInfoEXT dbgInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.pNext = nullptr,
.flags = 0,
.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
.pfnUserCallback = vk_dbg_callback,
.pUserData = nullptr
};
std::vector<char*> extension_cstrs = transform_strings_to_c_strings(extensions);
std::vector<char*> layer_cstrs = transform_strings_to_c_strings(layers);
VkInstanceCreateInfo instanceInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
#if LOFT_DEBUG
.pNext = &dbgInfo,
#endif
.pApplicationInfo = &appInfo,
#if LOFT_DEBUG
.enabledLayerCount = (uint32_t)layer_cstrs.size(),
.ppEnabledLayerNames = layer_cstrs.data(),
#endif
.enabledExtensionCount = (uint32_t)extension_cstrs.size(),
.ppEnabledExtensionNames = extension_cstrs.data(),
};
if(callback != nullptr) {
g_logCallback = callback;
}
EXPECT(vkCreateInstance(&instanceInfo, nullptr, &m_instance) == VK_SUCCESS,
"Failed to create vulkan instance");
volkLoadInstance(m_instance);
lft::log::warn("Instance created successfully");
// cleanup
for(char* str : extension_cstrs) {
delete [] str;
}
for(char* str : layer_cstrs) {
delete [] str;
}
IS_INITIALIZED = true;
}
+55
View File
@@ -0,0 +1,55 @@
#include "Recording.hpp"
namespace lft {
RecordingBindPoint::RecordingBindPoint(
const Recording* recording,
const Pipeline pipeline,
VkPipelineBindPoint bind_point
) : m_recording(recording),
m_pipeline(pipeline),
m_bind_point(bind_point) {
vkCmdBindPipeline(m_recording->cmdbuf(), bind_point, pipeline.pipeline());
}
const RecordingBindPoint& RecordingBindPoint::bind_descriptor_set(
uint32_t set,
VkDescriptorSet descriptor_set
) const {
vkCmdBindDescriptorSets(m_recording->cmdbuf(),
m_bind_point,
m_pipeline.pipeline_layout(),
set,
1, &descriptor_set,
0, nullptr);
return *this;
}
const RecordingBindPoint& RecordingBindPoint::bind_descriptor_sets(
uint32_t first_set,
const std::vector<VkDescriptorSet>& descriptor_sets
) const {
vkCmdBindDescriptorSets(m_recording->cmdbuf(),
m_bind_point,
m_pipeline.pipeline_layout(),
first_set,
descriptor_sets.size(), descriptor_sets.data(),
0, nullptr);
return *this;
}
const RecordingBindPoint& RecordingBindPoint::push_constants(
VkShaderStageFlags shader_stages,
uint32_t offset, uint32_t size, const void* data) const {
vkCmdPushConstants(m_recording->cmdbuf(), m_pipeline.pipeline_layout(), shader_stages,
offset, size, data);
return *this;
}
}
+23
View File
@@ -0,0 +1,23 @@
#include <stdexcept>
#include "io/file.hpp"
#include "io/ShaderBinary.h"
ShaderBinary io::file::read_binary(const std::string& path) {
FILE *f = fopen(path.c_str(), "rb");
if(!f) {
throw std::runtime_error("Failed to open file");
}
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
std::vector<uint32_t> data(size + 1);
fseek(f, 0, SEEK_SET);
fread(data.data(), 4, size, f);
fclose(f);
data[size] = '\0';
return ShaderBinary(data);
}
+19
View File
@@ -0,0 +1,19 @@
//
// Created by martin on 4/5/24.
//
#include "resources/Buffer.hpp"
#include "Gpu.hpp"
void Buffer::set_debug_name(const Gpu* gpu, const std::string& name) const {
#if LOFT_DEBUG && VK_EXT_debug_utils
VkDebugUtilsObjectNameInfoEXT nameInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_BUFFER,
.objectHandle = (uint64_t)buf,
.pObjectName = name.c_str(),
};
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
#endif
}
@@ -0,0 +1,147 @@
#include "resources/BufferBusWriter.h"
#include <string.h>
#include <volk.h>
#include <algorithm>
int
BufferBusWriter::create_staging_buffer(size_t size) {
BufferCreateInfo stagingBufferInfo = {
.size = size,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.isExclusive = true
};
MemoryAllocationInfo memoryAllocationInfo = {
.usage = MEMORY_USAGE_AUTO_PREFER_HOST,
.requiredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
};
m_gpu->memory()->create_buffer(&stagingBufferInfo, &memoryAllocationInfo,
&m_stagingBuffer);
return 0;
}
int
BufferBusWriter::create_staging_command_buffer() {
VkCommandBufferAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = m_gpu->transfer_command_pool(),
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
vkAllocateCommandBuffers(m_gpu->dev(), &allocInfo, &m_stagingCommandBuffer);
return 0;
}
BufferBusWriter::BufferBusWriter(const Gpu* gpu, size_t size) :
m_gpu(gpu), m_unflushedSize(0), m_busSize(size), m_numWrites(0) {
create_staging_buffer(size);
create_staging_command_buffer();
m_gpu->memory()->map(m_stagingBuffer.allocation, &m_pData);
VkFenceCreateInfo fenceInfo = {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = VK_FENCE_CREATE_SIGNALED_BIT
};
vkCreateFence(m_gpu->dev(), &fenceInfo, nullptr, &m_fence);
}
void BufferBusWriter::write(Buffer* pTarget, void *pData, size_t offset, size_t size) {
char* pUploadData = (char*)pData;
while(size > 0) {
size_t uploadSize = std::min(m_busSize - m_unflushedSize, size);
memcpy((char*)m_pData + m_unflushedSize, pUploadData, uploadSize);
pUploadData += uploadSize;
VkBufferCopy write = {
.srcOffset = m_unflushedSize,
.dstOffset = offset,
.size = uploadSize,
};
m_numWrites++;
if(m_writes.size() <= m_numWrites) {
m_writes.resize(m_numWrites * 2);
}
m_writes[m_numWrites - 1] = std::pair(pTarget, write);
m_unflushedSize += uploadSize;
offset += uploadSize;
size -= uploadSize;
if(m_busSize - m_unflushedSize == 0) {
flush();
// wait, because we are gonna overwrite the data
wait();
}
}
}
void BufferBusWriter::flush() {
if(m_numWrites == 0) {
m_unflushedSize = 0;
return;
}
m_gpu->memory()->flush(m_stagingBuffer.allocation, 0, m_unflushedSize);
wait();
vkResetFences(m_gpu->dev(), 1, &m_fence);
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
vkBeginCommandBuffer(m_stagingCommandBuffer, &beginInfo);
for(uint32_t i = 0; i < m_numWrites; i++) {
vkCmdCopyBuffer(m_stagingCommandBuffer, m_stagingBuffer.buf, m_writes[i].first->buf,
1, &m_writes[i].second);
}
vkEndCommandBuffer(m_stagingCommandBuffer);
VkSubmitInfo submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &m_stagingCommandBuffer,
};
m_gpu->enqueue_transfer(&submitInfo, m_fence);
m_unflushedSize = 0;
m_numWrites = 0;
}
BufferBusWriter::~BufferBusWriter() {
flush();
wait();
m_gpu->memory()->destroy_buffer(&m_stagingBuffer);
}
void BufferBusWriter::wait() {
vkWaitForFences(m_gpu->dev(), 1, &m_fence, VK_TRUE, UINT64_MAX);
// vkDeviceWaitIdle(m_pGpu->dev());
}
@@ -0,0 +1,101 @@
#include "resources/DefaultAllocator.h"
#define VMA_IMPLEMENTATION
#include "vk_mem_alloc.h"
#include "Gpu.hpp"
DefaultAllocator::DefaultAllocator(Gpu *pGpu) {
VmaVulkanFunctions vma_vulkan_func{};
vma_vulkan_func.vkAllocateMemory = vkAllocateMemory;
vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory;
vma_vulkan_func.vkBindImageMemory = vkBindImageMemory;
vma_vulkan_func.vkCreateBuffer = vkCreateBuffer;
vma_vulkan_func.vkCreateImage = vkCreateImage;
vma_vulkan_func.vkDestroyBuffer = vkDestroyBuffer;
vma_vulkan_func.vkDestroyImage = vkDestroyImage;
vma_vulkan_func.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
vma_vulkan_func.vkFreeMemory = vkFreeMemory;
vma_vulkan_func.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
vma_vulkan_func.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
vma_vulkan_func.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
vma_vulkan_func.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
vma_vulkan_func.vkMapMemory = vkMapMemory;
vma_vulkan_func.vkUnmapMemory = vkUnmapMemory;
vma_vulkan_func.vkCmdCopyBuffer = vkCmdCopyBuffer;
vma_vulkan_func.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
vma_vulkan_func.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
VmaAllocatorCreateInfo allocatorCreateInfo = {
.physicalDevice = pGpu->gpu(),
.device = pGpu->dev(),
.pVulkanFunctions = &vma_vulkan_func,
.instance = pGpu->instance()->instance(),
.vulkanApiVersion = VK_API_VERSION_1_0,
};
vmaCreateAllocator(&allocatorCreateInfo, &m_allocator);
}
VmaMemoryUsage get_vma_memory_usage(MemoryUsage memoryUsage) {
switch(memoryUsage) {
case MEMORY_USAGE_AUTO:
return VMA_MEMORY_USAGE_AUTO;
case MEMORY_USAGE_AUTO_PREFER_DEVICE:
return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
case MEMORY_USAGE_AUTO_PREFER_HOST:
return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
default:
return VMA_MEMORY_USAGE_AUTO;
}
}
int DefaultAllocator::create_buffer(BufferCreateInfo *pBufferInfo, MemoryAllocationInfo *pAllocInfo, Buffer *pOut) {
VkBufferCreateInfo bufferInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = pBufferInfo->size,
.usage = pBufferInfo->usage,
.sharingMode = pBufferInfo->isExclusive ? VK_SHARING_MODE_EXCLUSIVE : VK_SHARING_MODE_CONCURRENT
};
VmaAllocationCreateInfo allocInfo = {
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
.usage = get_vma_memory_usage(pAllocInfo->usage),
.requiredFlags = pAllocInfo->requiredFlags,
};
vmaCreateBuffer(m_allocator, &bufferInfo, &allocInfo, &pOut->buf, &pOut->allocation.allocation, nullptr);
return 0;
}
int DefaultAllocator::create_image(ImageCreateInfo *pImageInfo, MemoryAllocationInfo *pAllocInfo, Image *pOut) {
VkImageCreateInfo imageInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = pImageInfo->format,
.extent = {
pImageInfo->extent.width,
pImageInfo->extent.height,
1,
},
.mipLevels = pImageInfo->mipLevels,
.arrayLayers = pImageInfo->arrayLayers,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = pImageInfo->usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
};
VmaAllocationCreateInfo allocInfo = {};
allocInfo.usage = get_vma_memory_usage(pAllocInfo->usage);
allocInfo.requiredFlags = pAllocInfo->requiredFlags;
vmaCreateImage(m_allocator, &imageInfo, &allocInfo, &pOut->img, &pOut->allocation.allocation, nullptr);
pOut->m_layer_count = imageInfo.arrayLayers;
pOut->m_level_count = imageInfo.mipLevels;
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
#include "resources/Image.hpp"
#include "Gpu.hpp"
ImageView
Image::create_view(const Gpu* gpu, VkFormat format,
VkImageSubresourceRange subresource) {
VkImageViewCreateInfo viewInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = img,
.viewType = subresource.layerCount == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY,
.format = format,
.components = {
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY
},
.subresourceRange = subresource
};
VkImageView result = VK_NULL_HANDLE;
vkCreateImageView(gpu->dev(), &viewInfo, nullptr, &result);
return {result};
}
void Image::set_debug_name(const Gpu* gpu, const std::string& name) const {
#if LOFT_DEBUG
VkDebugUtilsObjectNameInfoEXT nameInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_IMAGE,
.objectHandle = (uint64_t)img,
.pObjectName = name.c_str(),
};
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
#endif
}
@@ -0,0 +1,161 @@
#include "resources/ImageBusWriter.h"
#include <string.h>
#include <volk.h>
#include <cmath>
int ImageBusWriter::create_staging_buffer(size_t size) {
BufferCreateInfo stagingBufferInfo = {
.size = size,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.isExclusive = true
};
MemoryAllocationInfo memoryAllocationInfo = {
.usage = MEMORY_USAGE_AUTO_PREFER_HOST
};
m_gpu->memory()->create_buffer(&stagingBufferInfo, &memoryAllocationInfo,
&m_stagingBuffer);
m_gpu->memory()->map(m_stagingBuffer.allocation, &m_pMappedData);
return 0;
}
int ImageBusWriter::create_staging_command_buffer() {
VkCommandBufferAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = m_gpu->transfer_command_pool(),
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
vkAllocateCommandBuffers(m_gpu->dev(), &allocInfo,
&m_stagingCommandBuffer);
return 0;
}
int ImageBusWriter::create_fence() {
VkFenceCreateInfo fenceInfo = {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = VK_FENCE_CREATE_SIGNALED_BIT
};
vkCreateFence(m_gpu->dev(), &fenceInfo, nullptr, &m_fence);
return 0;
}
ImageBusWriter::ImageBusWriter(const Gpu* gpu, Image *pTarget,
VkExtent2D extent, uint32_t formatSize,
size_t maxWrites) :
m_gpu(gpu),
m_pTarget(pTarget),
m_writes(maxWrites),
m_numWrites(0),
m_formatSize(formatSize),
m_imageSize(extent.width * extent.height * formatSize) {
create_staging_buffer(extent.width * extent.height * formatSize);
create_staging_command_buffer();
create_fence();
}
void ImageBusWriter::write(VkBufferImageCopy write, void *pData, size_t size) {
write.bufferOffset = m_numWrites * m_imageSize;
m_writes[m_numWrites] = write;
memcpy((char*)m_pMappedData + m_numWrites * m_imageSize, pData, size);
m_numWrites++;
if(m_numWrites >= m_writes.size()) {
flush();
}
}
void ImageBusWriter::flush() {
if(m_numWrites == 0) return;
vkWaitForFences(m_gpu->dev(), 1, &m_fence, VK_TRUE, UINT64_MAX);
vkResetFences(m_gpu->dev(), 1, &m_fence);
m_gpu->memory()->flush(m_stagingBuffer.allocation, 0,
m_imageSize * m_numWrites);
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
};
vkBeginCommandBuffer(m_stagingCommandBuffer, &beginInfo);
VkImageMemoryBarrier barrierInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = m_pTarget->img,
};
std::vector<VkImageMemoryBarrier> barriers(m_writes.size(), barrierInfo);
uint32_t i = 0;
for(auto& write : m_writes) {
barriers[i++].subresourceRange = {
.aspectMask = write.imageSubresource.aspectMask,
.baseMipLevel = write.imageSubresource.mipLevel,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = write.imageSubresource.baseArrayLayer,
.layerCount = write.imageSubresource.layerCount,
};
}
vkCmdPipelineBarrier(m_stagingCommandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
0, nullptr,
barriers.size(), barriers.data());
vkCmdCopyBufferToImage(
m_stagingCommandBuffer,
m_stagingBuffer.buf,
m_pTarget->img,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
m_numWrites,
m_writes.data()
);
for(auto& barrier : barriers) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
vkCmdPipelineBarrier(m_stagingCommandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
0, nullptr,
barriers.size(), barriers.data());
vkEndCommandBuffer(m_stagingCommandBuffer);
VkSubmitInfo submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &m_stagingCommandBuffer
};
m_gpu->enqueue_transfer(&submitInfo, m_fence);
m_numWrites = 0;
}
+18
View File
@@ -0,0 +1,18 @@
#include "resources/ImageView.hpp"
#include "Gpu.hpp"
void ImageView::set_debug_name(const std::shared_ptr<const Gpu>& gpu, const std::string &name) const {
#if LOFT_DEBUG
VkDebugUtilsObjectNameInfoEXT nameInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_IMAGE_VIEW,
.objectHandle = (uint64_t)view,
.pObjectName = name.c_str(),
};
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
#endif
}
@@ -0,0 +1,181 @@
#include "resources/MipmapGenerator.h"
#include "Gpu.hpp"
#include "Recording.hpp"
#include "TransferTaskPipeline.hpp"
#include <vulkan/vulkan_core.h>
MipmapGenerator::MipmapGenerator(const Gpu* gpu) :
m_gpu(gpu), m_commandBuffer(create_command_buffer(gpu)), m_fence(create_fence(gpu)) {
}
VkFence MipmapGenerator::create_fence(const Gpu* gpu) {
VkFenceCreateInfo fenceInfo = {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = VK_FENCE_CREATE_SIGNALED_BIT
};
VkFence fence = VK_NULL_HANDLE;
vkCreateFence(gpu->dev(), &fenceInfo, nullptr, &fence);
return fence;
}
VkCommandBuffer MipmapGenerator::create_command_buffer(const Gpu* gpu) {
VkCommandBufferAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = gpu->transfer_command_pool(),
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
VkCommandBuffer cmdbuf = VK_NULL_HANDLE;
vkAllocateCommandBuffers(gpu->dev(), &allocInfo,
&cmdbuf);
return cmdbuf;
}
uint32_t MipmapGenerator::generate(Image image, VkImageLayout oldLayout, VkExtent2D extent, VkImageSubresourceRange range) {
vkWaitForFences(m_gpu->dev(), 1, &m_fence, VK_TRUE, UINT64_MAX);
vkResetFences(m_gpu->dev(), 1, &m_fence);
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
};
vkBeginCommandBuffer(m_commandBuffer, &beginInfo);
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.oldLayout = oldLayout,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image.img,
.subresourceRange = {
.aspectMask = range.aspectMask,
.baseMipLevel = 1,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = range.layerCount,
},
};
vkCmdPipelineBarrier(m_commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier);
barrier.subresourceRange.levelCount = 1;
int32_t width = extent.width;
auto layout = oldLayout;
for (uint32_t i = 1; i < range.levelCount; i++) {
uint32_t from_level = i - 1;
uint32_t to_level = i;
std::vector<VkImageMemoryBarrier> barriers(2, barrier);
barriers[0].oldLayout = layout;
barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barriers[0].subresourceRange.baseMipLevel = from_level;
vkCmdPipelineBarrier(m_commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, nullptr,
0, nullptr,
1, barriers.data());
VkImageBlit blit = {
.srcSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = from_level,
.baseArrayLayer = 0,
.layerCount = range.layerCount,
},
.srcOffsets = {
{ 0, 0, 0 },
{ width, width, 1 }
},
.dstSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = to_level,
.baseArrayLayer = 0,
.layerCount = range.layerCount
},
.dstOffsets = {
{ 0, 0, 0 },
{
width > 1 ? width / 2 : 1,
width > 1 ? width / 2 : 1,
1
}
},
};
vkCmdBlitImage(m_commandBuffer,
image.img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
image.img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit,
VK_FILTER_LINEAR);
// transfer back to old layout
/* barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barriers[0].newLayout = oldLayout;
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(m_commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
0, nullptr,
1, barriers.data()); */
width /= 2;
layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
}
std::vector<VkImageMemoryBarrier> barriers(2, barrier);
barriers[0].subresourceRange.baseMipLevel = 0;
barriers[0].subresourceRange.levelCount = range.levelCount - 1;
barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barriers[0].newLayout = oldLayout;
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barriers[1].subresourceRange.baseMipLevel = range.levelCount - 1;
barriers[1].subresourceRange.levelCount = 1;
barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barriers[1].newLayout = oldLayout;
barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(m_commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
0, nullptr,
2, barriers.data());
vkEndCommandBuffer(m_commandBuffer);
VkSubmitInfo submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &m_commandBuffer
};
m_gpu->enqueue_transfer(&submitInfo, m_fence);
return 0;
}
@@ -0,0 +1,35 @@
#include "shaders/ComputePipelineBuilder.hpp"
namespace lft {
ComputePipelineBuilder::ComputePipelineBuilder(const Shader* shader, VkPipelineLayout layout) :
m_shader(shader),
m_layout(layout) {
}
Pipeline ComputePipelineBuilder::build(const Gpu* gpu) {
VkPipelineShaderStageCreateInfo computeShaderStageInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = m_shader->module(),
.pName = "main",
};
VkComputePipelineCreateInfo pipeline_info = {
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.stage = computeShaderStageInfo,
.layout = m_layout,
};
VkPipeline pipeline = VK_NULL_HANDLE;
if (vkCreateComputePipelines(gpu->dev(),
VK_NULL_HANDLE, 1, &pipeline_info, nullptr,
&pipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create compute pipeline!");
}
return Pipeline(m_layout, pipeline);
}
}
@@ -0,0 +1,10 @@
//
// Created by martin on 10/24/23.
//
#include "../../include/shaders/GlslShaderBuilder.hpp"
Shader GlslShaderBuilder::from_file(std::string path) {
Shader shader(VK_NULL_HANDLE);
return shader;
}
+2
View File
@@ -0,0 +1,2 @@
#include "shaders/Pipeline.hpp"
@@ -0,0 +1,144 @@
#include "shaders/PipelineBuilder.h"
#include "shaders/Shader.hpp"
#include <vulkan/vulkan_core.h>
PipelineBuilder::PipelineBuilder(const Gpu* gpu, const VkViewport& viewport,
VkPipelineLayout layout, VkRenderPass outputLayout,
uint32_t numAttachments,
const Shader* vertexShader, const Shader* fragmentShader) :
m_gpu(gpu),
m_viewport(viewport),
m_scissor({
.offset = {0, 0},
.extent = {(uint32_t)viewport.width, (uint32_t)std::abs(viewport.height)}
}),
m_layout(layout), m_renderpass(outputLayout),
m_inputAssemblyInfo({
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = false
}),
m_rasterInfo({
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = false,
.rasterizerDiscardEnable = false,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
.depthBiasEnable = false,
.lineWidth = 1.0f
}),
m_depthStencilInfo({
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = true,
.depthWriteEnable = true,
.depthCompareOp = VK_COMPARE_OP_LESS,
.depthBoundsTestEnable = false,
.stencilTestEnable = false
}),
m_vertexInputInfo({
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
}),
m_blendingInfo(numAttachments)
{
stages.resize(2);
stages[0] = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = vertexShader->module(),
.pName = "main"
};
stages[1] = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = fragmentShader->module(),
.pName = "main",
};
for(uint32_t i = 0; i < num_attachments(); i++) {
m_blendingInfo[i] = {
.blendEnable = false,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.alphaBlendOp = VK_BLEND_OP_ADD,
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT
};
}
}
Pipeline PipelineBuilder::build() {
m_vertexInputInfo.vertexBindingDescriptionCount = m_vertexBindings.size();
m_vertexInputInfo.pVertexBindingDescriptions = (VkVertexInputBindingDescription*)m_vertexBindings.data();
m_vertexInputInfo.vertexAttributeDescriptionCount = m_vertexAttributes.size();
m_vertexInputInfo.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription*)m_vertexAttributes.data();
/* Multisampling disabled. Use TTA */
VkPipelineMultisampleStateCreateInfo multisampling = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.sampleShadingEnable = VK_FALSE,
.minSampleShading = 1.0f,
.pSampleMask = nullptr,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
VkPipelineViewportStateCreateInfo viewportState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = &m_viewport,
.scissorCount = 1,
.pScissors = &m_scissor
};
VkPipelineColorBlendStateCreateInfo colorBlending = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = (unsigned)m_blendingInfo.size(),
.pAttachments = m_blendingInfo.data(),
.blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f}
};
std::vector<VkDynamicState> dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicState = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = (uint32_t)dynamicStates.size(),
.pDynamicStates = dynamicStates.data()
};
VkGraphicsPipelineCreateInfo pipelineInfo = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = (uint32_t)stages.size(),
.pStages = stages.data(),
.pVertexInputState = &m_vertexInputInfo,
.pInputAssemblyState = &m_inputAssemblyInfo,
.pViewportState = &viewportState,
.pRasterizationState = &m_rasterInfo,
.pMultisampleState = &multisampling,
.pDepthStencilState = &m_depthStencilInfo,
.pColorBlendState = &colorBlending,
.pDynamicState = &dynamicState,
.layout = m_layout,
.renderPass = m_renderpass,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
.basePipelineIndex = -1,
};
VkPipeline pipeline;
if(vkCreateGraphicsPipelines(m_gpu->dev(), VK_NULL_HANDLE, 1,
&pipelineInfo, nullptr, &pipeline)) {
throw std::runtime_error("Failed to create graphics pipeline");
}
return Pipeline(m_layout, pipeline);
}
@@ -0,0 +1,48 @@
//
// Created by martin on 10/24/23.
//
#include <stdexcept>
#include "shaders/SpirvShaderBuilder.hpp"
#include "io/file.hpp"
SpirvShaderBuilder::SpirvShaderBuilder(const Gpu* gpu) :
m_gpu(gpu) {
}
Shader SpirvShaderBuilder::from_binary(const std::vector<uint32_t>& code) const {
VkShaderModuleCreateInfo moduleInfo = {
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
.codeSize = code.size(),
.pCode = code.data(),
};
VkShaderModule module = VK_NULL_HANDLE;
if(vkCreateShaderModule(m_gpu->dev(), &moduleInfo, nullptr, &module)) {
throw std::runtime_error(std::format("Failed to create shader module from binary. Length was {}", code.size() * sizeof(uint32_t)));
}
return Shader(module);
}
Shader SpirvShaderBuilder::from_file(std::string path) {
auto shaderBinary = io::file::read_binary(path);
VkShaderModuleCreateInfo moduleInfo = {
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
.codeSize = shaderBinary.code_size(),
.pCode = shaderBinary.data().data(),
};
VkShaderModule module = VK_NULL_HANDLE;
if(vkCreateShaderModule(m_gpu->dev(), &moduleInfo, nullptr, &module)) {
throw std::runtime_error("Failed to create shader module");
}
auto shader = Shader(module);
shader.set_name(m_gpu, path);
return shader;
}