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 <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace engine {
|
||||
namespace engine::gfx {
|
||||
|
||||
enum class ShaderType {
|
||||
VERTEX,
|
||||
@ -23,10 +24,28 @@ namespace engine {
|
||||
TRIANGLE_STRIP,
|
||||
};
|
||||
|
||||
enum class IndexBufferFormat {
|
||||
UNSIGNED_8_BITS,
|
||||
UNSIGNED_16_BITS,
|
||||
UNSIGNED_32_BITS,
|
||||
enum class VertexAttribFormat {
|
||||
VEC2,
|
||||
VEC3,
|
||||
};
|
||||
|
||||
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,36 +2,13 @@
|
||||
|
||||
#include "engine_api.h"
|
||||
|
||||
#include "gfx.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct SDL_Window;
|
||||
|
||||
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 {
|
||||
|
||||
@ -42,15 +19,18 @@ namespace engine {
|
||||
GFXDevice& operator=(const GFXDevice&) = delete;
|
||||
~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.
|
||||
void draw();
|
||||
|
||||
// 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
|
||||
gfx::BufferHandle* createVertexBuffer(const gfx::BufferDesc& desc, const void* vertices, const void* indices);
|
||||
void destroyBuffer(const gfx::BufferHandle* buffer);
|
||||
gfx::VertexBuffer* createVertexBuffer(uint32_t size, const void* vertices, const void* indices);
|
||||
void destroyVertexBuffer(const gfx::VertexBuffer* buffer);
|
||||
|
||||
// wait until all the active GPU queues have finished working
|
||||
void waitIdle();
|
||||
|
@ -5,6 +5,11 @@
|
||||
#include "resource_manager.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
static engine::gfx::VertexBuffer* buffer;
|
||||
static engine::gfx::VertexBuffer* buffer2;
|
||||
|
||||
namespace engine {
|
||||
|
||||
Application::Application(const char* appName, const char* appVersion)
|
||||
@ -14,22 +19,48 @@ namespace engine {
|
||||
|
||||
engine::ResourceManager resMan{};
|
||||
|
||||
m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str());
|
||||
|
||||
gfx::BufferDesc bufferDesc {
|
||||
.size = 65536,
|
||||
struct Vertex {
|
||||
glm::vec2 pos;
|
||||
glm::vec3 col;
|
||||
};
|
||||
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()
|
||||
{
|
||||
m_gfx->destroyVertexBuffer(buffer);
|
||||
m_gfx->destroyVertexBuffer(buffer2);
|
||||
}
|
||||
|
||||
void Application::gameLoop()
|
||||
{
|
||||
TRACE("Begin game loop...");
|
||||
|
||||
uint64_t lastTick = m_win->getNanos();
|
||||
constexpr int TICKFREQ = 1; // in hz
|
||||
|
||||
@ -54,6 +85,10 @@ namespace engine {
|
||||
}
|
||||
|
||||
/* draw */
|
||||
|
||||
m_gfx->drawBuffer(buffer);
|
||||
m_gfx->drawBuffer(buffer2);
|
||||
|
||||
m_gfx->draw();
|
||||
|
||||
/* 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
|
||||
|
||||
#ifdef ENGINE_BUILD_OPENGL
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
namespace engine {
|
||||
|
||||
@ -77,13 +78,29 @@ namespace engine {
|
||||
|
||||
// handles
|
||||
|
||||
struct gfx::BufferHandle {
|
||||
struct gfx::VertexBuffer {
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
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
|
||||
|
||||
static std::vector<char> readFile(const std::string& filename)
|
||||
@ -532,6 +549,8 @@ namespace engine {
|
||||
|
||||
Pipeline pipeline{};
|
||||
|
||||
std::queue<const gfx::VertexBuffer*> drawQueue{};
|
||||
|
||||
};
|
||||
|
||||
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
|
||||
@ -952,6 +971,11 @@ namespace engine {
|
||||
vkDestroyInstance(pimpl->instance, nullptr);
|
||||
}
|
||||
|
||||
void GFXDevice::drawBuffer(const gfx::VertexBuffer* vb)
|
||||
{
|
||||
pimpl->drawQueue.push(vb);
|
||||
}
|
||||
|
||||
void GFXDevice::draw()
|
||||
{
|
||||
VkResult res;
|
||||
@ -995,7 +1019,6 @@ namespace engine {
|
||||
renderPassInfo.pClearValues = &clearColor;
|
||||
|
||||
vkCmdBeginRenderPass(pimpl->commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pimpl->pipeline.handle);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
@ -1011,7 +1034,20 @@ namespace engine {
|
||||
scissor.extent = pimpl->swapchain.extent;
|
||||
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);
|
||||
|
||||
@ -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;
|
||||
|
||||
// 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 fragShaderCode = readFile(fragShaderPath);
|
||||
INFO("Opened shader: {}", std::filesystem::path(vertShaderPath).filename().string());
|
||||
@ -1080,12 +1133,13 @@ namespace engine {
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[2] = { vertShaderStageInfo, fragShaderStageInfo };
|
||||
|
||||
// this sets "vertex attribute pointers"
|
||||
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;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
||||
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = attribDescs.size();
|
||||
vertexInputInfo.pVertexAttributeDescriptions = attribDescs.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
|
||||
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 };
|
||||
createInfo.size = desc.size;
|
||||
createInfo.size = out->size;
|
||||
createInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
createInfo.flags = 0;
|
||||
|
||||
VmaAllocationCreateInfo allocInfo{};
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
void GFXDevice::destroyBuffer(const gfx::BufferHandle* buffer)
|
||||
void GFXDevice::destroyVertexBuffer(const gfx::VertexBuffer* buffer)
|
||||
{
|
||||
vmaDestroyBuffer(pimpl->allocator, buffer->buffer, buffer->allocation);
|
||||
delete buffer;
|
||||
|
Loading…
Reference in New Issue
Block a user