mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Get vertex buffers working
This commit is contained in:
parent
eb1884ee8e
commit
b6a7634cc5
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace engine {
|
namespace engine::gfx {
|
||||||
|
|
||||||
enum class ShaderType {
|
enum class ShaderType {
|
||||||
VERTEX,
|
VERTEX,
|
||||||
@ -23,10 +24,28 @@ namespace engine {
|
|||||||
TRIANGLE_STRIP,
|
TRIANGLE_STRIP,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class IndexBufferFormat {
|
enum class VertexAttribFormat {
|
||||||
UNSIGNED_8_BITS,
|
VEC2,
|
||||||
UNSIGNED_16_BITS,
|
VEC3,
|
||||||
UNSIGNED_32_BITS,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VertexBufferDesc {
|
||||||
|
uint64_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexAttribDescription {
|
||||||
|
uint32_t location;
|
||||||
|
VertexAttribFormat format;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexFormat {
|
||||||
|
uint32_t stride;
|
||||||
|
std::vector<VertexAttribDescription> attributeDescriptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
// handles (incomplete types)
|
||||||
|
|
||||||
|
struct VertexBuffer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,37 +2,14 @@
|
|||||||
|
|
||||||
#include "engine_api.h"
|
#include "engine_api.h"
|
||||||
|
|
||||||
|
#include "gfx.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
namespace gfx {
|
|
||||||
|
|
||||||
enum class BufferUsage {
|
|
||||||
DEFAULT,
|
|
||||||
UPLOAD,
|
|
||||||
READBACK,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class BindFlag {
|
|
||||||
NONE = 0,
|
|
||||||
UNIFORM_BUFFER = 1 << 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BufferDesc {
|
|
||||||
uint64_t size;
|
|
||||||
BufferUsage usage;
|
|
||||||
BindFlag bindFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
// handles (incomplete types)
|
|
||||||
|
|
||||||
class BufferHandle;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class ENGINE_API GFXDevice {
|
class ENGINE_API GFXDevice {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -42,15 +19,18 @@ namespace engine {
|
|||||||
GFXDevice& operator=(const GFXDevice&) = delete;
|
GFXDevice& operator=(const GFXDevice&) = delete;
|
||||||
~GFXDevice();
|
~GFXDevice();
|
||||||
|
|
||||||
|
// adds a vertex buffer draw call to the queue
|
||||||
|
void drawBuffer(const gfx::VertexBuffer* vb);
|
||||||
|
|
||||||
// Call once per frame. Executes all queued draw calls and renders to the screen.
|
// Call once per frame. Executes all queued draw calls and renders to the screen.
|
||||||
void draw();
|
void draw();
|
||||||
|
|
||||||
// creates the equivalent of an OpenGL shader program & vertex attrib configuration
|
// creates the equivalent of an OpenGL shader program & vertex attrib configuration
|
||||||
void createPipeline(const char* vertShaderPath, const char* fragShaderPath);
|
void createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat);
|
||||||
|
|
||||||
// creates a vertex array for holding mesh data
|
// creates a vertex array for holding mesh data
|
||||||
gfx::BufferHandle* createVertexBuffer(const gfx::BufferDesc& desc, const void* vertices, const void* indices);
|
gfx::VertexBuffer* createVertexBuffer(uint32_t size, const void* vertices, const void* indices);
|
||||||
void destroyBuffer(const gfx::BufferHandle* buffer);
|
void destroyVertexBuffer(const gfx::VertexBuffer* buffer);
|
||||||
|
|
||||||
// wait until all the active GPU queues have finished working
|
// wait until all the active GPU queues have finished working
|
||||||
void waitIdle();
|
void waitIdle();
|
||||||
|
@ -5,6 +5,11 @@
|
|||||||
#include "resource_manager.hpp"
|
#include "resource_manager.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
static engine::gfx::VertexBuffer* buffer;
|
||||||
|
static engine::gfx::VertexBuffer* buffer2;
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
Application::Application(const char* appName, const char* appVersion)
|
Application::Application(const char* appName, const char* appVersion)
|
||||||
@ -14,22 +19,48 @@ namespace engine {
|
|||||||
|
|
||||||
engine::ResourceManager resMan{};
|
engine::ResourceManager resMan{};
|
||||||
|
|
||||||
m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str());
|
struct Vertex {
|
||||||
|
glm::vec2 pos;
|
||||||
gfx::BufferDesc bufferDesc {
|
glm::vec3 col;
|
||||||
.size = 65536,
|
|
||||||
};
|
};
|
||||||
gfx::BufferHandle* buffer = m_gfx->createBuffer(bufferDesc, nullptr);
|
|
||||||
|
|
||||||
m_gfx->destroyBuffer(buffer);
|
gfx::VertexFormat vertFormat{
|
||||||
|
.stride = (uint32_t)sizeof(Vertex),
|
||||||
|
};
|
||||||
|
|
||||||
|
vertFormat.attributeDescriptions.push_back({0, gfx::VertexAttribFormat::VEC2, 0});
|
||||||
|
vertFormat.attributeDescriptions.push_back({1, gfx::VertexAttribFormat::VEC3, offsetof(Vertex, col)});
|
||||||
|
|
||||||
|
m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<Vertex> vertices = {
|
||||||
|
{ { 0.0f, -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} }
|
||||||
|
};
|
||||||
|
buffer = m_gfx->createVertexBuffer(sizeof(Vertex) * vertices.size(), vertices.data(), nullptr);
|
||||||
|
|
||||||
|
const std::vector<Vertex> vertices2 = {
|
||||||
|
{ { 0.9f, -0.9f}, {1.0f, 0.0f, 0.0f} },
|
||||||
|
{ { 0.9f, -0.8f}, {1.0f, 0.0f, 0.0f} },
|
||||||
|
{ { 0.8f, -0.9f}, {1.0f, 0.0f, 0.0f} }
|
||||||
|
};
|
||||||
|
buffer2 = m_gfx->createVertexBuffer(sizeof(Vertex) * vertices2.size(), vertices2.data(), nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
{
|
{
|
||||||
|
m_gfx->destroyVertexBuffer(buffer);
|
||||||
|
m_gfx->destroyVertexBuffer(buffer2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::gameLoop()
|
void Application::gameLoop()
|
||||||
{
|
{
|
||||||
|
TRACE("Begin game loop...");
|
||||||
|
|
||||||
uint64_t lastTick = m_win->getNanos();
|
uint64_t lastTick = m_win->getNanos();
|
||||||
constexpr int TICKFREQ = 1; // in hz
|
constexpr int TICKFREQ = 1; // in hz
|
||||||
|
|
||||||
@ -54,6 +85,10 @@ namespace engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* draw */
|
/* draw */
|
||||||
|
|
||||||
|
m_gfx->drawBuffer(buffer);
|
||||||
|
m_gfx->drawBuffer(buffer2);
|
||||||
|
|
||||||
m_gfx->draw();
|
m_gfx->draw();
|
||||||
|
|
||||||
/* poll events */
|
/* poll events */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// The implementation of the graphics layer using Vulkan 1.3.
|
// The implementation of the graphics layer using OpenGL 4.5
|
||||||
// This uses SDL specific code
|
// This uses SDL specific code
|
||||||
|
|
||||||
#ifdef ENGINE_BUILD_OPENGL
|
#ifdef ENGINE_BUILD_OPENGL
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
@ -77,13 +78,29 @@ namespace engine {
|
|||||||
|
|
||||||
// handles
|
// handles
|
||||||
|
|
||||||
struct gfx::BufferHandle {
|
struct gfx::VertexBuffer {
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
VkBuffer buffer = VK_NULL_HANDLE;
|
||||||
VmaAllocation allocation = nullptr;
|
VmaAllocation allocation = nullptr;
|
||||||
|
uint32_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// enum converters
|
||||||
|
|
||||||
|
namespace vkinternal {
|
||||||
|
|
||||||
|
static VkFormat getVertexAttribFormat(gfx::VertexAttribFormat fmt)
|
||||||
|
{
|
||||||
|
switch (fmt) {
|
||||||
|
case gfx::VertexAttribFormat::VEC2:
|
||||||
|
return VK_FORMAT_R32G32_SFLOAT;
|
||||||
|
case gfx::VertexAttribFormat::VEC3:
|
||||||
|
return VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
|
|
||||||
static std::vector<char> readFile(const std::string& filename)
|
static std::vector<char> readFile(const std::string& filename)
|
||||||
@ -532,6 +549,8 @@ namespace engine {
|
|||||||
|
|
||||||
Pipeline pipeline{};
|
Pipeline pipeline{};
|
||||||
|
|
||||||
|
std::queue<const gfx::VertexBuffer*> drawQueue{};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
|
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
|
||||||
@ -952,6 +971,11 @@ namespace engine {
|
|||||||
vkDestroyInstance(pimpl->instance, nullptr);
|
vkDestroyInstance(pimpl->instance, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GFXDevice::drawBuffer(const gfx::VertexBuffer* vb)
|
||||||
|
{
|
||||||
|
pimpl->drawQueue.push(vb);
|
||||||
|
}
|
||||||
|
|
||||||
void GFXDevice::draw()
|
void GFXDevice::draw()
|
||||||
{
|
{
|
||||||
VkResult res;
|
VkResult res;
|
||||||
@ -995,7 +1019,6 @@ namespace engine {
|
|||||||
renderPassInfo.pClearValues = &clearColor;
|
renderPassInfo.pClearValues = &clearColor;
|
||||||
|
|
||||||
vkCmdBeginRenderPass(pimpl->commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(pimpl->commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pimpl->pipeline.handle);
|
|
||||||
|
|
||||||
VkViewport viewport{};
|
VkViewport viewport{};
|
||||||
viewport.x = 0.0f;
|
viewport.x = 0.0f;
|
||||||
@ -1011,7 +1034,20 @@ namespace engine {
|
|||||||
scissor.extent = pimpl->swapchain.extent;
|
scissor.extent = pimpl->swapchain.extent;
|
||||||
vkCmdSetScissor(pimpl->commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(pimpl->commandBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
vkCmdDraw(pimpl->commandBuffer, 3, 1, 0, 0);
|
// run queued draw calls
|
||||||
|
|
||||||
|
vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pimpl->pipeline.handle);
|
||||||
|
VkDeviceSize offsets[] = { 0 };
|
||||||
|
while (pimpl->drawQueue.empty() == false) {
|
||||||
|
|
||||||
|
const auto* buffer = pimpl->drawQueue.front();
|
||||||
|
|
||||||
|
vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &buffer->buffer, offsets);
|
||||||
|
vkCmdDraw(pimpl->commandBuffer, buffer->size, 1, 0, 0);
|
||||||
|
|
||||||
|
pimpl->drawQueue.pop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdEndRenderPass(pimpl->commandBuffer);
|
vkCmdEndRenderPass(pimpl->commandBuffer);
|
||||||
|
|
||||||
@ -1054,11 +1090,28 @@ namespace engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath)
|
void GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat)
|
||||||
{
|
{
|
||||||
|
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
||||||
|
// get vertex attrib layout:
|
||||||
|
VkVertexInputBindingDescription bindingDescription{ };
|
||||||
|
bindingDescription.binding = 0;
|
||||||
|
bindingDescription.stride = vertexFormat.stride;
|
||||||
|
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
|
||||||
|
std::vector<VkVertexInputAttributeDescription> attribDescs{};
|
||||||
|
attribDescs.reserve(vertexFormat.attributeDescriptions.size());
|
||||||
|
for (const auto& desc : vertexFormat.attributeDescriptions) {
|
||||||
|
VkVertexInputAttributeDescription vulkanAttribDesc{};
|
||||||
|
vulkanAttribDesc.binding = 0;
|
||||||
|
vulkanAttribDesc.location = desc.location;
|
||||||
|
vulkanAttribDesc.offset = desc.offset;
|
||||||
|
vulkanAttribDesc.format = vkinternal::getVertexAttribFormat(desc.format);
|
||||||
|
attribDescs.push_back(vulkanAttribDesc);
|
||||||
|
}
|
||||||
|
|
||||||
auto vertShaderCode = readFile(vertShaderPath);
|
auto vertShaderCode = readFile(vertShaderPath);
|
||||||
auto fragShaderCode = readFile(fragShaderPath);
|
auto fragShaderCode = readFile(fragShaderPath);
|
||||||
INFO("Opened shader: {}", std::filesystem::path(vertShaderPath).filename().string());
|
INFO("Opened shader: {}", std::filesystem::path(vertShaderPath).filename().string());
|
||||||
@ -1080,12 +1133,13 @@ namespace engine {
|
|||||||
|
|
||||||
VkPipelineShaderStageCreateInfo shaderStages[2] = { vertShaderStageInfo, fragShaderStageInfo };
|
VkPipelineShaderStageCreateInfo shaderStages[2] = { vertShaderStageInfo, fragShaderStageInfo };
|
||||||
|
|
||||||
|
// this sets "vertex attribute pointers"
|
||||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
|
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
|
||||||
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
vertexInputInfo.vertexBindingDescriptionCount = 0;
|
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
||||||
vertexInputInfo.pVertexBindingDescriptions = nullptr;
|
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
|
||||||
vertexInputInfo.vertexAttributeDescriptionCount = 0;
|
vertexInputInfo.vertexAttributeDescriptionCount = attribDescs.size();
|
||||||
vertexInputInfo.pVertexAttributeDescriptions = nullptr;
|
vertexInputInfo.pVertexAttributeDescriptions = attribDescs.data();
|
||||||
|
|
||||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
|
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
|
||||||
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
@ -1205,24 +1259,35 @@ namespace engine {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::BufferHandle* GFXDevice::createBuffer(const gfx::BufferDesc& desc, const void* data)
|
gfx::VertexBuffer* GFXDevice::createVertexBuffer(uint32_t size, const void* vertices, const void* indices)
|
||||||
{
|
{
|
||||||
auto out = new gfx::BufferHandle{};
|
auto out = new gfx::VertexBuffer{};
|
||||||
|
out->size = size;
|
||||||
|
|
||||||
VkBufferCreateInfo createInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
VkBufferCreateInfo createInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||||
createInfo.size = desc.size;
|
createInfo.size = out->size;
|
||||||
createInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
createInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||||
|
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
createInfo.flags = 0;
|
||||||
|
|
||||||
VmaAllocationCreateInfo allocInfo{};
|
VmaAllocationCreateInfo allocInfo{};
|
||||||
allocInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
allocInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
|
|
||||||
VkResult res = vmaCreateBuffer(pimpl->allocator, &createInfo, &allocInfo, &out->buffer, &out->allocation, nullptr);
|
VkResult res = vmaCreateBuffer(pimpl->allocator, &createInfo, &allocInfo, &out->buffer, &out->allocation, nullptr);
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
|
void* data;
|
||||||
|
res = vmaMapMemory(pimpl->allocator, out->allocation, &data);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
memcpy(data, vertices, out->size);
|
||||||
|
vmaUnmapMemory(pimpl->allocator, out->allocation);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXDevice::destroyBuffer(const gfx::BufferHandle* buffer)
|
void GFXDevice::destroyVertexBuffer(const gfx::VertexBuffer* buffer)
|
||||||
{
|
{
|
||||||
vmaDestroyBuffer(pimpl->allocator, buffer->buffer, buffer->allocation);
|
vmaDestroyBuffer(pimpl->allocator, buffer->buffer, buffer->allocation);
|
||||||
delete buffer;
|
delete buffer;
|
||||||
|
Loading…
Reference in New Issue
Block a user