diff --git a/.cache/clangd/index/agnosiaimgui.cpp.D917B7EB41E8A56F.idx b/.cache/clangd/index/agnosiaimgui.cpp.D917B7EB41E8A56F.idx index b61d11b..27042b5 100644 Binary files a/.cache/clangd/index/agnosiaimgui.cpp.D917B7EB41E8A56F.idx and b/.cache/clangd/index/agnosiaimgui.cpp.D917B7EB41E8A56F.idx differ diff --git a/.cache/clangd/index/buffers.cpp.FC2CC275D910BCB7.idx b/.cache/clangd/index/buffers.cpp.FC2CC275D910BCB7.idx index 73d3a19..6e728ce 100644 Binary files a/.cache/clangd/index/buffers.cpp.FC2CC275D910BCB7.idx and b/.cache/clangd/index/buffers.cpp.FC2CC275D910BCB7.idx differ diff --git a/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx b/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx index 90ecd48..19a2916 100644 Binary files a/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx and b/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx differ diff --git a/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx b/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx index ab7b5f7..f13b3c9 100644 Binary files a/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx and b/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx differ diff --git a/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx b/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx index d929e5e..b8608c4 100644 Binary files a/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx and b/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx differ diff --git a/.cache/clangd/index/graphicspipeline.cpp.F94E3ACB17FA6762.idx b/.cache/clangd/index/graphicspipeline.cpp.F94E3ACB17FA6762.idx index f912b13..9f62eea 100644 Binary files a/.cache/clangd/index/graphicspipeline.cpp.F94E3ACB17FA6762.idx and b/.cache/clangd/index/graphicspipeline.cpp.F94E3ACB17FA6762.idx differ diff --git a/.cache/clangd/index/graphicspipeline.h.093A3C67F46BDBAE.idx b/.cache/clangd/index/graphicspipeline.h.093A3C67F46BDBAE.idx index 95d67bd..6ffaaa0 100644 Binary files a/.cache/clangd/index/graphicspipeline.h.093A3C67F46BDBAE.idx and b/.cache/clangd/index/graphicspipeline.h.093A3C67F46BDBAE.idx differ diff --git a/.cache/clangd/index/material.h.3635D536A26B1F7D.idx b/.cache/clangd/index/material.h.3635D536A26B1F7D.idx new file mode 100644 index 0000000..ea6883f Binary files /dev/null and b/.cache/clangd/index/material.h.3635D536A26B1F7D.idx differ diff --git a/.cache/clangd/index/model.cpp.56D1ED026EF1D5F1.idx b/.cache/clangd/index/model.cpp.56D1ED026EF1D5F1.idx index 5bc649e..431044b 100644 Binary files a/.cache/clangd/index/model.cpp.56D1ED026EF1D5F1.idx and b/.cache/clangd/index/model.cpp.56D1ED026EF1D5F1.idx differ diff --git a/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx b/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx index d234b70..763a7c1 100644 Binary files a/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx and b/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx differ diff --git a/.cache/clangd/index/render.cpp.657B8B8CBD5B3B6B.idx b/.cache/clangd/index/render.cpp.657B8B8CBD5B3B6B.idx index b3d994a..9b1da59 100644 Binary files a/.cache/clangd/index/render.cpp.657B8B8CBD5B3B6B.idx and b/.cache/clangd/index/render.cpp.657B8B8CBD5B3B6B.idx differ diff --git a/.cache/clangd/index/texture.cpp.14763AFB742F8112.idx b/.cache/clangd/index/texture.cpp.14763AFB742F8112.idx index 7fe761e..11c780f 100644 Binary files a/.cache/clangd/index/texture.cpp.14763AFB742F8112.idx and b/.cache/clangd/index/texture.cpp.14763AFB742F8112.idx differ diff --git a/.cache/clangd/index/texture.h.712506A996DB5236.idx b/.cache/clangd/index/texture.h.712506A996DB5236.idx index 7c0ee1c..8d6dec3 100644 Binary files a/.cache/clangd/index/texture.h.712506A996DB5236.idx and b/.cache/clangd/index/texture.h.712506A996DB5236.idx differ diff --git a/.cache/clangd/index/types.h.2A872A9A515562E6.idx b/.cache/clangd/index/types.h.2A872A9A515562E6.idx index f4ca67d..64f68ee 100644 Binary files a/.cache/clangd/index/types.h.2A872A9A515562E6.idx and b/.cache/clangd/index/types.h.2A872A9A515562E6.idx differ diff --git a/Makefile b/Makefile index eff14b5..371b4e9 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ LDFLAGS=-lglfw -Ilib -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi -ltinyobjloade MAKEFLAGS += -j16 SRC = $(shell find . -name "*.cpp") CSRC = $(shell find . -name "*.c") -SHDRSRC = $(shell find . -name "*.frag" -o -name "*vert") +SHDRSRC = $(shell find . -name "*.frag" -o -name "*.vert") SPV = $(SHDRSRC:%.vert=%.spv) $(SHDRSRC:%.frag=%.spv) OBJ = $(SRC:%.cpp=%.o) COBJ=$(CSRC:%.c=%.o) @@ -48,6 +48,8 @@ $(BIN): $(OBJ) $(COBJ) $(SPV) glslc $< -o $@ %.spv: %.vert glslc $< -o $@ +%.spv: %.glsl + glslc $< -o $@ .PHONY: clean clean: diff --git a/imgui.ini b/imgui.ini index 42e0e92..ca80a3a 100644 --- a/imgui.ini +++ b/imgui.ini @@ -3,6 +3,6 @@ Pos=60,60 Size=400,400 [Window][Agnosia Debug] -Pos=522,0 -Size=583,202 +Pos=40,377 +Size=623,438 diff --git a/src/agnosiaimgui.cpp b/src/agnosiaimgui.cpp index 4404aa5..e9440d7 100644 --- a/src/agnosiaimgui.cpp +++ b/src/agnosiaimgui.cpp @@ -2,23 +2,32 @@ #include "devicelibrary.h" #include "entrypoint.h" #include "graphics/buffers.h" +#include "graphics/graphicspipeline.h" #include "graphics/texture.h" #include "imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_vulkan.h" +#include #include VkDescriptorPool imGuiDescriptorPool; void initImGuiWindow() { + if (ImGui::TreeNode("Model Transforms")) { + for (Model *model : Model::getInstances()) { - 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, + ImGui::DragFloat3(model->getID().c_str(), + const_cast(glm::value_ptr(model->getPos()))); + } + ImGui::TreePop(); + } + + ImGui::DragFloat3("Camera Position", Graphics::getCamPos()); + ImGui::DragFloat3("Center Position", Graphics::getCenterPos()); + ImGui::DragFloat3("Up Direction", Graphics::getUpDir()); + ImGui::DragFloat("Depth of Field", &Graphics::getDepthField(), 0.1f, 1.0f, 180.0f, NULL, ImGuiSliderFlags_AlwaysClamp); - ImGui::DragFloat2("Near and Far fields", Buffers::getDistanceField()); + ImGui::DragFloat2("Near and Far fields", Graphics::getDistanceField()); } void drawTabs() { @@ -37,8 +46,6 @@ void Gui::drawImGui() { ImGui_ImplVulkan_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); - // 2. Show a simple window that we create ourselves. We use a Begin/End pair - // to create a named window. ImGui::Begin("Agnosia Debug"); diff --git a/src/devicelibrary.cpp b/src/devicelibrary.cpp index 6d28958..a1f7cd4 100644 --- a/src/devicelibrary.cpp +++ b/src/devicelibrary.cpp @@ -4,7 +4,6 @@ #include #include #include -#include VkPhysicalDeviceProperties deviceProperties; VkDevice device; @@ -303,18 +302,31 @@ void DeviceControl::createLogicalDevice() { VkPhysicalDeviceVulkan12Features features12{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, .pNext = nullptr, + .shaderSampledImageArrayNonUniformIndexing = true, + .shaderStorageBufferArrayNonUniformIndexing = true, + .shaderStorageImageArrayNonUniformIndexing = true, + .descriptorBindingSampledImageUpdateAfterBind = true, + .descriptorBindingStorageImageUpdateAfterBind = true, + .descriptorBindingStorageBufferUpdateAfterBind = true, + .descriptorBindingUpdateUnusedWhilePending = true, + .descriptorBindingPartiallyBound = true, + .runtimeDescriptorArray = true, + .scalarBlockLayout = true, .bufferDeviceAddress = true, + }; VkPhysicalDeviceVulkan13Features features13{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, .pNext = &features12, .synchronization2 = true, .dynamicRendering = true, + }; VkPhysicalDeviceFeatures featuresBase{ .robustBufferAccess = true, .sampleRateShading = true, .samplerAnisotropy = true, + }; VkPhysicalDeviceFeatures2 deviceFeatures{ diff --git a/src/entrypoint.cpp b/src/entrypoint.cpp index b387701..b296faf 100644 --- a/src/entrypoint.cpp +++ b/src/entrypoint.cpp @@ -3,6 +3,7 @@ #include "entrypoint.h" #include "graphics/buffers.h" #include "graphics/graphicspipeline.h" + #include "graphics/model.h" #include "graphics/render.h" #include "graphics/texture.h" @@ -88,6 +89,22 @@ void createInstance() { } void initVulkan() { + Material *vikingRoomMaterial = + new Material("vikingRoomMaterial", "assets/textures/viking_room.png"); + Material *stanfordDragonMaterial = + new Material("stanfordDragonMaterial", "assets/textures/checkermap.png"); + Material *teapotMaterial = + new Material("teapotMaterial", "assets/textures/checkermap.png"); + Model *vikingRoom = + new Model("vikingRoom", *vikingRoomMaterial, + "assets/models/viking_room.obj", glm::vec3(0.0f, 0.0f, 0.0f)); + Model *stanfordDragon = new Model("stanfordDragon", *stanfordDragonMaterial, + "assets/models/StanfordDragon800k.obj", + glm::vec3(0.0f, 2.0f, 0.0f)); + Model *teapot = + new Model("teapot", *teapotMaterial, "assets/models/teapot.obj", + glm::vec3(1.0f, -3.0f, -1.0f)); + // Initialize volk and continue if successful. volkInitialize(); // Initialize vulkan and set up pipeline. @@ -98,20 +115,22 @@ void initVulkan() { DeviceControl::createLogicalDevice(); volkLoadDevice(DeviceControl::getDevice()); DeviceControl::createSwapChain(window); - Buffers::createMemoryAllocator(vulkaninstance); + Model::createMemoryAllocator(vulkaninstance); DeviceControl::createImageViews(); Buffers::createDescriptorSetLayout(); Graphics::createGraphicsPipeline(); Graphics::createCommandPool(); + // Image creation MUST be after command pool, because command + // buffers. + vikingRoom->populateData(); + stanfordDragon->populateData(); + teapot->populateData(); + Texture::createMaterialTextures(Model::getInstances()); Texture::createColorResources(); Texture::createDepthResources(); - Texture::createTextureImage(); - Texture::createTextureImageView(); - Texture::createTextureSampler(); - Model::loadModel(glm::vec3(0.0, 0.0, 0.0)); - Buffers::createUniformBuffers(); + Buffers::createDescriptorPool(); - Buffers::createDescriptorSets(); + Buffers::createDescriptorSet(Model::getInstances()); Graphics::createCommandBuffer(); Render::createSyncObject(); @@ -131,12 +150,7 @@ void mainLoop() { void cleanup() { Render::cleanupSwapChain(); Graphics::destroyGraphicsPipeline(); - Buffers::destroyUniformBuffer(); - Buffers::destroyDescriptorPool(); - Texture::destroyTextureSampler(); - Texture::destroyTextureImage(); - vkDestroyDescriptorSetLayout(DeviceControl::getDevice(), - Buffers::getDescriptorSetLayout(), nullptr); + Buffers::destroyBuffers(); Render::destroyFenceSemaphores(); Graphics::destroyCommandPool(); @@ -163,6 +177,7 @@ void EntryApp::initialize() { initialized = true; } bool EntryApp::isInitialized() const { return initialized; } GLFWwindow *EntryApp::getWindow() { return window; } void EntryApp::run() { + initWindow(); initVulkan(); mainLoop(); diff --git a/src/graphics/buffers.cpp b/src/graphics/buffers.cpp index 4494f83..78af9a7 100644 --- a/src/graphics/buffers.cpp +++ b/src/graphics/buffers.cpp @@ -1,58 +1,165 @@ #include "../devicelibrary.h" -#include "../types.h" -#include "buffers.h" -#include "texture.h" -#include +#include "buffers.h" +#include "model.h" + #include #include -#include + #include #include + #include #include -#define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 -#define VMA_IMPLEMENTATION -#include "vk_mem_alloc.h" +std::vector modelSetLayouts; VkBuffer vertexBuffer; VkDeviceMemory vertexBufferMemory; VkBuffer indexBuffer; VkDeviceMemory indexBufferMemory; -std::vector vertices; -// Index buffer definition, showing which points to reuse. -std::vector indices; +uint32_t indicesSize; -VmaAllocator _allocator; -Agnosia_T::GPUPushConstants pushConstants; +// Select a binding for each descriptor type +constexpr int STORAGE_BINDING = 0; +constexpr int SAMPLER_BINDING = 1; +constexpr int IMAGE_BINDING = 2; +// Max count of each descriptor type +// You can query the max values for these with +// physicalDevice.getProperties().limits.maxDescriptrorSet******* +constexpr int STORAGE_COUNT = 65536; +constexpr int SAMPLER_COUNT = 65536; +constexpr int IMAGE_COUNT = 65536; + +// Create descriptor pool VkDescriptorPool descriptorPool; VkDescriptorSetLayout descriptorSetLayout; -std::vector descriptorSets; +VkDescriptorSet descriptorSet; VkCommandPool commandPool; std::vector commandBuffers; -std::vector uniformBuffers; -std::vector uniformBuffersMemory; -std::vector uniformBuffersMapped; - -float objPos[4] = {0.0f, 0.0f, 0.0f, 0.44f}; -float camPos[4] = {2.0f, 2.0f, 2.0f, 0.44f}; -float centerPos[4] = {0.0f, 0.0f, 0.0f, 0.44f}; -float upDir[4] = {0.0f, 0.0f, 1.0f, 0.44f}; -float depthField = 45.0f; -float distanceField[2] = {0.1f, 100.0f}; 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; -}; + +void Buffers::createDescriptorSetLayout() { + // Create a table of pointers to data, a Descriptor Set! + + VkDescriptorSetLayoutBinding storageLayoutBinding = { + .binding = STORAGE_BINDING, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = STORAGE_COUNT, + .stageFlags = VK_SHADER_STAGE_ALL, + .pImmutableSamplers = nullptr, + }; + + VkDescriptorSetLayoutBinding samplerLayoutBinding = { + .binding = SAMPLER_BINDING, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = SAMPLER_COUNT, + .stageFlags = VK_SHADER_STAGE_ALL, + .pImmutableSamplers = nullptr, + }; + + VkDescriptorSetLayoutBinding imageLayoutBinding = { + .binding = IMAGE_BINDING, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = IMAGE_COUNT, + .stageFlags = VK_SHADER_STAGE_ALL, + .pImmutableSamplers = nullptr, + }; + + std::vector bindings = { + storageLayoutBinding, imageLayoutBinding, samplerLayoutBinding}; + + std::vector bindingFlags = { + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + }; + VkDescriptorSetLayoutBindingFlagsCreateInfo setLayoutBindingsFlags = { + .sType = + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + .bindingCount = 3, + .pBindingFlags = bindingFlags.data(), + }; + + VkDescriptorSetLayoutCreateInfo layoutInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + + .pNext = &setLayoutBindingsFlags, + .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + .bindingCount = static_cast(bindings.size()), + .pBindings = bindings.data(), + + }; + if (vkCreateDescriptorSetLayout(DeviceControl::getDevice(), &layoutInfo, + nullptr, + &descriptorSetLayout) != VK_SUCCESS) { + throw std::runtime_error("Failed to create descriptor set layout!"); + } +} +void Buffers::createDescriptorPool() { + + std::vector poolSizes = { + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, STORAGE_COUNT}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, SAMPLER_COUNT}, + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, IMAGE_COUNT}, + }; + VkDescriptorPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = static_cast(poolSizes.size()); + poolInfo.pPoolSizes = poolSizes.data(); + poolInfo.maxSets = 1; + poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; + + if (vkCreateDescriptorPool(DeviceControl::getDevice(), &poolInfo, nullptr, + &descriptorPool) != VK_SUCCESS) { + throw std::runtime_error("failed to create descriptor pool!"); + } +} +void Buffers::createDescriptorSet(std::vector models) { + VkDescriptorSetAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &descriptorSetLayout; + + if (vkAllocateDescriptorSets(DeviceControl::getDevice(), &allocInfo, + &descriptorSet) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate descriptor sets!"); + } + std::vector imageInfoSet; + imageInfoSet.resize(models.size()); + + for (int i = 0; i < models.size(); i++) { + imageInfoSet[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfoSet[i].imageView = models[i]->getMaterial().getTextureView(); + imageInfoSet[i].sampler = models[i]->getMaterial().getTextureSampler(); + } + + std::vector descriptorWrites{}; + descriptorWrites.resize(models.size()); + + for (int i = 0; i < models.size(); i++) { + descriptorWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[i].dstSet = descriptorSet; + descriptorWrites[i].dstBinding = SAMPLER_BINDING; + descriptorWrites[i].dstArrayElement = i; + descriptorWrites[i].descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrites[i].descriptorCount = 1; + descriptorWrites[i].pImageInfo = &imageInfoSet[i]; + } + + vkUpdateDescriptorSets(DeviceControl::getDevice(), + static_cast(descriptorWrites.size()), + descriptorWrites.data(), 0, nullptr); +} uint32_t Buffers::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { @@ -73,40 +180,6 @@ uint32_t Buffers::findMemoryType(uint32_t typeFilter, throw std::runtime_error("failed to find suitable memory type!"); } -void immediate_submit(std::function &&function) { - VkCommandBufferAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = commandPool; - allocInfo.commandBufferCount = 1; - - VkCommandBuffer commandBuffer; - vkAllocateCommandBuffers(DeviceControl::getDevice(), &allocInfo, - &commandBuffer); - - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - vkBeginCommandBuffer(commandBuffer, &beginInfo); - - function(commandBuffer); - - vkEndCommandBuffer(commandBuffer); - - VkSubmitInfo submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - - vkQueueSubmit(DeviceControl::getGraphicsQueue(), 1, &submitInfo, - VK_NULL_HANDLE); - vkQueueWaitIdle(DeviceControl::getGraphicsQueue()); - - vkFreeCommandBuffers(DeviceControl::getDevice(), commandPool, 1, - &commandBuffer); -} - void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -142,101 +215,6 @@ void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { vkFreeCommandBuffers(DeviceControl::getDevice(), commandPool, 1, &commandBuffer); } -void Buffers::createMemoryAllocator(VkInstance vkInstance) { - VmaVulkanFunctions vulkanFuncs{ - .vkGetInstanceProcAddr = vkGetInstanceProcAddr, - .vkGetDeviceProcAddr = vkGetDeviceProcAddr, - }; - VmaAllocatorCreateInfo allocInfo{ - .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, - .physicalDevice = DeviceControl::getPhysicalDevice(), - .device = DeviceControl::getDevice(), - .pVulkanFunctions = &vulkanFuncs, - .instance = vkInstance, - .vulkanApiVersion = VK_API_VERSION_1_3, - - }; - vmaCreateAllocator(&allocInfo, &_allocator); -} -Agnosia_T::AllocatedBuffer Buffers::createBuffer(size_t allocSize, - VkBufferUsageFlags usage, - VmaMemoryUsage memUsage) { - // Allocate the buffer we will use for Device Addresses - VkBufferCreateInfo bufferInfo{.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .size = allocSize, - .usage = usage}; - VmaAllocationCreateInfo vmaAllocInfo{ - .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, .usage = memUsage}; - - Agnosia_T::AllocatedBuffer newBuffer; - if (vmaCreateBuffer(_allocator, &bufferInfo, &vmaAllocInfo, &newBuffer.buffer, - &newBuffer.allocation, &newBuffer.info) != VK_SUCCESS) { - throw std::runtime_error("Failed to allocate a buffer using VMA!"); - } - return newBuffer; -} - -Agnosia_T::GPUMeshBuffers -Buffers::sendMesh(std::span indices, - std::span vertices) { - - const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex); - const size_t indexBufferSize = indices.size() * sizeof(uint32_t); - - Agnosia_T::GPUMeshBuffers newSurface; - - // Create a Vertex Buffer here, infinitely easier than the old Vulkan method! - newSurface.vertexBuffer = createBuffer( - vertexBufferSize, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VMA_MEMORY_USAGE_GPU_ONLY); - // Find the address of the vertex buffer! - VkBufferDeviceAddressInfo deviceAddressInfo{ - .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, - .buffer = newSurface.vertexBuffer.buffer, - }; - newSurface.vertexBufferAddress = - vkGetBufferDeviceAddress(DeviceControl::getDevice(), &deviceAddressInfo); - - // Create the index buffer to iterate over and check for duplicate vertices - newSurface.indexBuffer = createBuffer(indexBufferSize, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VMA_MEMORY_USAGE_GPU_ONLY); - - Agnosia_T::AllocatedBuffer stagingBuffer = - createBuffer(vertexBufferSize + indexBufferSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - - void *data = stagingBuffer.allocation->GetMappedData(); - - // Copy the vertex buffer - memcpy(data, vertices.data(), vertexBufferSize); - // Copy the index buffer - memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize); - - immediate_submit([&](VkCommandBuffer cmd) { - VkBufferCopy vertexCopy{0}; - vertexCopy.dstOffset = 0; - vertexCopy.srcOffset = 0; - vertexCopy.size = vertexBufferSize; - - vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer, - 1, &vertexCopy); - - VkBufferCopy indexCopy{0}; - indexCopy.dstOffset = 0; - indexCopy.srcOffset = vertexBufferSize; - indexCopy.size = indexBufferSize; - - vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, 1, - &indexCopy); - }); - vmaDestroyBuffer(_allocator, stagingBuffer.buffer, stagingBuffer.allocation); - return newSurface; -} void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, @@ -269,6 +247,11 @@ void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, vkBindBufferMemory(DeviceControl::getDevice(), buffer, bufferMemory, 0); } +VkDescriptorPool &Buffers::getDescriptorPool() { return descriptorPool; } +VkDescriptorSet &Buffers::getDescriptorSet() { return descriptorSet; } +VkDescriptorSetLayout &Buffers::getDescriptorSetLayout() { + return descriptorSetLayout; +} void Buffers::destroyBuffers() { vkDestroyBuffer(DeviceControl::getDevice(), indexBuffer, nullptr); @@ -278,202 +261,10 @@ void Buffers::destroyBuffers() { vkFreeMemory(DeviceControl::getDevice(), vertexBufferMemory, nullptr); } -// ------------------------------ Uniform Buffer Setup -// -------------------------------- // -void Buffers::createDescriptorSetLayout() { - // Create a table of pointers to data, a Descriptor Set! - // --------------------- UBO Layout --------------------- // - VkDescriptorSetLayoutBinding uboLayoutBinding{}; - uboLayoutBinding.binding = 0; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - // Model-View-Projection matrix is in a single uniform buffer, so just 1 - // descriptor. - uboLayoutBinding.descriptorCount = 1; - // We are only using this buffer in the vertex shader, so set the flags thus. - uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - // Immutable Samplers is relevant for image sampling. - uboLayoutBinding.pImmutableSamplers = nullptr; - - // --------------- Texture Sampler Layout --------------- // - VkDescriptorSetLayoutBinding samplerLayoutBinding{}; - samplerLayoutBinding.binding = 1; - samplerLayoutBinding.descriptorCount = 1; - samplerLayoutBinding.descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - samplerLayoutBinding.pImmutableSamplers = nullptr; - samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - - std::array bindings = {uboLayoutBinding, - samplerLayoutBinding}; - VkDescriptorSetLayoutCreateInfo layoutInfo{}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = static_cast(bindings.size()); - layoutInfo.pBindings = bindings.data(); - - if (vkCreateDescriptorSetLayout(DeviceControl::getDevice(), &layoutInfo, - nullptr, - &descriptorSetLayout) != VK_SUCCESS) { - throw std::runtime_error("Failed to create descriptor set layout!"); - } -} -void Buffers::createUniformBuffers() { - // Map the uniform buffer to memory as a pointer we can use to write data to - // 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(UniformBufferObject); - - 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(DeviceControl::getDevice(), uniformBuffersMemory[i], 0, - bufferSize, 0, &uniformBuffersMapped[i]); - } -} -void Buffers::updateUniformBuffer(uint32_t currentImage) { - // Update the uniform buffer every frame to change the position, but notably, - // use chrono to know exactly how much to move so we aren't locked to the - // framerate as the world time. - - static auto startTime = std::chrono::high_resolution_clock::now(); - // Calculate the time in seconds since rendering has began to floating point - // precision. - auto currentTime = std::chrono::high_resolution_clock::now(); - float time = std::chrono::duration( - currentTime - startTime) - .count(); - - UniformBufferObject ubo{}; - ubo.time = time; - // Modify the model projection transformation to rotate around the Z over - // time. - ubo.model = glm::translate(glm::mat4(1.0f), - glm::vec3(objPos[0], objPos[1], objPos[2])); - // ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(30.0f), - // glm::vec3(0.0f, 0.0f, 1.0f)); - // Modify the view transformation to look at the object from above at a 45 - // degree angle. This takes the eye position, center position, and the up - // direction. - ubo.view = glm::lookAt(glm::vec3(camPos[0], camPos[1], camPos[2]), - 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), - 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. - ubo.proj[1][1] *= -1; - - memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo)); -} -void Buffers::destroyUniformBuffer() { - 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 poolSizes{}; - poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSizes[0].descriptorCount = static_cast(MAX_FRAMES_IN_FLIGHT); - poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - poolSizes[1].descriptorCount = static_cast(MAX_FRAMES_IN_FLIGHT); - - VkDescriptorPoolCreateInfo poolInfo{}; - poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = static_cast(poolSizes.size()); - poolInfo.pPoolSizes = poolSizes.data(); - poolInfo.maxSets = static_cast(MAX_FRAMES_IN_FLIGHT); - - if (vkCreateDescriptorPool(DeviceControl::getDevice(), &poolInfo, nullptr, - &descriptorPool) != VK_SUCCESS) { - throw std::runtime_error("failed to create descriptor pool!"); - } -} -void Buffers::createDescriptorSets() { - std::vector layouts(MAX_FRAMES_IN_FLIGHT, - descriptorSetLayout); - VkDescriptorSetAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = descriptorPool; - allocInfo.descriptorSetCount = static_cast(MAX_FRAMES_IN_FLIGHT); - allocInfo.pSetLayouts = layouts.data(); - - 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 < MAX_FRAMES_IN_FLIGHT; i++) { - VkDescriptorBufferInfo bufferInfo{}; - bufferInfo.buffer = uniformBuffers[i]; - bufferInfo.offset = 0; - bufferInfo.range = sizeof(UniformBufferObject); - - VkDescriptorImageInfo imageInfo{}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = Texture::getTextureImageView(); - imageInfo.sampler = Texture::getTextureSampler(); - - std::array descriptorWrites{}; - - descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrites[0].dstSet = descriptorSets[i]; - descriptorWrites[0].dstBinding = 0; - descriptorWrites[0].dstArrayElement = 0; - descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorWrites[0].descriptorCount = 1; - descriptorWrites[0].pBufferInfo = &bufferInfo; - - descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrites[1].dstSet = descriptorSets[i]; - descriptorWrites[1].dstBinding = 1; - descriptorWrites[1].dstArrayElement = 0; - descriptorWrites[1].descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorWrites[1].descriptorCount = 1; - descriptorWrites[1].pImageInfo = &imageInfo; - - vkUpdateDescriptorSets(DeviceControl::getDevice(), - static_cast(descriptorWrites.size()), - descriptorWrites.data(), 0, nullptr); - } -} -void Buffers::destroyDescriptorPool() { - vkDestroyDescriptorPool(DeviceControl::getDevice(), descriptorPool, nullptr); -} -VkDescriptorPool &Buffers::getDescriptorPool() { return descriptorPool; } -std::vector &Buffers::getDescriptorSets() { - return descriptorSets; -} -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::getDistanceField() { return distanceField; } uint32_t Buffers::getMaxFramesInFlight() { return MAX_FRAMES_IN_FLIGHT; } std::vector &Buffers::getCommandBuffers() { return commandBuffers; } -std::vector &Buffers::getUniformBuffers() { return uniformBuffers; } -std::vector &Buffers::getUniformBuffersMemory() { - return uniformBuffersMemory; -} + VkCommandPool &Buffers::getCommandPool() { return commandPool; } -VkDescriptorSetLayout &Buffers::getDescriptorSetLayout() { - return descriptorSetLayout; -} -std::vector &Buffers::getVertices() { return vertices; } -std::vector &Buffers::getIndices() { return indices; } +uint32_t Buffers::getIndicesSize() { return indicesSize; } diff --git a/src/graphics/buffers.h b/src/graphics/buffers.h index df86cba..be65a6d 100644 --- a/src/graphics/buffers.h +++ b/src/graphics/buffers.h @@ -1,51 +1,37 @@ #pragma once #include -#include + #define VK_NO_PROTOTYPES #include "../types.h" +#include "model.h" #include "volk.h" #include #define GLFW_INCLUDE_VULKAN #include class Buffers { - public: static Agnosia_T::AllocatedBuffer createBuffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memUsage); static void createMemoryAllocator(VkInstance vkInstance); - static Agnosia_T::GPUMeshBuffers - sendMesh(std::span indices, std::span vertices); + static void createDescriptorSetLayout(); + static void createDescriptorSet(std::vector models); + static void createDescriptorPool(); static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags props, VkBuffer &buffer, VkDeviceMemory &bufferMemory); static uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags flags); static void destroyBuffers(); - static void createDescriptorSetLayout(); - static void createUniformBuffers(); - static void updateUniformBuffer(uint32_t currentImage); - static void destroyUniformBuffer(); - static void createDescriptorPool(); - static void createDescriptorSets(); - static void destroyDescriptorPool(); static VkDescriptorPool &getDescriptorPool(); - static VkDescriptorSetLayout &getDescriptorSetLayout(); - static std::vector &getDescriptorSets(); + static VkDescriptorSet &getDescriptorSet(); - static float *getObjPos(); - static float *getCamPos(); - static float *getCenterPos(); - static float *getUpDir(); - static float &getDepthField(); - static float *getDistanceField(); + static VkDescriptorSetLayout &getDescriptorSetLayout(); static uint32_t getMaxFramesInFlight(); static std::vector &getCommandBuffers(); - static std::vector &getUniformBuffers(); - static std::vector &getUniformBuffersMemory(); + static VkCommandPool &getCommandPool(); - static std::vector &getVertices(); - static std::vector &getIndices(); + static uint32_t getIndicesSize(); }; diff --git a/src/graphics/graphicspipeline.cpp b/src/graphics/graphicspipeline.cpp index 68d78b0..0548fe2 100644 --- a/src/graphics/graphicspipeline.cpp +++ b/src/graphics/graphicspipeline.cpp @@ -6,7 +6,18 @@ #include "render.h" #include "texture.h" #include +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include + #include +#include + +float camPos[4] = {3.0f, 3.0f, 3.0f, 0.44f}; +float centerPos[4] = {0.0f, 0.0f, 0.0f, 0.44f}; +float upDir[4] = {0.0f, 0.0f, 1.0f, 0.44f}; +float depthField = 45.0f; +float distanceField[2] = {0.1f, 100.0f}; std::vector dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; @@ -84,15 +95,6 @@ void Graphics::createGraphicsPipeline() { vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - auto bindingDescription = Agnosia_T::Vertex::getBindingDescription(); - auto attributeDescriptions = Agnosia_T::Vertex::getAttributeDescriptions(); - - vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; - vertexInputInfo.vertexAttributeDescriptionCount = - static_cast(attributeDescriptions.size()); - vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); - // ------------------- STAGE 5 - RASTERIZATION ----------------- // // Take Vertex shader vertices and fragmentize them for the frament shader. // The rasterizer also can perform depth testing, face culling, and scissor @@ -176,7 +178,7 @@ void Graphics::createGraphicsPipeline() { dynamicState.pDynamicStates = dynamicStates.data(); VkPushConstantRange pushConstant{ - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .stageFlags = VK_SHADER_STAGE_ALL, .offset = 0, .size = sizeof(Agnosia_T::GPUPushConstants), }; @@ -351,26 +353,45 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer, scissor.offset = {0, 0}; scissor.extent = DeviceControl::getSwapChainExtent(); vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + int texID = 0; + for (Model *model : Model::getInstances()) { - Agnosia_T::GPUMeshBuffers Model = - Buffers::sendMesh(Buffers::getIndices(), Buffers::getVertices()); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipelineLayout, 0, 1, &Buffers::getDescriptorSet(), + 0, nullptr); - Agnosia_T::GPUPushConstants pushConsts; - pushConsts.vertexBuffer = Model.vertexBufferAddress; + Agnosia_T::GPUPushConstants pushConsts; + pushConsts.vertexBuffer = model->getBuffers().vertexBufferAddress; + pushConsts.objPosition = model->getPos(); + pushConsts.textureID = texID; - vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, - 0, sizeof(Agnosia_T::GPUPushConstants), &pushConsts); - vkCmdBindIndexBuffer(commandBuffer, Model.indexBuffer.buffer, 0, - VK_INDEX_TYPE_UINT32); + pushConsts.model = + glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); - vkCmdBindDescriptorSets( - commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, - &Buffers::getDescriptorSets()[Render::getCurrentFrame()], 0, nullptr); + pushConsts.view = + glm::lookAt(glm::vec3(camPos[0], camPos[1], camPos[2]), + glm::vec3(centerPos[0], centerPos[1], centerPos[2]), + glm::vec3(upDir[0], upDir[1], upDir[2])); - vkCmdDrawIndexed(commandBuffer, - static_cast(Buffers::getIndices().size()), 1, 0, 0, - 0); + pushConsts.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. + pushConsts.proj[1][1] *= -1; + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_ALL, 0, + sizeof(Agnosia_T::GPUPushConstants), &pushConsts); + + vkCmdBindIndexBuffer(commandBuffer, model->getBuffers().indexBuffer.buffer, + 0, VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(commandBuffer, static_cast(model->getIndices()), + 1, 0, 0, 0); + texID++; + } ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer); vkCmdEndRendering(commandBuffer); @@ -403,10 +424,16 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer, .pImageMemoryBarriers = &prePresentImageBarrier, }; - vkCmdPipelineBarrier2( - Buffers ::getCommandBuffers()[Render::getCurrentFrame()], &depInfo); + vkCmdPipelineBarrier2(Buffers::getCommandBuffers()[Render::getCurrentFrame()], + &depInfo); if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { throw std::runtime_error("failed to record command buffer!"); } } + +float *Graphics::getCamPos() { return camPos; } +float *Graphics::getCenterPos() { return centerPos; } +float *Graphics::getUpDir() { return upDir; } +float &Graphics::getDepthField() { return depthField; } +float *Graphics::getDistanceField() { return distanceField; } diff --git a/src/graphics/graphicspipeline.h b/src/graphics/graphicspipeline.h index e177a45..ad64512 100644 --- a/src/graphics/graphicspipeline.h +++ b/src/graphics/graphicspipeline.h @@ -13,4 +13,10 @@ public: static void createCommandBuffer(); static void recordCommandBuffer(VkCommandBuffer cmndBuffer, uint32_t imageIndex); + + static float *getCamPos(); + static float *getCenterPos(); + static float *getUpDir(); + static float &getDepthField(); + static float *getDistanceField(); }; diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp new file mode 100644 index 0000000..04fd909 --- /dev/null +++ b/src/graphics/material.cpp @@ -0,0 +1,19 @@ +#include "material.h" + +Material::Material(const std::string &matID, const std::string &texPath) + : ID(matID), texturePath(texPath) {} + +std::string Material::getID() const { return ID; } +std::string Material::getTexturePath() const { return texturePath; } + +VkImage &Material::getTextureImage() { return this->textureImage; } +VkImageView &Material::getTextureView() { return this->textureImageView; } +VkSampler &Material::getTextureSampler() { return this->textureSampler; } + +void Material::setTextureImage(VkImage image) { this->textureImage = image; } +void Material::setTextureView(VkImageView imageView) { + this->textureImageView = imageView; +} +void Material::setTextureSampler(VkSampler sampler) { + this->textureSampler = sampler; +} diff --git a/src/graphics/material.h b/src/graphics/material.h new file mode 100644 index 0000000..18f3128 --- /dev/null +++ b/src/graphics/material.h @@ -0,0 +1,26 @@ + +#define VK_NO_PROTOTYPES +#include "volk.h" +#include + +class Material { +protected: + std::string ID; + std::string texturePath; + + VkImage textureImage; + VkImageView textureImageView; + VkSampler textureSampler; + +public: + Material(const std::string &matID, const std::string &texPath); + std::string getID() const; + std::string getTexturePath() const; + VkImage &getTextureImage(); + VkImageView &getTextureView(); + VkSampler &getTextureSampler(); + + void setTextureImage(VkImage image); + void setTextureView(VkImageView imageView); + void setTextureSampler(VkSampler sampler); +}; diff --git a/src/graphics/model.cpp b/src/graphics/model.cpp index bef6691..3a39550 100644 --- a/src/graphics/model.cpp +++ b/src/graphics/model.cpp @@ -1,13 +1,25 @@ #include "buffers.h" #include "model.h" -#include +#include +#include +#include #define TINY_OBJ_IMPLEMENTATION +#include #include - #define GLM_ENABLE_EXPERIMENTAL +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include "../devicelibrary.h" +#include #include +#define VMA_STATIC_VULKAN_FUNCTIONS 0 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#define VMA_IMPLEMENTATION +#include "vk_mem_alloc.h" + +std::vector Model::instances; +VmaAllocator _allocator; namespace std { template <> struct hash { size_t operator()(Agnosia_T::Vertex const &vertex) const { @@ -18,15 +30,90 @@ template <> struct hash { } }; } // namespace std +void Model::createMemoryAllocator(VkInstance vkInstance) { + VmaVulkanFunctions vulkanFuncs{ + .vkGetInstanceProcAddr = vkGetInstanceProcAddr, + .vkGetDeviceProcAddr = vkGetDeviceProcAddr, + }; + VmaAllocatorCreateInfo allocInfo{ + .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, + .physicalDevice = DeviceControl::getPhysicalDevice(), + .device = DeviceControl::getDevice(), + .pVulkanFunctions = &vulkanFuncs, + .instance = vkInstance, + .vulkanApiVersion = VK_API_VERSION_1_3, -const std::string MODEL_PATH = "assets/models/viking_room.obj"; + }; + vmaCreateAllocator(&allocInfo, &_allocator); +} +Agnosia_T::AllocatedBuffer createBuffer(size_t allocSize, + VkBufferUsageFlags usage, + VmaMemoryUsage memUsage) { + // Allocate the buffer we will use for Device Addresses + VkBufferCreateInfo bufferInfo{.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .size = allocSize, + .usage = usage}; + VmaAllocationCreateInfo vmaAllocInfo{ + .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, .usage = memUsage}; -void Model::loadModel(glm::vec3 position) { + Agnosia_T::AllocatedBuffer newBuffer; + if (vmaCreateBuffer(_allocator, &bufferInfo, &vmaAllocInfo, &newBuffer.buffer, + &newBuffer.allocation, &newBuffer.info) != VK_SUCCESS) { + throw std::runtime_error("Failed to allocate a buffer using VMA!"); + } + return newBuffer; +} +void immediate_submit(std::function &&function) { + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = Buffers::getCommandPool(); + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(DeviceControl::getDevice(), &allocInfo, + &commandBuffer); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + function(commandBuffer); + + vkEndCommandBuffer(commandBuffer); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + vkQueueSubmit(DeviceControl::getGraphicsQueue(), 1, &submitInfo, + VK_NULL_HANDLE); + vkQueueWaitIdle(DeviceControl::getGraphicsQueue()); + + vkFreeCommandBuffers(DeviceControl::getDevice(), Buffers::getCommandPool(), 1, + &commandBuffer); +} + +Model::Model(const std::string &modelID, const Material &material, + const std::string &modelPath, const glm::vec3 &objPos) + : ID(modelID), material(material), objPosition(objPos), + modelPath(modelPath) { + instances.push_back(this); +} + +void Model::populateData() { + + std::vector vertices; + // Index buffer definition, showing which points to reuse. + std::vector indices; tinyobj::ObjReaderConfig readerConfig; - tinyobj::ObjReader reader; - if (!reader.ParseFromFile(MODEL_PATH, readerConfig)) { + if (!reader.ParseFromFile(modelPath, readerConfig)) { if (!reader.Error().empty()) { throw std::runtime_error(reader.Error()); } @@ -38,15 +125,16 @@ void Model::loadModel(glm::vec3 position) { auto &attrib = reader.GetAttrib(); auto &shapes = reader.GetShapes(); auto &materials = reader.GetMaterials(); + std::unordered_map uniqueVertices{}; for (const auto &shape : shapes) { for (const auto &index : shape.mesh.indices) { Agnosia_T::Vertex vertex{}; - vertex.pos = {attrib.vertices[3 * index.vertex_index + 0] + position.x, - attrib.vertices[3 * index.vertex_index + 1] + position.y, - attrib.vertices[3 * index.vertex_index + 2] + position.z}; + 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. @@ -58,11 +146,76 @@ void Model::loadModel(glm::vec3 position) { vertex.color = {1.0f, 1.0f, 1.0f}; if (uniqueVertices.count(vertex) == 0) { - uniqueVertices[vertex] = - static_cast(Buffers::getVertices().size()); - Buffers::getVertices().push_back(vertex); + uniqueVertices[vertex] = static_cast(vertices.size()); + vertices.push_back(vertex); } - Buffers::getIndices().push_back(uniqueVertices[vertex]); + indices.push_back(uniqueVertices[vertex]); } } + + const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex); + const size_t indexBufferSize = indices.size() * sizeof(uint32_t); + + Agnosia_T::GPUMeshBuffers newSurface; + + // Create a Vertex Buffer here, infinitely easier than the old Vulkan method! + newSurface.vertexBuffer = createBuffer( + vertexBufferSize, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + // Find the address of the vertex buffer! + VkBufferDeviceAddressInfo deviceAddressInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .buffer = newSurface.vertexBuffer.buffer, + }; + newSurface.vertexBufferAddress = + vkGetBufferDeviceAddress(DeviceControl::getDevice(), &deviceAddressInfo); + + // Create the index buffer to iterate over and check for duplicate vertices + newSurface.indexBuffer = createBuffer(indexBufferSize, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + + Agnosia_T::AllocatedBuffer stagingBuffer = + createBuffer(vertexBufferSize + indexBufferSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + + void *data = stagingBuffer.allocation->GetMappedData(); + + // Copy the vertex buffer + memcpy(data, vertices.data(), vertexBufferSize); + // Copy the index buffer + memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize); + + immediate_submit([&](VkCommandBuffer cmd) { + VkBufferCopy vertexCopy{0}; + vertexCopy.dstOffset = 0; + vertexCopy.srcOffset = 0; + vertexCopy.size = vertexBufferSize; + + vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer, + 1, &vertexCopy); + + VkBufferCopy indexCopy{0}; + indexCopy.dstOffset = 0; + indexCopy.srcOffset = vertexBufferSize; + indexCopy.size = indexBufferSize; + + vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, 1, + &indexCopy); + }); + vmaDestroyBuffer(_allocator, stagingBuffer.buffer, stagingBuffer.allocation); + + this->buffers = newSurface; + this->objPosition = objPosition; + this->indiceCount = indices.size(); } + +std::string Model::getID() { return this->ID; } +glm::vec3 &Model::getPos() { return this->objPosition; } +Material &Model::getMaterial() { return this->material; } +Agnosia_T::GPUMeshBuffers Model::getBuffers() { return this->buffers; } +uint32_t Model::getIndices() { return this->indiceCount; } +const std::vector &Model::getInstances() { return instances; } diff --git a/src/graphics/model.h b/src/graphics/model.h index d00517b..d2bdd0f 100644 --- a/src/graphics/model.h +++ b/src/graphics/model.h @@ -1,8 +1,39 @@ #pragma once -#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include + +#define VK_NO_PROTOTYPES + +#include "../types.h" + +#include "material.h" +#include "volk.h" #include +#include class Model { +protected: + std::string ID; + Agnosia_T::GPUMeshBuffers buffers; + Material material; + glm::vec3 objPosition; + uint32_t indiceCount; + std::string modelPath; + static std::vector instances; + public: - static void loadModel(glm::vec3 position); + Model(const std::string &modelID, const Material &material, + const std::string &modelPath, const glm::vec3 &opjPos); + + static void createMemoryAllocator(VkInstance instance); + static const std::vector &getInstances(); + + void populateData(); + + Agnosia_T::GPUMeshBuffers getBuffers(); + std::string getID(); + glm::vec3 &getPos(); + Material &getMaterial(); + std::string getModelPath(); + uint32_t getIndices(); }; diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 40aacf2..ea5bacb 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -59,16 +59,12 @@ void Render::drawFrame() { throw std::runtime_error("failed to acquire swap chain image!"); } - Buffers::updateUniformBuffer(currentFrame); - vkResetFences(DeviceControl::getDevice(), 1, &inFlightFences[currentFrame]); vkResetCommandBuffer(Buffers::getCommandBuffers()[currentFrame], /*VkCommandBufferResetFlagBits*/ 0); Graphics::recordCommandBuffer(Buffers::getCommandBuffers()[currentFrame], imageIndex); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), - Buffers::getCommandBuffers()[currentFrame]); VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; diff --git a/src/graphics/texture.cpp b/src/graphics/texture.cpp index 04027c3..db109a6 100644 --- a/src/graphics/texture.cpp +++ b/src/graphics/texture.cpp @@ -1,6 +1,7 @@ #include "../devicelibrary.h" #include "buffers.h" #include "texture.h" +#include #include #include #define STB_IMAGE_IMPLEMENTATION @@ -8,14 +9,10 @@ uint32_t mipLevels; -VkImage textureImage; VkDeviceMemory textureImageMemory; VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; -VkImageView textureImageView; -VkSampler textureSampler; - VkImage colorImage; VkImageView colorImageView; VkDeviceMemory colorImageMemory; @@ -24,8 +21,6 @@ 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, @@ -290,118 +285,119 @@ void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t textureWidth, } // -------------------------------- Image Libraries // ------------------------------- // -void Texture::createTextureImage() { +void Texture::createMaterialTextures(std::vector models) { // Import pixels from image with data on color channels, width and height, and // 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(TEXTURE_PATH.c_str(), &textureWidth, - &textureHeight, &textureChannels, STBI_rgb_alpha); - mipLevels = static_cast(std::floor( - std::log2(std::max(textureWidth, textureHeight)))) + - 1; + for (Model *model : models) { - VkDeviceSize imageSize = textureWidth * textureHeight * 4; + int textureWidth, textureHeight, textureChannels; - if (!pixels) { - throw std::runtime_error("Failed to load texture!"); - } - VkBuffer stagingBuffer; - VkDeviceMemory stagingBufferMemory; - Buffers::createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - stagingBuffer, stagingBufferMemory); + stbi_uc *pixels = + stbi_load(model->getMaterial().getTexturePath().c_str(), &textureWidth, + &textureHeight, &textureChannels, STBI_rgb_alpha); - void *data; - vkMapMemory(DeviceControl::getDevice(), stagingBufferMemory, 0, imageSize, 0, - &data); - memcpy(data, pixels, static_cast(imageSize)); - vkUnmapMemory(DeviceControl::getDevice(), stagingBufferMemory); + mipLevels = static_cast(std::floor( + std::log2(std::max(textureWidth, textureHeight)))) + + 1; - stbi_image_free(pixels); + VkDeviceSize imageSize = textureWidth * textureHeight * 4; - createImage(textureWidth, textureHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT, - VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, - textureImageMemory); + if (!pixels) { + throw std::runtime_error("Failed to load texture!"); + } + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + Buffers::createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + stagingBuffer, stagingBufferMemory); - transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels); - copyBufferToImage(stagingBuffer, textureImage, - static_cast(textureWidth), - static_cast(textureHeight)); + void *data; + vkMapMemory(DeviceControl::getDevice(), stagingBufferMemory, 0, imageSize, + 0, &data); + memcpy(data, pixels, static_cast(imageSize)); + vkUnmapMemory(DeviceControl::getDevice(), stagingBufferMemory); - vkDestroyBuffer(DeviceControl::getDevice(), stagingBuffer, nullptr); - vkFreeMemory(DeviceControl::getDevice(), stagingBufferMemory, nullptr); + stbi_image_free(pixels); - generateMipmaps(textureImage, VK_FORMAT_R8G8B8A8_SRGB, textureWidth, - textureHeight, mipLevels); -} -void Texture::createTextureImageView() { - // Create a texture image view, which is a struct of information about the - // image. - 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. - VkSamplerCreateInfo samplerInfo{}; - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - // These two options define the filtering method when sampling the texture. - // It also handles zooming in versus out, min vs mag! - samplerInfo.magFilter = VK_FILTER_LINEAR; // TODO: CUBIC - samplerInfo.minFilter = VK_FILTER_LINEAR; // TODO: CUBIC + createImage(textureWidth, textureHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT, + VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + model->getMaterial().getTextureImage(), textureImageMemory); - // These options define UVW edge modes, ClampToEdge extends the last pixels to - // the edges when larger than the UVW. - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + transitionImageLayout(model->getMaterial().getTextureImage(), + VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels); + copyBufferToImage(stagingBuffer, model->getMaterial().getTextureImage(), + static_cast(textureWidth), + static_cast(textureHeight)); - VkPhysicalDeviceProperties properties{}; - vkGetPhysicalDeviceProperties(DeviceControl::getPhysicalDevice(), - &properties); - // Enable or Disable Anisotropy, and set the amount. - samplerInfo.anisotropyEnable = VK_TRUE; - samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy; + vkDestroyBuffer(DeviceControl::getDevice(), stagingBuffer, nullptr); + vkFreeMemory(DeviceControl::getDevice(), stagingBufferMemory, nullptr); - // When sampling with Clamp to Border, the border color is defined here. - samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - // Normalizing coordinates changes texCoords from [0, texWidth] to [0, 1]. - // This is what should ALWAYS be used, because it means you can use varying - // texture sizes. Another TODO: Normalizing - samplerInfo.unnormalizedCoordinates = VK_FALSE; - // Compare texels to a value and use the output in filtering! - // This is mainly used in percentage-closer filtering on shadow maps, this - // will be revisted eventually... - samplerInfo.compareEnable = VK_FALSE; - samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + generateMipmaps(model->getMaterial().getTextureImage(), + VK_FORMAT_R8G8B8A8_SRGB, textureWidth, textureHeight, + mipLevels); + // Create a texture image view, which is a struct of information about the + // image. + model->getMaterial().setTextureView(DeviceControl::createImageView( + model->getMaterial().getTextureImage(), VK_FORMAT_R8G8B8A8_SRGB, + VK_IMAGE_ASPECT_COLOR_BIT, mipLevels)); - // Mipmaps are basically LoD's for textures, different resolutions to load - // based on distance. These settings simply describe how to apply mipmapping. - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerInfo.mipLodBias = 0.0f; - samplerInfo.minLod = 0.0f; - samplerInfo.maxLod = VK_LOD_CLAMP_NONE; + // Create a sampler to access and parse the texture object. - if (vkCreateSampler(DeviceControl::getDevice(), &samplerInfo, nullptr, - &textureSampler) != VK_SUCCESS) { - throw std::runtime_error("failed to create texture sampler!"); + VkSamplerCreateInfo samplerInfo{}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + // These two options define the filtering method when sampling the texture. + // It also handles zooming in versus out, min vs mag! + samplerInfo.magFilter = VK_FILTER_LINEAR; // TODO: CUBIC + samplerInfo.minFilter = VK_FILTER_LINEAR; // TODO: CUBIC + + // These options define UVW edge modes, ClampToEdge extends the last pixels + // to the edges when larger than the UVW. + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + VkPhysicalDeviceProperties properties{}; + vkGetPhysicalDeviceProperties(DeviceControl::getPhysicalDevice(), + &properties); + // Enable or Disable Anisotropy, and set the amount. + samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy; + + // When sampling with Clamp to Border, the border color is defined here. + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + // Normalizing coordinates changes texCoords from [0, texWidth] to [0, 1]. + // This is what should ALWAYS be used, because it means you can use varying + // texture sizes. Another TODO: Normalizing + samplerInfo.unnormalizedCoordinates = VK_FALSE; + // Compare texels to a value and use the output in filtering! + // This is mainly used in percentage-closer filtering on shadow maps, this + // will be revisted eventually... + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + + // Mipmaps are basically LoD's for textures, different resolutions to load + // based on distance. These settings simply describe how to apply + // mipmapping. + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = VK_LOD_CLAMP_NONE; + + if (vkCreateSampler(DeviceControl::getDevice(), &samplerInfo, nullptr, + &model->getMaterial().getTextureSampler()) != + VK_SUCCESS) { + throw std::runtime_error("failed to create texture sampler!"); + } } } -void Texture::destroyTextureSampler() { - vkDestroySampler(DeviceControl::getDevice(), textureSampler, nullptr); - vkDestroyImageView(DeviceControl::getDevice(), textureImageView, nullptr); -} -void Texture::destroyTextureImage() { - vkDestroyImage(DeviceControl::getDevice(), textureImage, nullptr); - vkFreeMemory(DeviceControl::getDevice(), textureImageMemory, nullptr); -} + VkFormat Texture::findDepthFormat() { return findSupportedFormat( {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, @@ -438,8 +434,6 @@ void Texture::createDepthResources() { // ---------------------------- Getters & Setters // ---------------------------------// uint32_t Texture::getMipLevels() { return mipLevels; } -VkImageView &Texture::getTextureImageView() { return textureImageView; } -VkSampler &Texture::getTextureSampler() { return textureSampler; } VkImage &Texture::getColorImage() { return colorImage; } VkImageView &Texture::getColorImageView() { return colorImageView; } diff --git a/src/graphics/texture.h b/src/graphics/texture.h index 940bc2e..f55d19d 100644 --- a/src/graphics/texture.h +++ b/src/graphics/texture.h @@ -1,12 +1,14 @@ #pragma once +#include "model.h" + #define VK_NO_PROTOTYPES + #include "volk.h" #include class Texture { public: - static void createTextureImage(); - static void createTextureImageView(); - static void createTextureSampler(); + static const uint32_t TEXTURE_COUNT = 2; + static void createMaterialTextures(std::vector models); static void destroyTextureImage(); static void destroyTextureSampler(); static VkFormat findDepthFormat(); @@ -14,8 +16,6 @@ public: static void createColorResources(); // ------------ Getters & Setters ------------ // static uint32_t getMipLevels(); - static VkImageView &getTextureImageView(); - static VkSampler &getTextureSampler(); static VkImage &getColorImage(); static VkImageView &getColorImageView(); diff --git a/src/shaders/common.glsl b/src/shaders/common.glsl new file mode 100644 index 0000000..f117a1d --- /dev/null +++ b/src/shaders/common.glsl @@ -0,0 +1,21 @@ +#extension GL_EXT_buffer_reference : require +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_nonuniform_qualifier : require + +struct Vertex { + vec3 pos; + vec3 color; + vec2 texCoord; +}; + +layout(buffer_reference, scalar) readonly buffer VertexBuffer{ + Vertex vertices[]; +}; +layout( push_constant, scalar ) uniform constants { + VertexBuffer vertBuffer; + vec3 objPos; + int textureID; + mat4 model; + mat4 view; + mat4 proj; +} PushConstants; diff --git a/src/shaders/fragment.frag b/src/shaders/fragment.frag index ea2e60b..27d6329 100644 --- a/src/shaders/fragment.frag +++ b/src/shaders/fragment.frag @@ -1,5 +1,9 @@ #version 450 -layout(binding = 1) uniform sampler2D texSampler; +#extension GL_GOOGLE_include_directive : enable +#include "common.glsl" + +layout(binding = 1) uniform sampler2D texSampler[]; + layout(location = 0) in vec3 fragColor; layout(location = 1) in vec2 fragTexCoord; @@ -7,6 +11,5 @@ layout(location = 1) in vec2 fragTexCoord; layout(location = 0) out vec4 outColor; void main() { - - outColor = vec4(texture(texSampler, fragTexCoord).rgb, 1.0); + outColor = texture(texSampler[PushConstants.textureID], fragTexCoord); } diff --git a/src/shaders/vertex.vert b/src/shaders/vertex.vert index dab8105..ab0b4d2 100644 --- a/src/shaders/vertex.vert +++ b/src/shaders/vertex.vert @@ -1,32 +1,15 @@ #version 450 -#extension GL_EXT_buffer_reference : require - -layout(binding = 0) uniform UniformBufferObject { - float time; - mat4 model; - mat4 view; - mat4 proj; -} ubo; -struct Vertex { - - vec3 pos; - vec3 color; - vec2 texCoord; -}; - -layout(buffer_reference, std430) readonly buffer VertexBuffer{ - Vertex vertices[]; -}; -layout( push_constant ) uniform constants { - VertexBuffer vertBuffer; -}PushConstants; +#extension GL_GOOGLE_include_directive : enable +#include "common.glsl" layout(location = 0) out vec3 fragColor; layout(location = 1) out vec2 fragTexCoord; void main() { - Vertex v = PushConstants.vertBuffer.vertices[gl_VertexIndex]; - gl_Position = ubo.proj * ubo.view * ubo.model * vec4(v.pos, 1.0f); - fragColor = v.color.xyz; - fragTexCoord = v.texCoord; + Vertex vertex = PushConstants.vertBuffer.vertices[gl_VertexIndex]; + + gl_Position = PushConstants.proj * PushConstants.view * PushConstants.model * + vec4(vertex.pos + PushConstants.objPos, 1.0f); + fragColor = vertex.color.rgb; + fragTexCoord = vertex.texCoord; } diff --git a/src/types.h b/src/types.h index 858bba4..5108fc4 100644 --- a/src/types.h +++ b/src/types.h @@ -1,9 +1,7 @@ #pragma once #define GLM_FORCE_DEPTH_ZERO_TO_ONE - #include "vk_mem_alloc.h" -#include #include class Agnosia_T { @@ -11,38 +9,10 @@ public: struct Vertex { // This defines what a vertex is! // We control the position, color and texture coordinate here! - alignas(16) glm::vec3 pos; - alignas(16) glm::vec3 color; - alignas(8) glm::vec2 texCoord; + 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 - getAttributeDescriptions() { - std::array 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; @@ -60,5 +30,10 @@ public: }; struct GPUPushConstants { VkDeviceAddress vertexBuffer; + glm::vec3 objPosition; + int textureID; + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; }; };