diff --git a/include/gfx.hpp b/include/gfx.hpp index 94cbf30..eb7f2c1 100644 --- a/include/gfx.hpp +++ b/include/gfx.hpp @@ -46,6 +46,6 @@ namespace engine::gfx { // handles (incomplete types) struct Pipeline; - struct VertexBuffer; + struct Buffer; } diff --git a/include/gfx_device.hpp b/include/gfx_device.hpp index 75833d2..3b61743 100644 --- a/include/gfx_device.hpp +++ b/include/gfx_device.hpp @@ -20,18 +20,19 @@ namespace engine { ~GFXDevice(); // 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. - void draw(); + void renderFrame(); // creates the equivalent of an OpenGL shader program & vertex attrib configuration gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat); void destroyPipeline(const gfx::Pipeline* pipeline); - // creates a vertex array for holding mesh data - gfx::VertexBuffer* createVertexBuffer(uint32_t size, const void* vertices, const void* indices); - void destroyVertexBuffer(const gfx::VertexBuffer* buffer); + gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data); + void destroyBuffer(const gfx::Buffer* buffer); // wait until all the active GPU queues have finished working void waitIdle(); diff --git a/src/engine.cpp b/src/engine.cpp index 6fc83c2..47797a7 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -8,7 +8,8 @@ #include static engine::gfx::Pipeline* pipeline; -static engine::gfx::VertexBuffer* buffer; +static engine::gfx::Buffer* vb; +static engine::gfx::Buffer* ib; 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); const std::vector 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, 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 indices{ - 0, 1, 2, + vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, sizeof(Vertex) * vertices.size(), vertices.data()); + const std::vector 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() { - m_gfx->destroyVertexBuffer(buffer); + m_gfx->destroyBuffer(vb); + m_gfx->destroyBuffer(ib); m_gfx->destroyPipeline(pipeline); } @@ -76,9 +80,9 @@ namespace engine { /* draw */ - m_gfx->drawBuffer(pipeline, buffer); + m_gfx->drawIndexed(pipeline, vb, ib, 6); - m_gfx->draw(); + m_gfx->renderFrame(); /* poll events */ m_win->getInputAndEvents(); diff --git a/src/gfx_device_opengl45.cpp b/src/gfx_device_opengl45.cpp index 929ff25..8648681 100644 --- a/src/gfx_device_opengl45.cpp +++ b/src/gfx_device_opengl45.cpp @@ -57,19 +57,41 @@ namespace engine { GFXDevice::~GFXDevice() { TRACE("Destroying GFXDevice..."); + + SDL_GL_DeleteContext(pimpl->context); } - void GFXDevice::draw() - { - } - - void GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath) + void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, uint32_t count) { } - 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() diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 6e9d446..c20fbfe 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -66,6 +66,12 @@ namespace engine { 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 { GRAPHICS = (1 << 0), TRANSFER = (1 << 1), @@ -74,10 +80,11 @@ namespace engine { // handles - struct gfx::VertexBuffer { + struct gfx::Buffer { + gfx::BufferType type; VkBuffer buffer = VK_NULL_HANDLE; VmaAllocation allocation = nullptr; - uint32_t size; + VkDeviceSize size = 0; }; struct gfx::Pipeline { @@ -101,6 +108,18 @@ namespace engine { } 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 @@ -596,7 +615,7 @@ namespace engine { VkFence inFlightFence = VK_NULL_HANDLE; - std::map> drawQueues{}; + std::map> drawQueues{}; }; @@ -1016,12 +1035,34 @@ namespace engine { 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; @@ -1086,9 +1127,15 @@ namespace engine { for (auto& [pipeline, queue] : pimpl->drawQueues) { vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); while (queue.empty() == false) { - const gfx::VertexBuffer* buffer = queue.front(); - vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &buffer->buffer, offsets); - vkCmdDraw(pimpl->commandBuffer, buffer->size, 1, 0, 0); + DrawCall call = queue.front(); + vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &call.vertexBuffer->buffer, offsets); + 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(); } } @@ -1318,13 +1365,15 @@ namespace engine { 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; - auto out = new gfx::VertexBuffer{}; + auto out = new gfx::Buffer{}; out->size = size; + out->type = type; + VkBuffer stagingBuffer; VmaAllocation stagingAllocation; @@ -1344,10 +1393,10 @@ namespace engine { res = vmaCreateBuffer(pimpl->allocator, &stagingBufferInfo, &stagingAllocInfo, &stagingBuffer, &stagingAllocation, nullptr); assert(res == VK_SUCCESS); - void* data; - res = vmaMapMemory(pimpl->allocator, stagingAllocation, &data); + void* dataDest; + res = vmaMapMemory(pimpl->allocator, stagingAllocation, &dataDest); assert(res == VK_SUCCESS); - memcpy(data, vertices, out->size); + memcpy(dataDest, data, out->size); vmaUnmapMemory(pimpl->allocator, stagingAllocation); } @@ -1355,7 +1404,7 @@ namespace engine { { VkBufferCreateInfo gpuBufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; 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.flags = 0; @@ -1376,7 +1425,7 @@ namespace engine { return out; } - void GFXDevice::destroyVertexBuffer(const gfx::VertexBuffer* buffer) + void GFXDevice::destroyBuffer(const gfx::Buffer* buffer) { vmaDestroyBuffer(pimpl->allocator, buffer->buffer, buffer->allocation); delete buffer;