Add indexed buffer support

This commit is contained in:
Bailey Harrison 2022-10-24 01:10:48 +01:00
parent a24b951df1
commit ce12534ad8
5 changed files with 114 additions and 38 deletions

View File

@ -46,6 +46,6 @@ namespace engine::gfx {
// handles (incomplete types) // handles (incomplete types)
struct Pipeline; struct Pipeline;
struct VertexBuffer; struct Buffer;
} }

View File

@ -20,18 +20,19 @@ namespace engine {
~GFXDevice(); ~GFXDevice();
// adds a vertex buffer draw call to the queue // adds a vertex buffer draw call to the queue
void drawBuffer(const gfx::Pipeline* pipeline, const gfx::VertexBuffer* vb); void drawBuffer(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, uint32_t count);
void drawIndexed(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t indexCount);
// 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 renderFrame();
// creates the equivalent of an OpenGL shader program & vertex attrib configuration // creates the equivalent of an OpenGL shader program & vertex attrib configuration
gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat); gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat);
void destroyPipeline(const gfx::Pipeline* pipeline); void destroyPipeline(const gfx::Pipeline* pipeline);
// creates a vertex array for holding mesh data gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
gfx::VertexBuffer* createVertexBuffer(uint32_t size, const void* vertices, const void* indices); void destroyBuffer(const gfx::Buffer* 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();

View File

@ -8,7 +8,8 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
static engine::gfx::Pipeline* pipeline; static engine::gfx::Pipeline* pipeline;
static engine::gfx::VertexBuffer* buffer; static engine::gfx::Buffer* vb;
static engine::gfx::Buffer* ib;
namespace engine { namespace engine {
@ -30,20 +31,23 @@ namespace engine {
pipeline = m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat); pipeline = 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 = { const std::vector<Vertex> vertices = {
{ { 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f} }, { { 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, 1.0f, 0.0f} },
{ {-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f} } { {-0.5f, -0.5f}, {0.0f, 0.0f, 1.0f} },
{ {-0.5f, 0.5f}, {0.0f, 1.0f, 1.0f} },
}; };
const std::vector<uint16_t> indices{ vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, sizeof(Vertex) * vertices.size(), vertices.data());
0, 1, 2, const std::vector<uint16_t> indices = {
0, 1, 2, 2, 1, 3,
}; };
buffer = m_gfx->createVertexBuffer(sizeof(Vertex) * vertices.size(), vertices.data(), indices.data()); ib = m_gfx->createBuffer(gfx::BufferType::INDEX, sizeof(uint16_t) * indices.size(), indices.data());
} }
Application::~Application() Application::~Application()
{ {
m_gfx->destroyVertexBuffer(buffer); m_gfx->destroyBuffer(vb);
m_gfx->destroyBuffer(ib);
m_gfx->destroyPipeline(pipeline); m_gfx->destroyPipeline(pipeline);
} }
@ -76,9 +80,9 @@ namespace engine {
/* draw */ /* draw */
m_gfx->drawBuffer(pipeline, buffer); m_gfx->drawIndexed(pipeline, vb, ib, 6);
m_gfx->draw(); m_gfx->renderFrame();
/* poll events */ /* poll events */
m_win->getInputAndEvents(); m_win->getInputAndEvents();

View File

@ -57,19 +57,41 @@ namespace engine {
GFXDevice::~GFXDevice() GFXDevice::~GFXDevice()
{ {
TRACE("Destroying GFXDevice..."); TRACE("Destroying GFXDevice...");
SDL_GL_DeleteContext(pimpl->context);
} }
void GFXDevice::draw() void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, uint32_t count)
{
}
void GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath)
{ {
} }
bool GFXDevice::createBuffer(const gfx::BufferDesc& desc, const void* data, gfx::BufferHandle* out) void GFXDevice::drawIndexed(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t indexCount)
{ {
return false; }
void GFXDevice::renderFrame()
{
}
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat)
{
return nullptr;
}
void GFXDevice::destroyPipeline(const gfx::Pipeline* pipeline)
{
}
gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data)
{
return nullptr;
}
void GFXDevice::destroyBuffer(const gfx::Buffer* buffer)
{
} }
void GFXDevice::waitIdle() void GFXDevice::waitIdle()

View File

