Major refactoring, removed the usage of the global header and replaced with getters and setters. Cleaned up headers and what is included.

This commit is contained in:
Lillian Salehi 2024-11-24 18:12:29 -06:00
parent d8c82d3351
commit f8bd7fdf3b
22 changed files with 708 additions and 706 deletions

View File

@ -3,6 +3,6 @@ Pos=60,60
Size=400,400
[Window][Agnosia Debug]
Pos=124,277
Pos=194,438
Size=583,225

View File

@ -1,26 +1,30 @@
#include "agnosiaimgui.h"
#include "devicelibrary.h"
#include "entrypoint.h"
#include "graphics/buffers.h"
namespace agnosia_imgui {
#include "graphics/texture.h"
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_vulkan.h"
#include <stdexcept>
VkDescriptorPool imGuiDescriptorPool;
void initWindow() {
void initImGuiWindow() {
ImGui::DragFloat3("Object Position", buffers_libs::Buffers::getObjPos());
ImGui::DragFloat3("Camera Position", buffers_libs::Buffers::getCamPos());
ImGui::DragFloat3("Center Position", buffers_libs::Buffers::getCenterPos());
ImGui::DragFloat3("Up Direction", buffers_libs::Buffers::getUpDir());
ImGui::DragFloat("Depth of Field", buffers_libs::Buffers::getDepthField(),
0.1f, 1.0f, 180.0f, NULL, ImGuiSliderFlags_AlwaysClamp);
ImGui::DragFloat2("Near and Far fields",
buffers_libs::Buffers::getDistanceField());
ImGui::DragFloat3("Object Position", Buffers::getObjPos());
ImGui::DragFloat3("Camera Position", Buffers::getCamPos());
ImGui::DragFloat3("Center Position", Buffers::getCenterPos());
ImGui::DragFloat3("Up Direction", Buffers::getUpDir());
ImGui::DragFloat("Depth of Field", &Buffers::getDepthField(), 0.1f, 1.0f,
180.0f, NULL, ImGuiSliderFlags_AlwaysClamp);
ImGui::DragFloat2("Near and Far fields", Buffers::getDistanceField());
}
void drawTabs() {
if (ImGui::BeginTabBar("MainTabBar", ImGuiTabBarFlags_Reorderable)) {
if (ImGui::BeginTabItem("Transforms Control")) {
initWindow();
initImGuiWindow();
ImGui::EndTabItem();
}
@ -50,7 +54,7 @@ void Gui::drawImGui() {
void Gui::initImgui(VkInstance instance) {
auto load_vk_func = [&](const char *fn) {
if (auto proc = vkGetDeviceProcAddr(Global::device, fn))
if (auto proc = vkGetDeviceProcAddr(DeviceControl::getDevice(), fn))
return proc;
return vkGetInstanceProcAddr(instance, fn);
};
@ -69,7 +73,7 @@ void Gui::initImgui(VkInstance instance) {
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForVulkan(Global::window, true);
ImGui_ImplGlfw_InitForVulkan(EntryApp::getWindow(), true);
VkDescriptorPoolSize ImGuiPoolSizes[]{
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1},
@ -81,33 +85,33 @@ void Gui::initImgui(VkInstance instance) {
.poolSizeCount = 1,
.pPoolSizes = ImGuiPoolSizes,
};
if (vkCreateDescriptorPool(Global::device, &ImGuiPoolInfo, nullptr,
&imGuiDescriptorPool) != VK_SUCCESS) {
if (vkCreateDescriptorPool(DeviceControl::getDevice(), &ImGuiPoolInfo,
nullptr, &imGuiDescriptorPool) != VK_SUCCESS) {
throw std::runtime_error("Failed to create ImGui descriptor pool!");
}
VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
.colorAttachmentCount = 1,
.pColorAttachmentFormats = device_libs::DeviceControl::getImageFormat(),
.depthAttachmentFormat = texture_libs::Texture::findDepthFormat(),
.pColorAttachmentFormats = &DeviceControl::getImageFormat(),
.depthAttachmentFormat = Texture::findDepthFormat(),
};
ImGui_ImplVulkan_InitInfo initInfo{
.Instance = instance,
.PhysicalDevice = Global::physicalDevice,
.Device = Global::device,
.QueueFamily = Global::findQueueFamilies(Global::physicalDevice)
.graphicsFamily.value(),
.Queue = Global::graphicsQueue,
.PhysicalDevice = DeviceControl::getPhysicalDevice(),
.Device = DeviceControl::getDevice(),
.QueueFamily =
DeviceControl::findQueueFamilies(DeviceControl::getPhysicalDevice())
.graphicsFamily.value(),
.Queue = DeviceControl::getGraphicsQueue(),
.DescriptorPool = imGuiDescriptorPool,
.MinImageCount = Global::MAX_FRAMES_IN_FLIGHT,
.ImageCount = Global::MAX_FRAMES_IN_FLIGHT,
.MSAASamples = Global::perPixelSampleCount,
.MinImageCount = Buffers::getMaxFramesInFlight(),
.ImageCount = Buffers::getMaxFramesInFlight(),
.MSAASamples = DeviceControl::getPerPixelSampleCount(),
.UseDynamicRendering = true,
.PipelineRenderingCreateInfo = pipelineRenderingCreateInfo,
};
ImGui_ImplVulkan_Init(&initInfo);
}
} // namespace agnosia_imgui

View File

@ -1,15 +1,8 @@
#pragma once
#include "global.h"
#include "graphics/texture.h"
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_vulkan.h"
#include <map>
#include "volk.h"
namespace agnosia_imgui {
class Gui {
public:
static void drawImGui();
static void initImgui(VkInstance instance);
};
} // namespace agnosia_imgui

View File

@ -1,11 +1,22 @@
#include "devicelibrary.h"
#include "global.h"
namespace device_libs {
#include <algorithm>
#include <limits>
#include <set>
#include <stdexcept>
#include <string>
#include <vulkan/vulkan_core.h>
VkPhysicalDeviceProperties deviceProperties;
VkDevice device;
VkSurfaceKHR surface;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkPhysicalDevice physicalDevice;
VkSampleCountFlagBits perPixelSampleCount;
VkSwapchainKHR swapChain;
std::vector<VkImage> swapChainImages;
std::vector<VkImageView> swapChainImageViews;
VkFormat swapChainImageFormat;
VkExtent2D swapChainExtent;
@ -18,6 +29,47 @@ const std::vector<const char *> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
};
DeviceControl::QueueFamilyIndices
DeviceControl::findQueueFamilies(VkPhysicalDevice device) {
// First we feed in a integer we want to use to hold the number of queued
// items, that fills it, then we create that amount of default constructed
// *VkQueueFamilyProperties* structs. These store the flags, the amount of
// queued items in the family, and timestamp data. Queue families are simply
// group collections of tasks we want to get done. Next, we check the flags of
// the queueFamily item, use a bitwise and to see if they match, i.e. support
// graphical operations, then return that to notify that we have at least one
// family that supports VK_QUEUE_GRAPHICS_BIT. Which means this device
// supports graphical operations! We also do the same thing for window
// presentation, just check to see if its supported.
DeviceControl::QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
queueFamilies.data());
int i = 0;
for (const auto &queueFamily : queueFamilies) {
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphicsFamily = i;
}
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, DeviceControl::getSurface(),
&presentSupport);
if (presentSupport) {
indices.presentFamily = i;
}
if (indices.isComplete()) {
break;
}
i++;
}
return indices;
}
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
/* Swap chains are weird ngl, it's another one of those Vulkan platform
@ -28,28 +80,26 @@ SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
no fucking clue how it works though) */
SwapChainSupportDetails details;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, Global::surface,
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface,
&details.capabilities);
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, Global::surface, &formatCount,
nullptr);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
if (formatCount != 0) {
details.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, Global::surface, &formatCount,
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount,
details.formats.data());
}
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(
device, Global::surface, &presentModeCount, details.presentModes.data());
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount,
details.presentModes.data());
if (presentModeCount != 0) {
details.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, Global::surface,
&presentModeCount,
details.presentModes.data());
vkGetPhysicalDeviceSurfacePresentModesKHR(
device, surface, &presentModeCount, details.presentModes.data());
}
return details;
@ -88,7 +138,8 @@ bool isDeviceSuitable(VkPhysicalDevice device) {
// We need to find a device that supports graphical operations, or else we
// cant do much with it! This function just runs over all the queueFamilies
// and sees if there is a queue family with the VK_QUEUE_GRAPHICS_BIT flipped!
Global::QueueFamilyIndices indices = Global::findQueueFamilies(device);
DeviceControl::QueueFamilyIndices indices =
DeviceControl::findQueueFamilies(device);
bool extensionSupported = checkDeviceExtensionSupport(device);
bool swapChainAdequate = false;
@ -167,7 +218,7 @@ VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities,
VkSampleCountFlagBits getMaxUsableSampleCount() {
VkPhysicalDeviceProperties physicalDeviceProps;
VkSampleCountFlags maxCounts;
vkGetPhysicalDeviceProperties(Global::physicalDevice, &physicalDeviceProps);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProps);
VkSampleCountFlags counts =
physicalDeviceProps.limits.framebufferColorSampleCounts &
@ -210,20 +261,20 @@ void DeviceControl::pickPhysicalDevice(VkInstance &instance) {
if (isDeviceSuitable(device)) {
// Once we have buttons or such, maybe ask the user or write a config file
// for which GPU to use?
Global::physicalDevice = device;
Global::perPixelSampleCount = getMaxUsableSampleCount();
physicalDevice = device;
perPixelSampleCount = getMaxUsableSampleCount();
break;
}
}
if (Global::physicalDevice == VK_NULL_HANDLE) {
if (physicalDevice == VK_NULL_HANDLE) {
throw std::runtime_error("Failed to find a suitable GPU!");
}
}
void DeviceControl::destroySurface(VkInstance &instance) {
vkDestroySurfaceKHR(instance, Global::surface, nullptr);
vkDestroySurfaceKHR(instance, surface, nullptr);
}
void DeviceControl::createSurface(VkInstance &instance, GLFWwindow *window) {
if (glfwCreateWindowSurface(instance, window, nullptr, &Global::surface) !=
if (glfwCreateWindowSurface(instance, window, nullptr, &surface) !=
VK_SUCCESS) {
throw std::runtime_error("Failed to create window surface!!");
}
@ -234,8 +285,7 @@ void DeviceControl::createLogicalDevice() {
// transfer ops, decode and encode operations can also queued with setup! We
// also assign each queue a priority. We do this by looping over all the
// queueFamilies and sorting them by indices to fill the queue at the end!
Global::QueueFamilyIndices indices =
Global::findQueueFamilies(Global::physicalDevice);
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(),
@ -278,18 +328,16 @@ void DeviceControl::createLogicalDevice() {
static_cast<uint32_t>(deviceExtensions.size());
createDeviceInfo.ppEnabledExtensionNames = deviceExtensions.data();
if (vkCreateDevice(Global::physicalDevice, &createDeviceInfo, nullptr,
&Global::device) != VK_SUCCESS) {
if (vkCreateDevice(physicalDevice, &createDeviceInfo, nullptr, &device) !=
VK_SUCCESS) {
throw std::runtime_error("Failed to create logical device");
}
vkGetDeviceQueue(Global::device, indices.graphicsFamily.value(), 0,
&Global::graphicsQueue);
vkGetDeviceQueue(Global::device, indices.presentFamily.value(), 0,
&Global::presentQueue);
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
}
void DeviceControl::createSwapChain(GLFWwindow *window) {
SwapChainSupportDetails swapChainSupport =
querySwapChainSupport(Global::physicalDevice);
querySwapChainSupport(physicalDevice);
VkSurfaceFormatKHR surfaceFormat =
chooseSwapSurfaceFormat(swapChainSupport.formats);
@ -311,7 +359,7 @@ void DeviceControl::createSwapChain(GLFWwindow *window) {
VkSwapchainCreateInfoKHR createSwapChainInfo{};
createSwapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createSwapChainInfo.surface = Global::surface;
createSwapChainInfo.surface = surface;
createSwapChainInfo.minImageCount = imageCount;
createSwapChainInfo.imageFormat = surfaceFormat.format;
createSwapChainInfo.imageColorSpace = surfaceFormat.colorSpace;
@ -327,8 +375,7 @@ void DeviceControl::createSwapChain(GLFWwindow *window) {
// This handles swap chain images across multiple queue families, ie, if the
// graphics queue family is different from the present queue
Global::QueueFamilyIndices indices =
Global::findQueueFamilies(Global::physicalDevice);
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(),
indices.presentFamily.value()};
// Usage across multiple queue families without explicit transfer of ownership
@ -357,22 +404,21 @@ void DeviceControl::createSwapChain(GLFWwindow *window) {
// it and reference the old one specified here, will revisit in a few days.
// createSwapChainInfo.oldSwapchain = VK_NULL_HANDLE;
if (vkCreateSwapchainKHR(Global::device, &createSwapChainInfo, nullptr,
&Global::swapChain) != VK_SUCCESS) {
if (vkCreateSwapchainKHR(device, &createSwapChainInfo, nullptr, &swapChain) !=
VK_SUCCESS) {
throw std::runtime_error("Failed to create the swap chain!!");
}
vkGetSwapchainImagesKHR(Global::device, Global::swapChain, &imageCount,
nullptr);
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
swapChainImages.resize(imageCount);
vkGetSwapchainImagesKHR(Global::device, Global::swapChain, &imageCount,
vkGetSwapchainImagesKHR(device, swapChain, &imageCount,
swapChainImages.data());
swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent;
}
void DeviceControl::destroySwapChain() {
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
vkDestroySwapchainKHR(device, swapChain, nullptr);
}
VkImageView DeviceControl::createImageView(VkImage image, VkFormat format,
VkImageAspectFlags flags,
@ -391,33 +437,43 @@ VkImageView DeviceControl::createImageView(VkImage image, VkFormat format,
viewInfo.subresourceRange.levelCount = mipLevels;
VkImageView imageView;
if (vkCreateImageView(Global::device, &viewInfo, nullptr, &imageView) !=
VK_SUCCESS) {
if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) {
throw std::runtime_error("failed to create image view!");
}
return imageView;
}
void DeviceControl::createImageViews() {
Global::swapChainImageViews.resize(swapChainImages.size());
swapChainImageViews.resize(swapChainImages.size());
for (uint32_t i = 0; i < swapChainImages.size(); i++) {
Global::swapChainImageViews[i] = createImageView(
swapChainImageViews[i] = createImageView(
swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);
}
}
void DeviceControl::destroyImageViews() {
for (auto imageView : Global::swapChainImageViews) {
vkDestroyImageView(Global::device, imageView, nullptr);
for (auto imageView : swapChainImageViews) {
vkDestroyImageView(device, imageView, nullptr);
}
}
// --------------------------------------- Getters & Setters
// ------------------------------------------ //
VkFormat *DeviceControl::getImageFormat() { return &swapChainImageFormat; }
VkExtent2D DeviceControl::getSwapChainExtent() { return swapChainExtent; }
std::vector<VkImage> DeviceControl::getSwapChainImages() {
VkFormat &DeviceControl::getImageFormat() { return swapChainImageFormat; }
VkSwapchainKHR &DeviceControl::getSwapChain() { return swapChain; }
VkExtent2D &DeviceControl::getSwapChainExtent() { return swapChainExtent; }
std::vector<VkImage> &DeviceControl::getSwapChainImages() {
return swapChainImages;
}
} // namespace device_libs
std::vector<VkImageView> &DeviceControl::getSwapChainImageViews() {
return swapChainImageViews;
}
VkDevice &DeviceControl::getDevice() { return device; }
VkPhysicalDevice &DeviceControl::getPhysicalDevice() { return physicalDevice; }
VkSampleCountFlagBits &DeviceControl::getPerPixelSampleCount() {
return perPixelSampleCount;
}
VkQueue &DeviceControl::getGraphicsQueue() { return graphicsQueue; }
VkQueue &DeviceControl::getPresentQueue() { return presentQueue; }
VkSurfaceKHR &DeviceControl::getSurface() { return surface; }

View File

@ -1,31 +1,50 @@
#pragma once
#include "global.h"
#include <algorithm>
#include <limits>
#include <set>
#include <string>
#define VK_NO_PROTOTYPES
#include "volk.h"
#include <optional>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vector>
namespace device_libs {
class DeviceControl {
public:
static void pickPhysicalDevice(VkInstance& instance);
static void createLogicalDevice();
static void createSurface(VkInstance& instance, GLFWwindow* window);
static void destroySurface(VkInstance& instance);
static void createSwapChain(GLFWwindow* window);
static void destroySwapChain();
static VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags, uint32_t mipLevels);
static void createImageViews();
static void destroyImageViews();
static void createCommandPool();
static void destroyCommandPool();
public:
struct QueueFamilyIndices {
// We need to check that the Queue families support graphics operations and
// window presentation, sometimes they can support one or the other,
// therefore, we take into account both for completion.
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
// ---------- Getters & Setters ----------- //
static VkFormat* getImageFormat();
static VkExtent2D getSwapChainExtent();
static std::vector<VkImage> getSwapChainImages();
static std::vector<VkFramebuffer> getSwapChainFramebuffers();
bool isComplete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
}
static void pickPhysicalDevice(VkInstance &instance);
static void createLogicalDevice();
static void createSurface(VkInstance &instance, GLFWwindow *window);
static void destroySurface(VkInstance &instance);
static void createSwapChain(GLFWwindow *window);
static void destroySwapChain();
static VkImageView createImageView(VkImage image, VkFormat format,
VkImageAspectFlags flags,
uint32_t mipLevels);
static void createImageViews();
static void destroyImageViews();
static void createCommandPool();
static void destroyCommandPool();
static QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
// ---------- Getters & Setters ----------- //
static VkFormat &getImageFormat();
static VkExtent2D &getSwapChainExtent();
static std::vector<VkImage> &getSwapChainImages();
static std::vector<VkFramebuffer> &getSwapChainFramebuffers();
static VkDevice &getDevice();
static VkSurfaceKHR &getSurface();
static VkQueue &getGraphicsQueue();
static VkQueue &getPresentQueue();
static VkPhysicalDevice &getPhysicalDevice();
static VkSampleCountFlagBits &getPerPixelSampleCount();
static std::vector<VkImageView> &getSwapChainImageViews();
static VkSwapchainKHR &getSwapChain();
};

View File

@ -1,13 +1,26 @@
#include "agnosiaimgui.h"
#include "devicelibrary.h"
#include "entrypoint.h"
#include "global.h"
#include "graphics/buffers.h"
#include "graphics/graphicspipeline.h"
#include "graphics/model.h"
#include "graphics/render.h"
#include "graphics/texture.h"
#define VK_NO_PROTOTYPES
#include "volk.h"
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_vulkan.h"
#include <stdexcept>
VkInstance vulkaninstance;
GLFWwindow *window;
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;
// Getters and Setters!
void EntryApp::setFramebufferResized(bool setter) {
framebufferResized = setter;
@ -25,10 +38,9 @@ void initWindow() {
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
// Settings for the window are set, create window reference.
Global::window = glfwCreateWindow(Global::WIDTH, Global::HEIGHT,
"Trimgles :o", nullptr, nullptr);
glfwSetWindowUserPointer(Global::window, &EntryApp::getInstance());
glfwSetFramebufferSizeCallback(Global::window, framebufferResizeCallback);
window = glfwCreateWindow(WIDTH, HEIGHT, "Trimgles :o", nullptr, nullptr);
glfwSetWindowUserPointer(window, &EntryApp::getInstance());
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
}
void createInstance() {
@ -84,62 +96,62 @@ void initVulkan() {
// Initialize vulkan and set up pipeline.
createInstance();
volkLoadInstance(vulkaninstance);
device_libs::DeviceControl::createSurface(vulkaninstance, Global::window);
device_libs::DeviceControl::pickPhysicalDevice(vulkaninstance);
device_libs::DeviceControl::createLogicalDevice();
volkLoadDevice(Global::device);
device_libs::DeviceControl::createSwapChain(Global::window);
device_libs::DeviceControl::createImageViews();
buffers_libs::Buffers::createDescriptorSetLayout();
graphics_pipeline::Graphics::createGraphicsPipeline();
graphics_pipeline::Graphics::createCommandPool();
texture_libs::Texture::createColorResources();
texture_libs::Texture::createDepthResources();
texture_libs::Texture::createTextureImage();
texture_libs::Texture::createTextureImageView();
texture_libs::Texture::createTextureSampler();
modellib::Model::loadModel();
buffers_libs::Buffers::createVertexBuffer();
buffers_libs::Buffers::createIndexBuffer();
buffers_libs::Buffers::createUniformBuffers();
buffers_libs::Buffers::createDescriptorPool();
buffers_libs::Buffers::createDescriptorSets();
graphics_pipeline::Graphics::createCommandBuffer();
render_present::Render::createSyncObject();
agnosia_imgui::Gui::initImgui(vulkaninstance);
DeviceControl::createSurface(vulkaninstance, window);
DeviceControl::pickPhysicalDevice(vulkaninstance);
DeviceControl::createLogicalDevice();
volkLoadDevice(DeviceControl::getDevice());
DeviceControl::createSwapChain(window);
DeviceControl::createImageViews();
Buffers::createDescriptorSetLayout();
Graphics::createGraphicsPipeline();
Graphics::createCommandPool();
Texture::createColorResources();
Texture::createDepthResources();
Texture::createTextureImage();
Texture::createTextureImageView();
Texture::createTextureSampler();
Model::loadModel();
Buffers::createVertexBuffer();
Buffers::createIndexBuffer();
Buffers::createUniformBuffers();
Buffers::createDescriptorPool();
Buffers::createDescriptorSets();
Graphics::createCommandBuffer();
Render::createSyncObject();
Gui::initImgui(vulkaninstance);
}
void mainLoop() {
while (!glfwWindowShouldClose(Global::window)) {
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
agnosia_imgui::Gui::drawImGui();
render_present::Render::drawFrame();
Gui::drawImGui();
Render::drawFrame();
}
vkDeviceWaitIdle(Global::device);
vkDeviceWaitIdle(DeviceControl::getDevice());
}
void cleanup() {
render_present::Render::cleanupSwapChain();
graphics_pipeline::Graphics::destroyGraphicsPipeline();
buffers_libs::Buffers::destroyUniformBuffer();
buffers_libs::Buffers::destroyDescriptorPool();
texture_libs::Texture::destroyTextureSampler();
texture_libs::Texture::destroyTextureImage();
vkDestroyDescriptorSetLayout(Global::device, Global::descriptorSetLayout,
nullptr);
buffers_libs::Buffers::destroyBuffers();
render_present::Render::destroyFenceSemaphores();
graphics_pipeline::Graphics::destroyCommandPool();
Render::cleanupSwapChain();
Graphics::destroyGraphicsPipeline();
Buffers::destroyUniformBuffer();
Buffers::destroyDescriptorPool();
Texture::destroyTextureSampler();
Texture::destroyTextureImage();
vkDestroyDescriptorSetLayout(DeviceControl::getDevice(),
Buffers::getDescriptorSetLayout(), nullptr);
Buffers::destroyBuffers();
Render::destroyFenceSemaphores();
Graphics::destroyCommandPool();
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
vkDestroyDevice(Global::device, nullptr);
device_libs::DeviceControl::destroySurface(vulkaninstance);
vkDestroyDevice(DeviceControl::getDevice(), nullptr);
DeviceControl::destroySurface(vulkaninstance);
vkDestroyInstance(vulkaninstance, nullptr);
glfwDestroyWindow(Global::window);
glfwDestroyWindow(window);
glfwTerminate();
}
@ -152,7 +164,7 @@ EntryApp::EntryApp() : initialized(false), framebufferResized(false) {}
void EntryApp::initialize() { initialized = true; }
bool EntryApp::isInitialized() const { return initialized; }
GLFWwindow *EntryApp::getWindow() { return window; }
void EntryApp::run() {
initWindow();
initVulkan();

View File

@ -1,10 +1,6 @@
#pragma once
#include "global.h"
#include "graphics/graphicspipeline.h"
#include "graphics/model.h"
#include "graphics/render.h"
#include "graphics/texture.h"
#include <GLFW/glfw3.h>
class EntryApp {
public:
static EntryApp &getInstance();
@ -13,6 +9,7 @@ public:
void run();
void setFramebufferResized(bool frame);
bool getFramebufferResized() const;
static GLFWwindow *getWindow();
private:
EntryApp();

View File

@ -1,71 +0,0 @@
#include "global.h"
namespace Global {
VkSurfaceKHR surface;
VkDevice device;
VkPhysicalDevice physicalDevice;
VkSampleCountFlagBits perPixelSampleCount;
VkSwapchainKHR swapChain;
VkCommandPool commandPool;
std::vector<VkCommandBuffer> commandBuffers;
VkQueue graphicsQueue;
VkQueue presentQueue;
GLFWwindow *window;
VkDescriptorSetLayout descriptorSetLayout;
std::vector<VkDescriptorSet> descriptorSets;
uint32_t currentFrame = 0;
VkImageView textureImageView;
VkSampler textureSampler;
VkImageView colorImageView;
VkImage colorImage;
VkDeviceMemory colorImageMemory;
VkImageView depthImageView;
VkImage depthImage;
VkDeviceMemory depthImageMemory;
std::vector<VkImageView> swapChainImageViews;
std::vector<Vertex> vertices;
// Index buffer definition, showing which points to reuse.
std::vector<uint32_t> indices;
Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
// First we feed in a integer we want to use to hold the number of queued
// items, that fills it, then we create that amount of default constructed
// *VkQueueFamilyProperties* structs. These store the flags, the amount of
// queued items in the family, and timestamp data. Queue families are simply
// group collections of tasks we want to get done. Next, we check the flags of
// the queueFamily item, use a bitwise and to see if they match, i.e. support
// graphical operations, then return that to notify that we have at least one
// family that supports VK_QUEUE_GRAPHICS_BIT. Which means this device
// supports graphical operations! We also do the same thing for window
// presentation, just check to see if its supported.
Global::QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
queueFamilies.data());
int i = 0;
for (const auto &queueFamily : queueFamilies) {
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphicsFamily = i;
}
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, Global::surface,
&presentSupport);
if (presentSupport) {
indices.presentFamily = i;
}
if (indices.isComplete()) {
break;
}
i++;
}
return indices;
}
} // namespace Global

View File

@ -1,129 +0,0 @@
#pragma once
#define VK_NO_PROTOTYPES
#include "volk.h"
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/detail/qualifier.hpp>
#include <glm/ext/vector_float2.hpp>
#include <glm/ext/vector_float3.hpp>
#include <glm/fwd.hpp>
#include <glm/gtc/matrix_transform.hpp>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <array>
#include <cstdint>
#include <iostream>
#include <optional>
#include <ostream>
#include <vector>
namespace Global {
// Global variables and includes we are going to use almost everywhere,
// validation layers hook into everything, and you need to check if they are
// enabled first, so that's one obvious global, as well as the glfw includes!
extern VkPhysicalDevice physicalDevice;
extern VkSampleCountFlagBits perPixelSampleCount;
extern VkDevice device;
extern VkCommandPool commandPool;
extern std::vector<VkCommandBuffer> commandBuffers;
extern VkQueue graphicsQueue;
extern VkQueue presentQueue;
extern GLFWwindow *window;
extern VkSurfaceKHR surface;
extern uint32_t currentFrame;
extern std::vector<VkDescriptorSet> descriptorSets;
extern VkDescriptorSetLayout descriptorSetLayout;
extern VkImageView textureImageView;
extern VkSampler textureSampler;
extern VkImage colorImage;
extern VkImageView colorImageView;
extern VkDeviceMemory colorImageMemory;
extern VkImage depthImage;
extern VkImageView depthImageView;
extern VkDeviceMemory depthImageMemory;
extern VkSwapchainKHR swapChain;
extern std::vector<VkImageView> swapChainImageViews;
const std::string MODEL_PATH = "assets/models/viking_room.obj";
const std::string TEXTURE_PATH = "assets/textures/viking_room.png";
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;
const int MAX_FRAMES_IN_FLIGHT = 2;
struct UniformBufferObject {
float time;
alignas(16) glm::mat4 model;
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 proj;
};
struct Vertex {
// This defines what a vertex is!
// We control the position, color and texture coordinate here!
glm::vec3 pos;
glm::vec3 color;
glm::vec2 texCoord;
static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription bindingDescription{};
bindingDescription.binding = 0;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return bindingDescription;
}
static std::array<VkVertexInputAttributeDescription, 3>
getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};
attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[0].offset = offsetof(Vertex, pos);
attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[1].offset = offsetof(Vertex, color);
attributeDescriptions[2].binding = 0;
attributeDescriptions[2].location = 2;
attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
return attributeDescriptions;
}
bool operator==(const Vertex &other) const {
return pos == other.pos && color == other.color &&
texCoord == other.texCoord;
}
};
extern std::vector<Vertex> vertices;
// Index buffer definition, showing which points to reuse.
extern std::vector<uint32_t> indices;
struct QueueFamilyIndices {
// We need to check that the Queue families support graphics operations and
// window presentation, sometimes they can support one or the other,
// therefore, we take into account both for completion.
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool isComplete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
} // namespace Global

View File

@ -1,12 +1,27 @@
#include "../devicelibrary.h"
#include "buffers.h"
#include <glm/fwd.hpp>
#include "texture.h"
#include <chrono>
#include <cstdint>
#include <cstring>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/ext/matrix_transform.hpp>
VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;
VkBuffer indexBuffer;
VkDeviceMemory indexBufferMemory;
VkDescriptorPool descriptorPool;
std::vector<Buffers::Vertex> vertices;
// Index buffer definition, showing which points to reuse.
std::vector<uint32_t> indices;
VkDescriptorPool descriptorPool;
VkDescriptorSetLayout descriptorSetLayout;
std::vector<VkDescriptorSet> descriptorSets;
VkCommandPool commandPool;
std::vector<VkCommandBuffer> commandBuffers;
std::vector<VkBuffer> uniformBuffers;
std::vector<VkDeviceMemory> uniformBuffersMemory;
std::vector<void *> uniformBuffersMapped;
@ -18,14 +33,22 @@ float upDir[4] = {0.0f, 0.0f, 1.0f, 0.44f};
float depthField = 45.0f;
float distanceField[2] = {0.1f, 100.0f};
namespace buffers_libs {
const int MAX_FRAMES_IN_FLIGHT = 2;
struct UniformBufferObject {
float time;
alignas(16) glm::mat4 model;
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 proj;
};
uint32_t Buffers::findMemoryType(uint32_t typeFilter,
VkMemoryPropertyFlags properties) {
// Graphics cards offer different types of memory to allocate from, here we
// query to find the right type of memory for our needs. Query the available
// types of memory to iterate over.
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(Global::physicalDevice, &memProperties);
vkGetPhysicalDeviceMemoryProperties(DeviceControl::getPhysicalDevice(),
&memProperties);
// iterate over and see if any of the memory types match our needs, in this
// case, HOST_VISIBLE and HOST_COHERENT. These will be explained shortly.
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
@ -41,11 +64,12 @@ void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = Global::commandPool;
allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(Global::device, &allocInfo, &commandBuffer);
vkAllocateCommandBuffers(DeviceControl::getDevice(), &allocInfo,
&commandBuffer);
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@ -64,10 +88,12 @@ void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(Global::graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(Global::graphicsQueue);
vkQueueSubmit(DeviceControl::getGraphicsQueue(), 1, &submitInfo,
VK_NULL_HANDLE);
vkQueueWaitIdle(DeviceControl::getGraphicsQueue());
vkFreeCommandBuffers(Global::device, Global::commandPool, 1, &commandBuffer);
vkFreeCommandBuffers(DeviceControl::getDevice(), commandPool, 1,
&commandBuffer);
}
void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
@ -79,13 +105,14 @@ void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if (vkCreateBuffer(Global::device, &bufferInfo, nullptr, &buffer) !=
VK_SUCCESS) {
if (vkCreateBuffer(DeviceControl::getDevice(), &bufferInfo, nullptr,
&buffer) != VK_SUCCESS) {
throw std::runtime_error("failed to create buffer!");
}
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(Global::device, buffer, &memRequirements);
vkGetBufferMemoryRequirements(DeviceControl::getDevice(), buffer,
&memRequirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
@ -93,16 +120,16 @@ void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
allocInfo.memoryTypeIndex =
findMemoryType(memRequirements.memoryTypeBits, properties);
if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &bufferMemory) !=
VK_SUCCESS) {
if (vkAllocateMemory(DeviceControl::getDevice(), &allocInfo, nullptr,
&bufferMemory) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate buffer memory!");
}
vkBindBufferMemory(Global::device, buffer, bufferMemory, 0);
vkBindBufferMemory(DeviceControl::getDevice(), buffer, bufferMemory, 0);
}
void Buffers::createIndexBuffer() {
VkDeviceSize bufferSize = sizeof(Global::indices[0]) * Global::indices.size();
VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
@ -113,10 +140,11 @@ void Buffers::createIndexBuffer() {
stagingBuffer, stagingBufferMemory);
void *data;
vkMapMemory(Global::device, stagingBufferMemory, 0, bufferSize, 0, &data);
memcpy(data, Global::indices.data(), (size_t)bufferSize);
vkMapMemory(DeviceControl::getDevice(), stagingBufferMemory, 0, bufferSize, 0,
&data);
memcpy(data, indices.data(), (size_t)bufferSize);
vkUnmapMemory(Global::device, stagingBufferMemory);
vkUnmapMemory(DeviceControl::getDevice(), stagingBufferMemory);
createBuffer(
bufferSize,
@ -125,8 +153,8 @@ void Buffers::createIndexBuffer() {
copyBuffer(stagingBuffer, indexBuffer, bufferSize);
vkDestroyBuffer(Global::device, stagingBuffer, nullptr);
vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
vkDestroyBuffer(DeviceControl::getDevice(), stagingBuffer, nullptr);
vkFreeMemory(DeviceControl::getDevice(), stagingBufferMemory, nullptr);
}
void Buffers::createVertexBuffer() {
// Create a Vertex Buffer to hold the vertex information in memory so it
@ -134,8 +162,7 @@ void Buffers::createVertexBuffer() {
// usage in this case is the buffer behaviour, using a bitwise OR. Sharing
// mode denostes the same as the images in the swap chain! in this case, only
// the graphics queue uses this buffer, so we make it exclusive.
VkDeviceSize bufferSize =
sizeof(Global::vertices[0]) * Global::vertices.size();
VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
@ -147,9 +174,10 @@ void Buffers::createVertexBuffer() {
stagingBuffer, stagingBufferMemory);
void *data;
vkMapMemory(Global::device, stagingBufferMemory, 0, bufferSize, 0, &data);
memcpy(data, Global::vertices.data(), (size_t)bufferSize);
vkUnmapMemory(Global::device, stagingBufferMemory);
vkMapMemory(DeviceControl::getDevice(), stagingBufferMemory, 0, bufferSize, 0,
&data);
memcpy(data, vertices.data(), (size_t)bufferSize);
vkUnmapMemory(DeviceControl::getDevice(), stagingBufferMemory);
createBuffer(
bufferSize,
@ -158,19 +186,17 @@ void Buffers::createVertexBuffer() {
copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
vkDestroyBuffer(Global::device, stagingBuffer, nullptr);
vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
vkDestroyBuffer(DeviceControl::getDevice(), stagingBuffer, nullptr);
vkFreeMemory(DeviceControl::getDevice(), stagingBufferMemory, nullptr);
}
void Buffers::destroyBuffers() {
vkDestroyBuffer(Global::device, indexBuffer, nullptr);
vkFreeMemory(Global::device, indexBufferMemory, nullptr);
vkDestroyBuffer(DeviceControl::getDevice(), indexBuffer, nullptr);
vkFreeMemory(DeviceControl::getDevice(), indexBufferMemory, nullptr);
vkDestroyBuffer(Global::device, vertexBuffer, nullptr);
vkFreeMemory(Global::device, vertexBufferMemory, nullptr);
vkDestroyBuffer(DeviceControl::getDevice(), vertexBuffer, nullptr);
vkFreeMemory(DeviceControl::getDevice(), vertexBufferMemory, nullptr);
}
VkBuffer Buffers::getVertexBuffer() { return vertexBuffer; }
VkBuffer Buffers::getIndexBuffer() { return indexBuffer; }
// ------------------------------ Uniform Buffer Setup
// -------------------------------- //
@ -204,8 +230,9 @@ void Buffers::createDescriptorSetLayout() {
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();
if (vkCreateDescriptorSetLayout(Global::device, &layoutInfo, nullptr,
&Global::descriptorSetLayout) != VK_SUCCESS) {
if (vkCreateDescriptorSetLayout(DeviceControl::getDevice(), &layoutInfo,
nullptr,
&descriptorSetLayout) != VK_SUCCESS) {
throw std::runtime_error("Failed to create descriptor set layout!");
}
}
@ -214,19 +241,18 @@ void Buffers::createUniformBuffers() {
// later. This stays mapped to memory for the applications lifetime. This
// technique is called "persistent mapping", not having to map the buffer
// every time we need to update it increases performance, though not free
VkDeviceSize bufferSize = sizeof(Global::UniformBufferObject);
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
uniformBuffers.resize(Global::MAX_FRAMES_IN_FLIGHT);
uniformBuffersMemory.resize(Global::MAX_FRAMES_IN_FLIGHT);
uniformBuffersMapped.resize(Global::MAX_FRAMES_IN_FLIGHT);
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
uniformBuffers[i], uniformBuffersMemory[i]);
vkMapMemory(Global::device, uniformBuffersMemory[i], 0, bufferSize, 0,
&uniformBuffersMapped[i]);
vkMapMemory(DeviceControl::getDevice(), uniformBuffersMemory[i], 0,
bufferSize, 0, &uniformBuffersMapped[i]);
}
}
void Buffers::updateUniformBuffer(uint32_t currentImage) {
@ -242,7 +268,7 @@ void Buffers::updateUniformBuffer(uint32_t currentImage) {
currentTime - startTime)
.count();
Global::UniformBufferObject ubo{};
UniformBufferObject ubo{};
ubo.time = time;
// Modify the model projection transformation to rotate around the Z over
// time.
@ -257,11 +283,11 @@ void Buffers::updateUniformBuffer(uint32_t currentImage) {
glm::vec3(centerPos[0], centerPos[1], centerPos[2]),
glm::vec3(upDir[0], upDir[1], upDir[2]));
// 45 degree field of view, set aspect ratio, and near and far clipping range.
ubo.proj = glm::perspective(
glm::radians(depthField),
device_libs::DeviceControl::getSwapChainExtent().width /
(float)device_libs::DeviceControl::getSwapChainExtent().height,
distanceField[0], distanceField[1]);
ubo.proj =
glm::perspective(glm::radians(depthField),
DeviceControl::getSwapChainExtent().width /
(float)DeviceControl::getSwapChainExtent().height,
distanceField[0], distanceField[1]);
// GLM was created for OpenGL, where the Y coordinate was inverted. This
// simply flips the sign.
@ -270,63 +296,60 @@ void Buffers::updateUniformBuffer(uint32_t currentImage) {
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
}
void Buffers::destroyUniformBuffer() {
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroyBuffer(Global::device, uniformBuffers[i], nullptr);
vkFreeMemory(Global::device, uniformBuffersMemory[i], nullptr);
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroyBuffer(DeviceControl::getDevice(), uniformBuffers[i], nullptr);
vkFreeMemory(DeviceControl::getDevice(), uniformBuffersMemory[i], nullptr);
}
}
void Buffers::createDescriptorPool() {
// Create a pool to be used to allocate descriptor sets.
std::array<VkDescriptorPoolSize, 2> poolSizes{};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[0].descriptorCount =
static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
poolSizes[0].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[1].descriptorCount =
static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
poolSizes[1].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
poolInfo.pPoolSizes = poolSizes.data();
poolInfo.maxSets = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
poolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
if (vkCreateDescriptorPool(Global::device, &poolInfo, nullptr,
if (vkCreateDescriptorPool(DeviceControl::getDevice(), &poolInfo, nullptr,
&descriptorPool) != VK_SUCCESS) {
throw std::runtime_error("failed to create descriptor pool!");
}
}
void Buffers::createDescriptorSets() {
std::vector<VkDescriptorSetLayout> layouts(Global::MAX_FRAMES_IN_FLIGHT,
Global::descriptorSetLayout);
std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT,
descriptorSetLayout);
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount =
static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
allocInfo.pSetLayouts = layouts.data();
Global::descriptorSets.resize(Global::MAX_FRAMES_IN_FLIGHT);
if (vkAllocateDescriptorSets(Global::device, &allocInfo,
Global::descriptorSets.data()) != VK_SUCCESS) {
descriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
if (vkAllocateDescriptorSets(DeviceControl::getDevice(), &allocInfo,
descriptorSets.data()) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate descriptor sets!");
}
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = uniformBuffers[i];
bufferInfo.offset = 0;
bufferInfo.range = sizeof(Global::UniformBufferObject);
bufferInfo.range = sizeof(UniformBufferObject);
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = Global::textureImageView;
imageInfo.sampler = Global::textureSampler;
imageInfo.imageView = Texture::getTextureImageView();
imageInfo.sampler = Texture::getTextureSampler();
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = Global::descriptorSets[i];
descriptorWrites[0].dstSet = descriptorSets[i];
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].dstArrayElement = 0;
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@ -334,7 +357,7 @@ void Buffers::createDescriptorSets() {
descriptorWrites[0].pBufferInfo = &bufferInfo;
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].dstSet = Global::descriptorSets[i];
descriptorWrites[1].dstSet = descriptorSets[i];
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstArrayElement = 0;
descriptorWrites[1].descriptorType =
@ -342,19 +365,37 @@ void Buffers::createDescriptorSets() {
descriptorWrites[1].descriptorCount = 1;
descriptorWrites[1].pImageInfo = &imageInfo;
vkUpdateDescriptorSets(Global::device,
vkUpdateDescriptorSets(DeviceControl::getDevice(),
static_cast<uint32_t>(descriptorWrites.size()),
descriptorWrites.data(), 0, nullptr);
}
}
void Buffers::destroyDescriptorPool() {
vkDestroyDescriptorPool(Global::device, descriptorPool, nullptr);
vkDestroyDescriptorPool(DeviceControl::getDevice(), descriptorPool, nullptr);
}
VkBuffer &Buffers::getVertexBuffer() { return vertexBuffer; }
VkBuffer &Buffers::getIndexBuffer() { return indexBuffer; }
VkDescriptorPool &Buffers::getDescriptorPool() { return descriptorPool; }
std::vector<VkDescriptorSet> &Buffers::getDescriptorSets() {
return descriptorSets;
}
VkDescriptorPool Buffers::getDescriptorPool() { return descriptorPool; }
float *Buffers::getObjPos() { return objPos; }
float *Buffers::getCamPos() { return camPos; }
float *Buffers::getCenterPos() { return centerPos; }
float *Buffers::getUpDir() { return upDir; }
float *Buffers::getDepthField() { return &depthField; }
float &Buffers::getDepthField() { return depthField; }
float *Buffers::getDistanceField() { return distanceField; }
} // namespace buffers_libs
uint32_t Buffers::getMaxFramesInFlight() { return MAX_FRAMES_IN_FLIGHT; }
std::vector<VkCommandBuffer> &Buffers::getCommandBuffers() {
return commandBuffers;
}
std::vector<VkBuffer> &Buffers::getUniformBuffers() { return uniformBuffers; }
std::vector<VkDeviceMemory> &Buffers::getUniformBuffersMemory() {
return uniformBuffersMemory;
}
VkCommandPool &Buffers::getCommandPool() { return commandPool; }
VkDescriptorSetLayout &Buffers::getDescriptorSetLayout() {
return descriptorSetLayout;
}
std::vector<Buffers::Vertex> &Buffers::getVertices() { return vertices; }
std::vector<uint32_t> &Buffers::getIndices() { return indices; }

View File

@ -1,11 +1,58 @@
#pragma once
#include "../devicelibrary.h"
#include <chrono>
#include <cstring>
namespace buffers_libs {
#define VK_NO_PROTOTYPES
#include "volk.h"
#include <vector>
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <array>
class Buffers {
public:
struct Vertex {
// This defines what a vertex is!
// We control the position, color and texture coordinate here!
glm::vec3 pos;
glm::vec3 color;
glm::vec2 texCoord;
static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription bindingDescription{};
bindingDescription.binding = 0;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return bindingDescription;
}
static std::array<VkVertexInputAttributeDescription, 3>
getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};
attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[0].offset = offsetof(Vertex, pos);
attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[1].offset = offsetof(Vertex, color);
attributeDescriptions[2].binding = 0;
attributeDescriptions[2].location = 2;
attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
return attributeDescriptions;
}
bool operator==(const Vertex &other) const {
return pos == other.pos && color == other.color &&
texCoord == other.texCoord;
}
};
static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
VkMemoryPropertyFlags props, VkBuffer &buffer,
VkDeviceMemory &bufferMemory);
@ -14,8 +61,8 @@ public:
static void createIndexBuffer();
static void createVertexBuffer();
static void destroyBuffers();
static VkBuffer getVertexBuffer();
static VkBuffer getIndexBuffer();
static VkBuffer &getVertexBuffer();
static VkBuffer &getIndexBuffer();
static void createDescriptorSetLayout();
static void createUniformBuffers();
static void updateUniformBuffer(uint32_t currentImage);
@ -23,13 +70,21 @@ public:
static void createDescriptorPool();
static void createDescriptorSets();
static void destroyDescriptorPool();
static VkDescriptorPool getDescriptorPool();
static VkDescriptorPool &getDescriptorPool();
static VkDescriptorSetLayout &getDescriptorSetLayout();
static std::vector<VkDescriptorSet> &getDescriptorSets();
static float *getObjPos();
static float *getCamPos();
static float *getCenterPos();
static float *getUpDir();
static float *getDepthField();
static float &getDepthField();
static float *getDistanceField();
static uint32_t getMaxFramesInFlight();
static std::vector<VkCommandBuffer> &getCommandBuffers();
static std::vector<VkBuffer> &getUniformBuffers();
static std::vector<VkDeviceMemory> &getUniformBuffersMemory();
static VkCommandPool &getCommandPool();
static std::vector<Vertex> &getVertices();
static std::vector<uint32_t> &getIndices();
};
} // namespace buffers_libs

View File

@ -1,9 +1,11 @@
#include "../devicelibrary.h"
#include "buffers.h"
#include "graphicspipeline.h"
#include "imgui.h"
#include "imgui_impl_vulkan.h"
#include "render.h"
#include "texture.h"
namespace graphics_pipeline {
#include <fstream>
std::vector<VkDynamicState> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR};
@ -43,8 +45,8 @@ VkShaderModule createShaderModule(const std::vector<char> &code,
}
void Graphics::destroyGraphicsPipeline() {
vkDestroyPipeline(Global::device, graphicsPipeline, nullptr);
vkDestroyPipelineLayout(Global::device, pipelineLayout, nullptr);
vkDestroyPipeline(DeviceControl::getDevice(), graphicsPipeline, nullptr);
vkDestroyPipelineLayout(DeviceControl::getDevice(), pipelineLayout, nullptr);
}
void Graphics::createGraphicsPipeline() {
@ -53,9 +55,9 @@ void Graphics::createGraphicsPipeline() {
auto vertShaderCode = readFile("src/shaders/vertex.spv");
auto fragShaderCode = readFile("src/shaders/fragment.spv");
VkShaderModule vertShaderModule =
createShaderModule(vertShaderCode, Global::device);
createShaderModule(vertShaderCode, DeviceControl::getDevice());
VkShaderModule fragShaderModule =
createShaderModule(fragShaderCode, Global::device);
createShaderModule(fragShaderCode, DeviceControl::getDevice());
// ------------------ STAGE 1 - INPUT ASSEMBLER ---------------- //
// This can get a little complicated, normally, vertices are loaded in
// sequential order, with an element buffer however, you can specify the
@ -81,8 +83,8 @@ void Graphics::createGraphicsPipeline() {
vertexInputInfo.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Global::Vertex::getBindingDescription();
auto attributeDescriptions = Global::Vertex::getAttributeDescriptions();
auto bindingDescription = Buffers::Vertex::getBindingDescription();
auto attributeDescriptions = Buffers::Vertex::getAttributeDescriptions();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
@ -149,7 +151,7 @@ void Graphics::createGraphicsPipeline() {
multisampling.sType =
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_TRUE;
multisampling.rasterizationSamples = Global::perPixelSampleCount;
multisampling.rasterizationSamples = DeviceControl::getPerPixelSampleCount();
// TODO: Document!
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType =
@ -175,18 +177,18 @@ void Graphics::createGraphicsPipeline() {
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &Global::descriptorSetLayout;
pipelineLayoutInfo.pSetLayouts = &Buffers::getDescriptorSetLayout();
if (vkCreatePipelineLayout(Global::device, &pipelineLayoutInfo, nullptr,
&pipelineLayout) != VK_SUCCESS) {
if (vkCreatePipelineLayout(DeviceControl::getDevice(), &pipelineLayoutInfo,
nullptr, &pipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("failed to create pipeline layout!");
}
VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
.colorAttachmentCount = 1,
.pColorAttachmentFormats = device_libs::DeviceControl::getImageFormat(),
.depthAttachmentFormat = texture_libs::Texture::findDepthFormat(),
.pColorAttachmentFormats = &DeviceControl::getImageFormat(),
.depthAttachmentFormat = Texture::findDepthFormat(),
};
// Here we combine all of the structures we created to make the final
@ -209,46 +211,48 @@ void Graphics::createGraphicsPipeline() {
.subpass = 0,
};
if (vkCreateGraphicsPipelines(Global::device, VK_NULL_HANDLE, 1,
if (vkCreateGraphicsPipelines(DeviceControl::getDevice(), VK_NULL_HANDLE, 1,
&pipelineInfo, nullptr,
&graphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create graphics pipeline!");
}
vkDestroyShaderModule(Global::device, fragShaderModule, nullptr);
vkDestroyShaderModule(Global::device, vertShaderModule, nullptr);
vkDestroyShaderModule(DeviceControl::getDevice(), fragShaderModule, nullptr);
vkDestroyShaderModule(DeviceControl::getDevice(), vertShaderModule, nullptr);
}
void Graphics::createCommandPool() {
// Commands in Vulkan are not executed using function calls, you have to
// record the ops you wish to perform to command buffers, pools manage the
// memory used by the buffer!
Global::QueueFamilyIndices queueFamilyIndices =
Global::findQueueFamilies(Global::physicalDevice);
DeviceControl::QueueFamilyIndices queueFamilyIndices =
DeviceControl::findQueueFamilies(DeviceControl::getPhysicalDevice());
VkCommandPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
if (vkCreateCommandPool(Global::device, &poolInfo, nullptr,
&Global::commandPool) != VK_SUCCESS) {
if (vkCreateCommandPool(DeviceControl::getDevice(), &poolInfo, nullptr,
&Buffers::getCommandPool()) != VK_SUCCESS) {
throw std::runtime_error("Failed to create command pool!");
}
}
void Graphics::destroyCommandPool() {
vkDestroyCommandPool(Global::device, Global::commandPool, nullptr);
vkDestroyCommandPool(DeviceControl::getDevice(), Buffers::getCommandPool(),
nullptr);
}
void Graphics::createCommandBuffer() {
Global::commandBuffers.resize(Global::MAX_FRAMES_IN_FLIGHT);
Buffers::getCommandBuffers().resize(Buffers::getMaxFramesInFlight());
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = Global::commandPool;
allocInfo.commandPool = Buffers::getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t)Global::commandBuffers.size();
allocInfo.commandBufferCount = (uint32_t)Buffers::getCommandBuffers().size();
if (vkAllocateCommandBuffers(Global::device, &allocInfo,
Global::commandBuffers.data()) != VK_SUCCESS) {
if (vkAllocateCommandBuffers(DeviceControl::getDevice(), &allocInfo,
Buffers::getCommandBuffers().data()) !=
VK_SUCCESS) {
throw std::runtime_error("Failed to allocate command buffers");
}
}
@ -272,7 +276,7 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
.newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = device_libs::DeviceControl::getSwapChainImages()[imageIndex],
.image = DeviceControl::getSwapChainImages()[imageIndex],
.subresourceRange =
{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
@ -294,10 +298,10 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
const VkRenderingAttachmentInfo colorAttachmentInfo{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.imageView = Global::colorImageView,
.imageView = Texture::getColorImageView(),
.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT,
.resolveImageView = Global::swapChainImageViews[imageIndex],
.resolveImageView = DeviceControl::getSwapChainImageViews()[imageIndex],
.resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
@ -305,7 +309,7 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
};
const VkRenderingAttachmentInfo depthAttachmentInfo{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.imageView = Global::depthImageView,
.imageView = Texture::getDepthImageView(),
.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
@ -315,8 +319,7 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
const VkRenderingInfo renderInfo{
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.renderArea = {.offset = {0, 0},
.extent =
device_libs::DeviceControl::getSwapChainExtent()},
.extent = DeviceControl::getSwapChainExtent()},
.layerCount = 1,
.colorAttachmentCount = 1,
.pColorAttachments = &colorAttachmentInfo,
@ -330,31 +333,30 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width =
(float)device_libs::DeviceControl::getSwapChainExtent().width;
viewport.height =
(float)device_libs::DeviceControl::getSwapChainExtent().height;
viewport.width = (float)DeviceControl::getSwapChainExtent().width;
viewport.height = (float)DeviceControl::getSwapChainExtent().height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = device_libs::DeviceControl::getSwapChainExtent();
scissor.extent = DeviceControl::getSwapChainExtent();
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
VkBuffer vertexBuffers[] = {buffers_libs::Buffers::getVertexBuffer()};
VkBuffer vertexBuffers[] = {Buffers::getVertexBuffer()};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer, buffers_libs::Buffers::getIndexBuffer(),
0, VK_INDEX_TYPE_UINT32);
vkCmdBindIndexBuffer(commandBuffer, Buffers::getIndexBuffer(), 0,
VK_INDEX_TYPE_UINT32);
vkCmdBindDescriptorSets(
commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
&Global::descriptorSets[Global::currentFrame], 0, nullptr);
&Buffers::getDescriptorSets()[Render::getCurrentFrame()], 0, nullptr);
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(Global::indices.size()),
1, 0, 0, 0);
vkCmdDrawIndexed(commandBuffer,
static_cast<uint32_t>(Buffers::getIndices().size()), 1, 0, 0,
0);
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer);
@ -371,7 +373,7 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = device_libs::DeviceControl::getSwapChainImages()[imageIndex],
.image = DeviceControl::getSwapChainImages()[imageIndex],
.subresourceRange =
{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
@ -388,11 +390,10 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
.pImageMemoryBarriers = &prePresentImageBarrier,
};
vkCmdPipelineBarrier2(Global::commandBuffers[Global::currentFrame], &depInfo);
vkCmdPipelineBarrier2(
Buffers ::getCommandBuffers()[Render::getCurrentFrame()], &depInfo);
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {
throw std::runtime_error("failed to record command buffer!");
}
}
} // namespace graphics_pipeline

View File

@ -1,20 +1,16 @@
#pragma once
#include "../global.h"
#include "../devicelibrary.h"
#include "buffers.h"
#include "texture.h"
#include <fstream>
#define VK_NO_PROTOTYPES
#include "volk.h"
namespace graphics_pipeline {
class Graphics {
public:
static void createGraphicsPipeline();
static void destroyGraphicsPipeline();
static void createFramebuffers();
static void destroyFramebuffers();
static void createCommandPool();
static void destroyCommandPool();
static void createCommandBuffer();
static void recordCommandBuffer(VkCommandBuffer cmndBuffer, uint32_t imageIndex);
};
}
class Graphics {
public:
static void createGraphicsPipeline();
static void destroyGraphicsPipeline();
static void createFramebuffers();
static void destroyFramebuffers();
static void createCommandPool();
static void destroyCommandPool();
static void createCommandBuffer();
static void recordCommandBuffer(VkCommandBuffer cmndBuffer,
uint32_t imageIndex);
};

View File

@ -1,64 +1,68 @@
#include "buffers.h"
#include "model.h"
#include <stdexcept>
#define TINY_OBJ_IMPLEMENTATION
#include <tiny_obj_loader.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>
namespace std {
template<> struct hash<Global::Vertex> {
size_t operator()(Global::Vertex const& vertex) const {
return ((hash<glm::vec3>()(vertex.pos) ^
(hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
(hash<glm::vec2>()(vertex.texCoord) << 1);
template <> struct hash<Buffers::Vertex> {
size_t operator()(Buffers::Vertex const &vertex) const {
return ((hash<glm::vec3>()(vertex.pos) ^
(hash<glm::vec3>()(vertex.color) << 1)) >>
1) ^
(hash<glm::vec2>()(vertex.texCoord) << 1);
}
};
} // namespace std
const std::string MODEL_PATH = "assets/models/viking_room.obj";
void Model::loadModel() {
tinyobj::ObjReaderConfig readerConfig;
tinyobj::ObjReader reader;
if (!reader.ParseFromFile(MODEL_PATH, readerConfig)) {
if (!reader.Error().empty()) {
throw std::runtime_error(reader.Error());
}
};
}
namespace modellib {
std::unordered_map<Global::Vertex, uint32_t> uniqueVertices{};
void Model::loadModel() {
tinyobj::ObjReaderConfig readerConfig;
tinyobj::ObjReader reader;
if(!reader.ParseFromFile(Global::MODEL_PATH, readerConfig)) {
if(!reader.Error().empty()) {
throw std::runtime_error(reader.Error());
}
if(!reader.Warning().empty()) {
throw std::runtime_error(reader.Warning());
}
if (!reader.Warning().empty()) {
throw std::runtime_error(reader.Warning());
}
auto& attrib = reader.GetAttrib();
auto& shapes = reader.GetShapes();
auto& materials = reader.GetMaterials();
}
for (const auto& shape : shapes) {
for (const auto& index : shape.mesh.indices) {
Global::Vertex vertex{};
auto &attrib = reader.GetAttrib();
auto &shapes = reader.GetShapes();
auto &materials = reader.GetMaterials();
std::unordered_map<Buffers::Vertex, uint32_t> uniqueVertices{};
vertex.pos = {
attrib.vertices[3 * index.vertex_index + 0],
attrib.vertices[3 * index.vertex_index + 1],
attrib.vertices[3 * index.vertex_index + 2]
};
//TODO: Small fix here, handle if there are no UV's unwrapped for the model.
// As of now, if it is not unwrapped, it segfaults on texCoord assignment.
// Obviously we should always have UV's, but it shouldn't crash, just unwrap
// in a default method.
vertex.texCoord = {
attrib.texcoords[2 * index.texcoord_index + 0],
1.0f - attrib.texcoords[2 * index.texcoord_index + 1]
};
vertex.color = {1.0f, 1.0f, 1.0f};
for (const auto &shape : shapes) {
for (const auto &index : shape.mesh.indices) {
Buffers::Vertex vertex{};
if (uniqueVertices.count(vertex) == 0) {
uniqueVertices[vertex] = static_cast<uint32_t>(Global::vertices.size());
Global::vertices.push_back(vertex);
}
Global::indices.push_back(uniqueVertices[vertex]);
vertex.pos = {attrib.vertices[3 * index.vertex_index + 0],
attrib.vertices[3 * index.vertex_index + 1],
attrib.vertices[3 * index.vertex_index + 2]};
// TODO: Small fix here, handle if there are no UV's unwrapped for the
// model.
// As of now, if it is not unwrapped, it segfaults on texCoord
// assignment. Obviously we should always have UV's, but it
// shouldn't crash, just unwrap in a default method.
vertex.texCoord = {attrib.texcoords[2 * index.texcoord_index + 0],
1.0f - attrib.texcoords[2 * index.texcoord_index + 1]};
vertex.color = {1.0f, 1.0f, 1.0f};
if (uniqueVertices.count(vertex) == 0) {
uniqueVertices[vertex] =
static_cast<uint32_t>(Buffers::getVertices().size());
Buffers::getVertices().push_back(vertex);
}
Buffers::getIndices().push_back(uniqueVertices[vertex]);
}
}
}

View File

@ -1,15 +1,6 @@
#pragma once
#include "../global.h"
#define TINY_OBJ_IMPLEMENTATION
#include <tiny_obj_loader.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>
namespace modellib {
class Model {
public:
static void loadModel();
};
} // namespace modellib

View File

@ -1,55 +1,56 @@
#include <stdexcept>
#include "imgui.h"
#include "imgui_impl_vulkan.h"
#include "../devicelibrary.h"
#include "../entrypoint.h"
#include "buffers.h"
#include "graphicspipeline.h"
#include "render.h"
#include "texture.h"
#include <stdexcept>
#include "imgui.h"
#include "imgui_impl_vulkan.h"
namespace render_present {
uint32_t currentFrame;
std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores;
std::vector<VkFence> inFlightFences;
void recreateSwapChain() {
int width = 0, height = 0;
glfwGetFramebufferSize(Global::window, &width, &height);
glfwGetFramebufferSize(EntryApp::getWindow(), &width, &height);
while (width == 0 || height == 0) {
glfwGetFramebufferSize(Global::window, &width, &height);
glfwGetFramebufferSize(EntryApp::getWindow(), &width, &height);
glfwWaitEvents();
}
vkDeviceWaitIdle(Global::device);
vkDeviceWaitIdle(DeviceControl::getDevice());
// Don't really wanna do this but I also don't want to create an extra class
// instance just to call the cleanup function.
for (auto imageView : Global::swapChainImageViews) {
vkDestroyImageView(Global::device, imageView, nullptr);
for (auto imageView : DeviceControl::getSwapChainImageViews()) {
vkDestroyImageView(DeviceControl::getDevice(), imageView, nullptr);
}
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
vkDestroySwapchainKHR(DeviceControl::getDevice(),
DeviceControl::getSwapChain(), nullptr);
device_libs::DeviceControl::createSwapChain(Global::window);
device_libs::DeviceControl::createImageViews();
texture_libs::Texture::createColorResources();
texture_libs::Texture::createDepthResources();
DeviceControl::createSwapChain(EntryApp::getWindow());
DeviceControl::createImageViews();
Texture::createColorResources();
Texture::createDepthResources();
}
// At a high level, rendering in Vulkan consists of 5 steps:
// Wait for the previous frame, acquire a image from the swap chain
// record a comman d buffer which draws the scene onto that image
// submit the recorded command buffer and present the image!
void Render::drawFrame() {
vkWaitForFences(Global::device, 1, &inFlightFences[Global::currentFrame],
vkWaitForFences(DeviceControl::getDevice(), 1, &inFlightFences[currentFrame],
VK_TRUE, UINT64_MAX);
vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]);
vkResetFences(DeviceControl::getDevice(), 1, &inFlightFences[currentFrame]);
uint32_t imageIndex;
VkResult result =
vkAcquireNextImageKHR(Global::device, Global::swapChain, UINT64_MAX,
imageAvailableSemaphores[Global::currentFrame],
VK_NULL_HANDLE, &imageIndex);
VkResult result = vkAcquireNextImageKHR(
DeviceControl::getDevice(), DeviceControl::getSwapChain(), UINT64_MAX,
imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapChain();
return;
@ -57,36 +58,34 @@ void Render::drawFrame() {
throw std::runtime_error("failed to acquire swap chain image!");
}
buffers_libs::Buffers::updateUniformBuffer(Global::currentFrame);
Buffers::updateUniformBuffer(currentFrame);
vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]);
vkResetFences(DeviceControl::getDevice(), 1, &inFlightFences[currentFrame]);
vkResetCommandBuffer(Global::commandBuffers[Global::currentFrame],
vkResetCommandBuffer(Buffers::getCommandBuffers()[currentFrame],
/*VkCommandBufferResetFlagBits*/ 0);
graphics_pipeline::Graphics::recordCommandBuffer(
Global::commandBuffers[Global::currentFrame], imageIndex);
Graphics::recordCommandBuffer(Buffers::getCommandBuffers()[currentFrame],
imageIndex);
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(),
Global::commandBuffers[Global::currentFrame]);
Buffers::getCommandBuffers()[currentFrame]);
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {
imageAvailableSemaphores[Global::currentFrame]};
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
VkPipelineStageFlags waitStages[] = {
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &Global::commandBuffers[Global::currentFrame];
submitInfo.pCommandBuffers = &Buffers::getCommandBuffers()[currentFrame];
VkSemaphore signalSemaphores[] = {
renderFinishedSemaphores[Global::currentFrame]};
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(Global::graphicsQueue, 1, &submitInfo,
inFlightFences[Global::currentFrame]) != VK_SUCCESS) {
if (vkQueueSubmit(DeviceControl::getGraphicsQueue(), 1, &submitInfo,
inFlightFences[currentFrame]) != VK_SUCCESS) {
throw std::runtime_error("failed to submit draw command buffer!");
}
@ -96,12 +95,12 @@ void Render::drawFrame() {
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = {Global::swapChain};
VkSwapchainKHR swapChains[] = {DeviceControl::getSwapChain()};
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
result = vkQueuePresentKHR(Global::presentQueue, &presentInfo);
result = vkQueuePresentKHR(DeviceControl::getPresentQueue(), &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR ||
EntryApp::getInstance().getFramebufferResized()) {
@ -110,8 +109,7 @@ void Render::drawFrame() {
} else if (result != VK_SUCCESS) {
throw std::runtime_error("failed to present swap chain image!");
}
Global::currentFrame =
(Global::currentFrame + 1) % Global::MAX_FRAMES_IN_FLIGHT;
currentFrame = (currentFrame + 1) % Buffers::getMaxFramesInFlight();
}
#pragma info
@ -139,9 +137,9 @@ void Render::drawFrame() {
#pragma endinfo
void Render::createSyncObject() {
imageAvailableSemaphores.resize(Global::MAX_FRAMES_IN_FLIGHT);
renderFinishedSemaphores.resize(Global::MAX_FRAMES_IN_FLIGHT);
inFlightFences.resize(Global::MAX_FRAMES_IN_FLIGHT);
imageAvailableSemaphores.resize(Buffers::getMaxFramesInFlight());
renderFinishedSemaphores.resize(Buffers::getMaxFramesInFlight());
inFlightFences.resize(Buffers::getMaxFramesInFlight());
VkSemaphoreCreateInfo semaphoreInfo{};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@ -150,36 +148,42 @@ void Render::createSyncObject() {
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
if (vkCreateSemaphore(Global::device, &semaphoreInfo, nullptr,
for (size_t i = 0; i < Buffers::getMaxFramesInFlight(); i++) {
if (vkCreateSemaphore(DeviceControl::getDevice(), &semaphoreInfo, nullptr,
&imageAvailableSemaphores[i]) != VK_SUCCESS ||
vkCreateSemaphore(Global::device, &semaphoreInfo, nullptr,
vkCreateSemaphore(DeviceControl::getDevice(), &semaphoreInfo, nullptr,
&renderFinishedSemaphores[i]) != VK_SUCCESS ||
vkCreateFence(Global::device, &fenceInfo, nullptr,
vkCreateFence(DeviceControl::getDevice(), &fenceInfo, nullptr,
&inFlightFences[i]) != VK_SUCCESS) {
throw std::runtime_error("Failed to create semaphores!");
}
}
}
void Render::destroyFenceSemaphores() {
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroySemaphore(Global::device, renderFinishedSemaphores[i], nullptr);
vkDestroySemaphore(Global::device, imageAvailableSemaphores[i], nullptr);
vkDestroyFence(Global::device, inFlightFences[i], nullptr);
for (size_t i = 0; i < Buffers::getMaxFramesInFlight(); i++) {
vkDestroySemaphore(DeviceControl::getDevice(), renderFinishedSemaphores[i],
nullptr);
vkDestroySemaphore(DeviceControl::getDevice(), imageAvailableSemaphores[i],
nullptr);
vkDestroyFence(DeviceControl::getDevice(), inFlightFences[i], nullptr);
}
}
void Render::cleanupSwapChain() {
vkDestroyImageView(Global::device, Global::colorImageView, nullptr);
vkDestroyImage(Global::device, Global::colorImage, nullptr);
vkFreeMemory(Global::device, Global::colorImageMemory, nullptr);
vkDestroyImageView(Global::device, Global::depthImageView, nullptr);
vkDestroyImage(Global::device, Global::depthImage, nullptr);
vkFreeMemory(Global::device, Global::depthImageMemory, nullptr);
vkDestroyImageView(DeviceControl::getDevice(), Texture::getColorImageView(),
nullptr);
vkDestroyImage(DeviceControl::getDevice(), Texture::getColorImage(), nullptr);
vkFreeMemory(DeviceControl::getDevice(), Texture::getColorImageMemory(),
nullptr);
vkDestroyImageView(DeviceControl::getDevice(), Texture::getDepthImageView(),
nullptr);
vkDestroyImage(DeviceControl::getDevice(), Texture::getDepthImage(), nullptr);
vkFreeMemory(DeviceControl::getDevice(), Texture::getDepthImageMemory(),
nullptr);
for (auto imageView : Global::swapChainImageViews) {
vkDestroyImageView(Global::device, imageView, nullptr);
for (auto imageView : DeviceControl::getSwapChainImageViews()) {
vkDestroyImageView(DeviceControl::getDevice(), imageView, nullptr);
}
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
vkDestroySwapchainKHR(DeviceControl::getDevice(),
DeviceControl::getSwapChain(), nullptr);
}
} // namespace render_present
uint32_t Render::getCurrentFrame() { return currentFrame; }

View File

@ -1,7 +1,6 @@
#pragma once
#include "../global.h"
namespace render_present {
#include <cstdint>
class Render {
public:
static void drawFrame();
@ -9,5 +8,5 @@ public:
static void destroyFenceSemaphores();
static void cleanupSwapChain();
static float getFloatBar();
static uint32_t getCurrentFrame();
};
} // namespace render_present

View File

@ -1,5 +1,9 @@
#define STB_IMAGE_IMPLEMENTATION
#include "../devicelibrary.h"
#include "buffers.h"
#include "texture.h"
#include <stdexcept>
#include <string>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
uint32_t mipLevels;
@ -9,7 +13,19 @@ VkDeviceMemory textureImageMemory;
VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage;
namespace texture_libs {
VkImageView textureImageView;
VkSampler textureSampler;
VkImage colorImage;
VkImageView colorImageView;
VkDeviceMemory colorImageMemory;
VkImage depthImage;
VkImageView depthImageView;
VkDeviceMemory depthImageMemory;
std::string TEXTURE_PATH = "assets/textures/viking_room.png";
void createImage(uint32_t width, uint32_t height, uint32_t mipLevels,
VkSampleCountFlagBits sampleNum, VkFormat format,
VkImageTiling tiling, VkImageUsageFlags usage,
@ -33,26 +49,27 @@ void createImage(uint32_t width, uint32_t height, uint32_t mipLevels,
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.mipLevels = mipLevels;
if (vkCreateImage(Global::device, &imageInfo, nullptr, &image) !=
if (vkCreateImage(DeviceControl::getDevice(), &imageInfo, nullptr, &image) !=
VK_SUCCESS) {
throw std::runtime_error("failed to create image!");
}
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(Global::device, image, &memRequirements);
vkGetImageMemoryRequirements(DeviceControl::getDevice(), image,
&memRequirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = buffers_libs::Buffers::findMemoryType(
memRequirements.memoryTypeBits, properties);
allocInfo.memoryTypeIndex =
Buffers::findMemoryType(memRequirements.memoryTypeBits, properties);
if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &imageMemory) !=
VK_SUCCESS) {
if (vkAllocateMemory(DeviceControl::getDevice(), &allocInfo, nullptr,
&imageMemory) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate image memory!");
}
vkBindImageMemory(Global::device, image, imageMemory, 0);
vkBindImageMemory(DeviceControl::getDevice(), image, imageMemory, 0);
}
VkCommandBuffer beginSingleTimeCommands() {
@ -61,11 +78,12 @@ VkCommandBuffer beginSingleTimeCommands() {
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = Global::commandPool;
allocInfo.commandPool = Buffers::getCommandPool();
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(Global::device, &allocInfo, &commandBuffer);
vkAllocateCommandBuffers(DeviceControl::getDevice(), &allocInfo,
&commandBuffer);
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@ -85,21 +103,14 @@ void endSingleTimeCommands(VkCommandBuffer commandBuffer) {
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(Global::graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(Global::graphicsQueue);
vkQueueSubmit(DeviceControl::getGraphicsQueue(), 1, &submitInfo,
VK_NULL_HANDLE);
vkQueueWaitIdle(DeviceControl::getGraphicsQueue());
vkFreeCommandBuffers(Global::device, Global::commandPool, 1, &commandBuffer);
vkFreeCommandBuffers(DeviceControl::getDevice(), Buffers::getCommandPool(), 1,
&commandBuffer);
}
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
// Copy 1 buffer to another.
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkBufferCopy copyRegion{};
copyRegion.size = size;
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
endSingleTimeCommands(commandBuffer);
}
void transitionImageLayout(VkImage image, VkFormat format,
VkImageLayout oldLayout, VkImageLayout newLayout,
uint32_t mipLevels) {
@ -173,7 +184,8 @@ VkFormat findSupportedFormat(const std::vector<VkFormat> &candidates,
VkFormatFeatureFlags features) {
for (VkFormat format : candidates) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(Global::physicalDevice, format, &props);
vkGetPhysicalDeviceFormatProperties(DeviceControl::getPhysicalDevice(),
format, &props);
// Do we support linear tiling?
if (tiling == VK_IMAGE_TILING_LINEAR &&
@ -195,8 +207,8 @@ void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t textureWidth,
int32_t textureHeight, uint32_t mipLevels) {
// Check if image format supports linear blitting
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(Global::physicalDevice, imageFormat,
&formatProperties);
vkGetPhysicalDeviceFormatProperties(DeviceControl::getPhysicalDevice(),
imageFormat, &formatProperties);
if (!(formatProperties.optimalTilingFeatures &
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
@ -283,7 +295,7 @@ void Texture::createTextureImage() {
// colorspace! Its a lot of kind of complicated memory calls to bring it from
// a file -> to a buffer -> to a image object.
int textureWidth, textureHeight, textureChannels;
stbi_uc *pixels = stbi_load(Global::TEXTURE_PATH.c_str(), &textureWidth,
stbi_uc *pixels = stbi_load(TEXTURE_PATH.c_str(), &textureWidth,
&textureHeight, &textureChannels, STBI_rgb_alpha);
mipLevels = static_cast<uint32_t>(std::floor(
std::log2(std::max(textureWidth, textureHeight)))) +
@ -296,16 +308,16 @@ void Texture::createTextureImage() {
}
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
buffers_libs::Buffers::createBuffer(imageSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
stagingBuffer, stagingBufferMemory);
Buffers::createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
stagingBuffer, stagingBufferMemory);
void *data;
vkMapMemory(Global::device, stagingBufferMemory, 0, imageSize, 0, &data);
vkMapMemory(DeviceControl::getDevice(), stagingBufferMemory, 0, imageSize, 0,
&data);
memcpy(data, pixels, static_cast<size_t>(imageSize));
vkUnmapMemory(Global::device, stagingBufferMemory);
vkUnmapMemory(DeviceControl::getDevice(), stagingBufferMemory);
stbi_image_free(pixels);
@ -323,8 +335,8 @@ void Texture::createTextureImage() {
static_cast<uint32_t>(textureWidth),
static_cast<uint32_t>(textureHeight));
vkDestroyBuffer(Global::device, stagingBuffer, nullptr);
vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
vkDestroyBuffer(DeviceControl::getDevice(), stagingBuffer, nullptr);
vkFreeMemory(DeviceControl::getDevice(), stagingBufferMemory, nullptr);
generateMipmaps(textureImage, VK_FORMAT_R8G8B8A8_SRGB, textureWidth,
textureHeight, mipLevels);
@ -332,9 +344,9 @@ void Texture::createTextureImage() {
void Texture::createTextureImageView() {
// Create a texture image view, which is a struct of information about the
// image.
Global::textureImageView = device_libs::DeviceControl::createImageView(
textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT,
mipLevels);
textureImageView =
DeviceControl::createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_ASPECT_COLOR_BIT, mipLevels);
}
void Texture::createTextureSampler() {
// Create a sampler to access and parse the texture object.
@ -352,7 +364,8 @@ void Texture::createTextureSampler() {
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
VkPhysicalDeviceProperties properties{};
vkGetPhysicalDeviceProperties(Global::physicalDevice, &properties);
vkGetPhysicalDeviceProperties(DeviceControl::getPhysicalDevice(),
&properties);
// Enable or Disable Anisotropy, and set the amount.
samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
@ -376,18 +389,18 @@ void Texture::createTextureSampler() {
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = VK_LOD_CLAMP_NONE;
if (vkCreateSampler(Global::device, &samplerInfo, nullptr,
&Global::textureSampler) != VK_SUCCESS) {
if (vkCreateSampler(DeviceControl::getDevice(), &samplerInfo, nullptr,
&textureSampler) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture sampler!");
}
}
void Texture::destroyTextureSampler() {
vkDestroySampler(Global::device, Global::textureSampler, nullptr);
vkDestroyImageView(Global::device, Global::textureImageView, nullptr);
vkDestroySampler(DeviceControl::getDevice(), textureSampler, nullptr);
vkDestroyImageView(DeviceControl::getDevice(), textureImageView, nullptr);
}
void Texture::destroyTextureImage() {
vkDestroyImage(Global::device, textureImage, nullptr);
vkFreeMemory(Global::device, textureImageMemory, nullptr);
vkDestroyImage(DeviceControl::getDevice(), textureImage, nullptr);
vkFreeMemory(DeviceControl::getDevice(), textureImageMemory, nullptr);
}
VkFormat Texture::findDepthFormat() {
return findSupportedFormat(
@ -396,32 +409,42 @@ VkFormat Texture::findDepthFormat() {
VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
}
void Texture::createColorResources() {
VkFormat colorFormat = *device_libs::DeviceControl::getImageFormat();
VkExtent2D swapChainExtent = device_libs::DeviceControl::getSwapChainExtent();
VkFormat colorFormat = DeviceControl::getImageFormat();
VkExtent2D swapChainExtent = DeviceControl::getSwapChainExtent();
createImage(swapChainExtent.width, swapChainExtent.height, 1,
Global::perPixelSampleCount, colorFormat, VK_IMAGE_TILING_OPTIMAL,
DeviceControl::getPerPixelSampleCount(), colorFormat,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, Global::colorImage,
Global::colorImageMemory);
Global::colorImageView = device_libs::DeviceControl::createImageView(
Global::colorImage, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, colorImage,
colorImageMemory);
colorImageView = DeviceControl::createImageView(colorImage, colorFormat,
VK_IMAGE_ASPECT_COLOR_BIT, 1);
}
void Texture::createDepthResources() {
VkFormat depthFormat = findDepthFormat();
VkExtent2D swapChainExtent = device_libs::DeviceControl::getSwapChainExtent();
createImage(swapChainExtent.width, swapChainExtent.height, 1,
Global::perPixelSampleCount, depthFormat, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, Global::depthImage,
Global::depthImageMemory);
Global::depthImageView = device_libs::DeviceControl::createImageView(
Global::depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1);
VkExtent2D swapChainExtent = DeviceControl::getSwapChainExtent();
createImage(
swapChainExtent.width, swapChainExtent.height, 1,
DeviceControl::getPerPixelSampleCount(), depthFormat,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);
depthImageView = DeviceControl::createImageView(depthImage, depthFormat,
VK_IMAGE_ASPECT_DEPTH_BIT, 1);
// Explicit transition from the layout of the image to the depth attachment is
// unnecessary here, since that will be handled in the render pass!
}
// ---------------------------- Getters & Setters
// ---------------------------------//
uint32_t Texture::getMipLevels() { return mipLevels; }
} // namespace texture_libs
VkImageView &Texture::getTextureImageView() { return textureImageView; }
VkSampler &Texture::getTextureSampler() { return textureSampler; }
VkImage &Texture::getColorImage() { return colorImage; }
VkImageView &Texture::getColorImageView() { return colorImageView; }
VkDeviceMemory &Texture::getColorImageMemory() { return colorImageMemory; }
VkImage &Texture::getDepthImage() { return depthImage; }
VkImageView &Texture::getDepthImageView() { return depthImageView; }
VkDeviceMemory &Texture::getDepthImageMemory() { return depthImageMemory; }

View File

@ -1,10 +1,7 @@
#pragma once
#include "../devicelibrary.h"
#include "../global.h"
#include "buffers.h"
#define VK_NO_PROTOTYPES
#include "volk.h"
#include <cstdint>
namespace texture_libs {
class Texture {
public:
static void createTextureImage();
@ -17,5 +14,14 @@ public:
static void createColorResources();
// ------------ Getters & Setters ------------ //
static uint32_t getMipLevels();
static VkImageView &getTextureImageView();
static VkSampler &getTextureSampler();
static VkImage &getColorImage();
static VkImageView &getColorImageView();
static VkDeviceMemory &getColorImageMemory();
static VkImage &getDepthImage();
static VkImageView &getDepthImageView();
static VkDeviceMemory &getDepthImageMemory();
};
} // namespace texture_libs

View File

@ -1,4 +1,5 @@
#include "entrypoint.h"
#include <iostream>
#define VOLK_IMPLEMENTATION
int main() {