Set up Vertex Buffer

This commit is contained in:
Lillian Salehi 2024-10-09 06:14:01 -05:00
parent 0fefb85d0a
commit 7e625a3db5
10 changed files with 146 additions and 27 deletions

View File

@ -6,7 +6,7 @@ SRC = $(shell find . -name "*.cpp")
SHDRSRC = $(shell find . -name "*.frag" -o -name "*vert")
SPV = $(SHDRSRC:%.vert=%.spv) $(SHDRSRC:%.frag=%.spv)
OBJ = $(SRC:%.cpp=%.o)
MAKEFLAGS += -j16
BIN=build/agnosiaengine
.PHONY: all

View File

@ -264,7 +264,7 @@ namespace DeviceControl {
// Do NOT blend with other windows on the system.
createSwapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createSwapChainInfo.presentMode = presentMode;
// This is interesting, clip pixels that are obscured for performance, but that means you wont be able to reaf them reliably..
// This is interesting, clip pixels that are obscured for performance, but that means you wont be able to read them reliably..
// I am curious if this would affect screen-space rendering techniques, may be something to note.
createSwapChainInfo.clipped = VK_TRUE;
// This is something that needs to be implemented later, operations like resizing the window invalidate the swap chain and

View File

@ -1,8 +1,10 @@
#include "entrypoint.h"
#include "graphics/buffers.h"
DeviceControl::devicelibrary deviceLibs;
Debug::vulkandebuglibs debugController;
Graphics::graphicspipeline graphicsPipeline;
RenderPresent::render renderPresentation;
Buffers::bufferslibrary buffers;
VkInstance vulkaninstance;
// Getters and Setters!
@ -40,7 +42,7 @@ void createInstance() {
appInfo.applicationVersion = VK_MAKE_VERSION(1,0,0); // Create a Major Minor Patch version number for the application!
appInfo.pEngineName = "Agnosia Engine"; // Give an internal name for the engine running
appInfo.engineVersion = VK_MAKE_VERSION(1,0,0); // Similar to the App version, give vulkan an *engine* version
appInfo.apiVersion = VK_API_VERSION_1_1; // Tell vulkan what the highest API version we will allow this program to run on
appInfo.apiVersion = VK_API_VERSION_1_3; // Tell vulkan what the highest API version we will allow this program to run on
VkInstanceCreateInfo createInfo{}; // Define parameters of new vulkan instance
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; // Tell vulkan this is a info structure
@ -52,7 +54,7 @@ void createInstance() {
void initVulkan() {
createInstance();
debugController.setupDebugMessenger(vulkaninstance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DNDEBUG flag (as per the makefile)
debugController.setupDebugMessenger(vulkaninstance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DDEBUG flag (as per the makefile)
deviceLibs.createSurface(vulkaninstance, Global::window);
deviceLibs.pickPhysicalDevice(vulkaninstance);
deviceLibs.createLogicalDevice();
@ -62,6 +64,7 @@ void initVulkan() {
graphicsPipeline.createGraphicsPipeline();
graphicsPipeline.createFramebuffers();
graphicsPipeline.createCommandPool();
buffers.createVertexBuffer();
graphicsPipeline.createCommandBuffer();
renderPresentation.createSyncObject();
}
@ -76,6 +79,7 @@ void mainLoop() { // This loop jus
void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library!
renderPresentation.cleanupSwapChain();
buffers.destroyVertexBuffer();
graphicsPipeline.destroyGraphicsPipeline();
graphicsPipeline.destroyRenderPass();
renderPresentation.destroyFenceSemaphores();

View File

@ -21,6 +21,7 @@ namespace Global {
VkQueue graphicsQueue;
VkQueue presentQueue;
GLFWwindow* window;
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.

View File

@ -1,10 +1,13 @@
#pragma once
#include <glm/ext/vector_float2.hpp>
#include <glm/ext/vector_float3.hpp>
#include <iostream>
#include <vector>
#include <optional>
#include <vulkan/vulkan_core.h>
#include "debug/vulkandebuglibs.h"
#include <array>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
@ -21,6 +24,34 @@ namespace Global {
const int MAX_FRAMES_IN_FLIGHT = 2;
extern GLFWwindow* window;
struct Vertex {
glm::vec2 pos;
glm::vec3 color;
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, 2> getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{};
attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32_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);
return attributeDescriptions;
}
};
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;

71
src/graphics/buffers.cpp Normal file
View File

@ -0,0 +1,71 @@
#include "buffers.h"
#include <iostream>
#include <vulkan/vulkan_core.h>
VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;
namespace Buffers {
const std::vector<Global::Vertex> vertices = {
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
};
uint32_t 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);
// 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++) {
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
return i;
}
}
throw std::runtime_error("failed to find suitable memory type!");
}
void bufferslibrary::createVertexBuffer() {
// Create a Vertex Buffer to hold the vertex information in memory so it doesn't have to be hardcoded!
// Size denotes the size of the buffer in bytes, 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.
VkBufferCreateInfo bufferInfo;
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = sizeof(vertices[0]) * vertices.size();
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufferInfo.pNext = NULL;
std::cerr << &bufferInfo << " " << &vertexBuffer << "\n";
if (vkCreateBuffer(Global::device, &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS) {
throw std::runtime_error("failed to create vertex buffer!");
}
// Query the memory requirements of the buffer.
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(Global::device, vertexBuffer, &memRequirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate vertex buffer memory!");
}
vkBindBufferMemory(Global::device, vertexBuffer, vertexBufferMemory, 0);
void* data;
vkMapMemory(Global::device, vertexBufferMemory, 0, bufferInfo.size, 0, &data);
memcpy(data, vertices.data(), (size_t) bufferInfo.size);
vkUnmapMemory(Global::device, vertexBufferMemory);
}
void bufferslibrary::destroyVertexBuffer() {
vkDestroyBuffer(Global::device, vertexBuffer, nullptr);
vkFreeMemory(Global::device, vertexBufferMemory, nullptr);
}
VkBuffer bufferslibrary::getVertexBuffer() {
return vertexBuffer;
}
std::vector<Global::Vertex> bufferslibrary::getVertices() {
return vertices;
}
}

12
src/graphics/buffers.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "../global.h"
namespace Buffers {
class bufferslibrary {
public:
void createVertexBuffer();
void destroyVertexBuffer();
VkBuffer getVertexBuffer();
std::vector<Global::Vertex> getVertices();
};
}

View File

@ -1,5 +1,7 @@
#include "graphicspipeline.h"
#include "buffers.h"
#include <vector>
namespace Graphics {
std::vector<VkDynamicState> dynamicStates = {
VK_DYNAMIC_STATE_VIEWPORT,
@ -11,6 +13,7 @@ namespace Graphics {
VkPipelineLayout pipelineLayout;
VkPipeline graphicsPipeline;
DeviceControl::devicelibrary deviceLibs;
Buffers::bufferslibrary buffers;
std::vector<VkFramebuffer> swapChainFramebuffers;
@ -75,10 +78,14 @@ namespace Graphics {
vertShaderStageInfo.pName = "main";
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 0;
vertexInputInfo.pVertexBindingDescriptions = nullptr;
vertexInputInfo.vertexAttributeDescriptionCount = 0;
vertexInputInfo.pVertexAttributeDescriptions = nullptr;
auto bindingDescription = Global::Vertex::getBindingDescription();
auto attributeDescriptions = Global::Vertex::getAttributeDescriptions();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(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 testing.
@ -265,8 +272,6 @@ namespace Graphics {
void graphicspipeline::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = 0; // Optional
beginInfo.pInheritanceInfo = nullptr; // Optional
if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
throw std::runtime_error("failed to begin recording command buffer!");
@ -286,7 +291,6 @@ namespace Graphics {
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
@ -299,10 +303,13 @@ namespace Graphics {
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = deviceLibs.getSwapChainExtent();
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
VkBuffer vertexBuffers[] = {buffers.getVertexBuffer()};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdDraw(commandBuffer, static_cast<uint32_t>(buffers.getVertices().size()), 1, 0, 0);
vkCmdEndRenderPass(commandBuffer);
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {

View File

@ -1,6 +1,7 @@
#pragma once
#include "../global.h"
#include "../devicelibrary.h"
#include "buffers.h"
#include <fstream>
namespace Graphics {
class graphicspipeline {

View File

@ -1,20 +1,12 @@
#version 450
// inPosition and inColor are vertex attributes, per-vertex properties defined in the vertex buffer!
// Layout assigns indices to access these inputs, dvec3 takes 2 slots so we must index it at 2. https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL)
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragColor;
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
vec3 colors[3] = vec3[](
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);
void main() {
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
fragColor = colors[gl_VertexIndex];
gl_Position = vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
}