@ -66,6 +66,12 @@ namespace engine {
VkSemaphore releaseSemaphore = VK_NULL_HANDLE; // waits until rendering finishes VkSemaphore releaseSemaphore = VK_NULL_HANDLE; // waits until rendering finishes
}; };
struct DrawCall {
const gfx::Buffer* vertexBuffer = nullptr;
const gfx::Buffer* indexBuffer = nullptr; // if this is nullptr, don't use indexed
uint32_t count = 0;
};
enum class QueueFlags : uint32_t { enum class QueueFlags : uint32_t {
GRAPHICS = (1 << 0), GRAPHICS = (1 << 0),
TRANSFER = (1 << 1), TRANSFER = (1 << 1),
@ -74,10 +80,11 @@ namespace engine {
// handles // handles
struct gfx::VertexBuffer { struct gfx::Buffer {
gfx::BufferType type;
VkBuffer buffer = VK_NULL_HANDLE; VkBuffer buffer = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr; VmaAllocation allocation = nullptr;
uint32_t size; VkDeviceSize size = 0;
}; };
struct gfx::Pipeline { struct gfx::Pipeline {
@ -101,6 +108,18 @@ namespace engine {
} }
throw std::runtime_error("Unknown vertex attribute format"); throw std::runtime_error("Unknown vertex attribute format");
} }
static VkBufferUsageFlagBits getBufferUsageFlag(gfx::BufferType type)
{
switch (type) {
case gfx::BufferType::VERTEX:
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
case gfx::BufferType::INDEX:
return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
}
throw std::runtime_error("Unknown buffer type");
}
} }
// functions // functions
@ -596,7 +615,7 @@ namespace engine {
VkFence inFlightFence = VK_NULL_HANDLE; VkFence inFlightFence = VK_NULL_HANDLE;
std::map<const gfx::Pipeline*, std::queue<const gfx::VertexBuffer*>> drawQueues{}; std::map<const gfx::Pipeline*, std::queue<DrawCall>> drawQueues{};
}; };
@ -1016,12 +1035,34 @@ namespace engine {
vkDestroyInstance(pimpl->instance, nullptr); vkDestroyInstance(pimpl->instance, nullptr);
} }
void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::VertexBuffer* vb) void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, uint32_t count)
{ {
pimpl->drawQueues[pipeline].push(vb); assert(vertexBuffer->type == gfx::BufferType::VERTEX);
DrawCall call{
.vertexBuffer = vertexBuffer,
.indexBuffer = nullptr, // don't use indexed drawing
.count = count,
};
pimpl->drawQueues[pipeline].push(call);
} }
void GFXDevice::draw() void GFXDevice::drawIndexed(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count)
{
assert(vertexBuffer->type == gfx::BufferType::VERTEX);
assert(indexBuffer->type == gfx::BufferType::INDEX);
DrawCall call{
.vertexBuffer = vertexBuffer,
.indexBuffer = indexBuffer, // don't use indexed drawing
.count = count,
};
pimpl->drawQueues[pipeline].push(call);
}
void GFXDevice::renderFrame()
{ {
VkResult res; VkResult res;
@ -1086,9 +1127,15 @@ namespace engine {
for (auto& [pipeline, queue] : pimpl->drawQueues) { for (auto& [pipeline, queue] : pimpl->drawQueues) {
vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle);
while (queue.empty() == false) { while (queue.empty() == false) {
const gfx::VertexBuffer* buffer = queue.front(); DrawCall call = queue.front();
vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &buffer->buffer, offsets); vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &call.vertexBuffer->buffer, offsets);
vkCmdDraw(pimpl->commandBuffer, buffer->size, 1, 0, 0); if (call.indexBuffer == nullptr) {
// do a simple draw call
vkCmdDraw(pimpl->commandBuffer, call.count, 1, 0, 0);
} else {
vkCmdBindIndexBuffer(pimpl->commandBuffer, call.indexBuffer->buffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdDrawIndexed(pimpl->commandBuffer, call.count, 1, 0, 0, 0);
}
queue.pop(); queue.pop();
} }
} }
@ -1318,13 +1365,15 @@ namespace engine {
delete pipeline; delete pipeline;
} }
gfx::VertexBuffer* GFXDevice::createVertexBuffer(uint32_t size, const void* vertices, const void* indices) gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data)
{ {
VkResult res; VkResult res;
auto out = new gfx::VertexBuffer{}; auto out = new gfx::Buffer{};
out->size = size; out->size = size;
out->type = type;
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
VmaAllocation stagingAllocation; VmaAllocation stagingAllocation;
@ -1344,10 +1393,10 @@ namespace engine {
res = vmaCreateBuffer(pimpl->allocator, &stagingBufferInfo, &stagingAllocInfo, &stagingBuffer, &stagingAllocation, nullptr); res = vmaCreateBuffer(pimpl->allocator, &stagingBufferInfo, &stagingAllocInfo, &stagingBuffer, &stagingAllocation, nullptr);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
void* data; void* dataDest;
res = vmaMapMemory(pimpl->allocator, stagingAllocation, &data); res = vmaMapMemory(pimpl->allocator, stagingAllocation, &dataDest);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
memcpy(data, vertices, out->size); memcpy(dataDest, data, out->size);
vmaUnmapMemory(pimpl->allocator, stagingAllocation); vmaUnmapMemory(pimpl->allocator, stagingAllocation);
} }
@ -1355,7 +1404,7 @@ namespace engine {
{ {
VkBufferCreateInfo gpuBufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo gpuBufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
gpuBufferInfo.size = out->size; gpuBufferInfo.size = out->size;
gpuBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; gpuBufferInfo.usage = vkinternal::getBufferUsageFlag(type) | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
gpuBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; gpuBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
gpuBufferInfo.flags = 0; gpuBufferInfo.flags = 0;
@ -1376,7 +1425,7 @@ namespace engine {
return out; return out;
} }
void GFXDevice::destroyVertexBuffer(const gfx::VertexBuffer* buffer) void GFXDevice::destroyBuffer(const gfx::Buffer* buffer)
{ {
vmaDestroyBuffer(pimpl->allocator, buffer->buffer, buffer->allocation); vmaDestroyBuffer(pimpl->allocator, buffer->buffer, buffer->allocation);
delete buffer; delete buffer;