mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Support multiple frames rendering at once
This commit is contained in:
parent
e811349e5b
commit
46895c0d4b
@ -14,6 +14,7 @@ namespace engine::gfx {
|
|||||||
enum class BufferType {
|
enum class BufferType {
|
||||||
VERTEX,
|
VERTEX,
|
||||||
INDEX,
|
INDEX,
|
||||||
|
UNIFORM,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Primitive {
|
enum class Primitive {
|
||||||
|
@ -28,7 +28,7 @@ namespace engine {
|
|||||||
void renderFrame();
|
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, uint64_t uniformBufferSize);
|
||||||
void destroyPipeline(const gfx::Pipeline* pipeline);
|
void destroyPipeline(const gfx::Pipeline* pipeline);
|
||||||
|
|
||||||
gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
|
gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
static engine::gfx::Pipeline* pipeline;
|
static engine::gfx::Pipeline* pipeline;
|
||||||
static engine::gfx::Buffer* vb;
|
static engine::gfx::Buffer* vb;
|
||||||
static engine::gfx::Buffer* ib;
|
static engine::gfx::Buffer* ib;
|
||||||
|
static engine::gfx::Buffer* ub;
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
@ -28,7 +29,12 @@ namespace engine {
|
|||||||
};
|
};
|
||||||
vertFormat.attributeDescriptions.push_back({0, gfx::VertexAttribFormat::VEC2, 0});
|
vertFormat.attributeDescriptions.push_back({0, gfx::VertexAttribFormat::VEC2, 0});
|
||||||
vertFormat.attributeDescriptions.push_back({1, gfx::VertexAttribFormat::VEC3, offsetof(Vertex, col)});
|
vertFormat.attributeDescriptions.push_back({1, gfx::VertexAttribFormat::VEC3, offsetof(Vertex, col)});
|
||||||
pipeline = m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat);
|
struct UBO {
|
||||||
|
glm::mat4 model{};
|
||||||
|
glm::mat4 view{};
|
||||||
|
glm::mat4 proj{};
|
||||||
|
};
|
||||||
|
pipeline = m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat, sizeof(UBO));
|
||||||
|
|
||||||
const std::vector<Vertex> vertices = {
|
const std::vector<Vertex> vertices = {
|
||||||
{ { 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f} },
|
{ { 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f} },
|
||||||
@ -42,12 +48,16 @@ namespace engine {
|
|||||||
};
|
};
|
||||||
ib = m_gfx->createBuffer(gfx::BufferType::INDEX, sizeof(uint32_t) * indices.size(), indices.data());
|
ib = m_gfx->createBuffer(gfx::BufferType::INDEX, sizeof(uint32_t) * indices.size(), indices.data());
|
||||||
|
|
||||||
|
UBO initialUbo{};
|
||||||
|
// ub = m_gfx->createBuffer(gfx::BufferType::UNIFORM, sizeof(UBO), &initialUbo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
{
|
{
|
||||||
m_gfx->destroyBuffer(vb);
|
// m_gfx->destroyBuffer(ub);
|
||||||
m_gfx->destroyBuffer(ib);
|
m_gfx->destroyBuffer(ib);
|
||||||
|
m_gfx->destroyBuffer(vb);
|
||||||
m_gfx->destroyPipeline(pipeline);
|
m_gfx->destroyPipeline(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
|
static constexpr uint32_t FRAMES_IN_FLIGHT = 2; // This improved FPS by 5x!
|
||||||
|
|
||||||
// structures and enums
|
// structures and enums
|
||||||
|
|
||||||
struct LayerInfo {
|
struct LayerInfo {
|
||||||
@ -63,8 +65,8 @@ namespace engine {
|
|||||||
|
|
||||||
VkRenderPass renderpass;
|
VkRenderPass renderpass;
|
||||||
|
|
||||||
VkSemaphore acquireSemaphore = VK_NULL_HANDLE; // waits until the image is available
|
std::array<VkSemaphore, FRAMES_IN_FLIGHT> acquireSemaphores{}; // waits until the image is available
|
||||||
VkSemaphore releaseSemaphore = VK_NULL_HANDLE; // waits until rendering finishes
|
std::array<VkSemaphore, FRAMES_IN_FLIGHT> releaseSemaphores{}; // waits until rendering finishes
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DrawCall {
|
struct DrawCall {
|
||||||
@ -91,6 +93,7 @@ namespace engine {
|
|||||||
struct gfx::Pipeline {
|
struct gfx::Pipeline {
|
||||||
VkPipelineLayout layout = VK_NULL_HANDLE;
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
||||||
VkPipeline handle = VK_NULL_HANDLE;
|
VkPipeline handle = VK_NULL_HANDLE;
|
||||||
|
std::vector<gfx::Buffer*> uniformBuffers{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -515,13 +518,17 @@ namespace engine {
|
|||||||
// create the swapchain semaphores
|
// create the swapchain semaphores
|
||||||
VkSemaphoreCreateInfo semaphoreInfo{};
|
VkSemaphoreCreateInfo semaphoreInfo{};
|
||||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
if (swapchain->acquireSemaphore == VK_NULL_HANDLE) {
|
for (auto& acquireSemaphore : swapchain->acquireSemaphores) {
|
||||||
res = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &swapchain->acquireSemaphore);
|
if (acquireSemaphore == VK_NULL_HANDLE) {
|
||||||
assert(res == VK_SUCCESS);
|
res = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &acquireSemaphore);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (swapchain->releaseSemaphore == VK_NULL_HANDLE) {
|
for (auto& releaseSemaphore : swapchain->releaseSemaphores) {
|
||||||
res = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &swapchain->releaseSemaphore);
|
if (releaseSemaphore == VK_NULL_HANDLE) {
|
||||||
assert(res == VK_SUCCESS);
|
res = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &releaseSemaphore);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -588,8 +595,6 @@ namespace engine {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// class definitions
|
// class definitions
|
||||||
|
|
||||||
struct GFXDevice::Impl {
|
struct GFXDevice::Impl {
|
||||||
@ -608,16 +613,21 @@ namespace engine {
|
|||||||
Queue gfxQueue{};
|
Queue gfxQueue{};
|
||||||
Queue presentQueue{};
|
Queue presentQueue{};
|
||||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||||
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VmaAllocator allocator = nullptr;
|
VmaAllocator allocator = nullptr;
|
||||||
|
|
||||||
Swapchain swapchain{};
|
Swapchain swapchain{};
|
||||||
|
|
||||||
VkFence inFlightFence = VK_NULL_HANDLE;
|
uint64_t FRAMECOUNT = 0;
|
||||||
|
|
||||||
|
std::array<VkCommandBuffer, FRAMES_IN_FLIGHT> commandBuffers{};
|
||||||
|
std::array<VkFence, FRAMES_IN_FLIGHT> inFlightFences{};
|
||||||
|
|
||||||
std::map<const gfx::Pipeline*, std::queue<DrawCall>> drawQueues{};
|
std::map<const gfx::Pipeline*, std::queue<DrawCall>> drawQueues{};
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding uboLayoutBinding{};
|
||||||
|
VkDescriptorSetLayout uboLayout{};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
|
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
|
||||||
@ -939,8 +949,10 @@ namespace engine {
|
|||||||
.commandBufferCount = 1
|
.commandBufferCount = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
res = vkAllocateCommandBuffers(pimpl->device, &gfxCmdBufInfo, &pimpl->commandBuffer);
|
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||||
assert(res == VK_SUCCESS);
|
res = vkAllocateCommandBuffers(pimpl->device, &gfxCmdBufInfo, &pimpl->commandBuffers[i]);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1001,12 +1013,28 @@ namespace engine {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// for testing purposes, create a pipeline with a simple shader
|
|
||||||
VkFenceCreateInfo fenceInfo{};
|
VkFenceCreateInfo fenceInfo{};
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
fenceInfo.pNext = nullptr;
|
fenceInfo.pNext = nullptr;
|
||||||
res = vkCreateFence(pimpl->device, &fenceInfo, nullptr, &pimpl->inFlightFence);
|
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||||
|
res = vkCreateFence(pimpl->device, &fenceInfo, nullptr, &pimpl->inFlightFences[i]);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create uniform buffer stuff
|
||||||
|
pimpl->uboLayoutBinding.binding = 0;
|
||||||
|
pimpl->uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
pimpl->uboLayoutBinding.descriptorCount = 1;
|
||||||
|
pimpl->uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||||
|
pimpl->uboLayoutBinding.pImmutableSamplers = nullptr;
|
||||||
|
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
||||||
|
descriptorSetLayoutInfo.bindingCount = 1;
|
||||||
|
descriptorSetLayoutInfo.pBindings = &pimpl->uboLayoutBinding;
|
||||||
|
res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->uboLayout);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1014,10 +1042,16 @@ namespace engine {
|
|||||||
{
|
{
|
||||||
TRACE("Destroying GFXDevice...");
|
TRACE("Destroying GFXDevice...");
|
||||||
|
|
||||||
vkDestroyFence(pimpl->device, pimpl->inFlightFence, nullptr);
|
vkDestroyDescriptorSetLayout(pimpl->device, pimpl->uboLayout, nullptr);
|
||||||
|
|
||||||
vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphore, nullptr);
|
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||||
vkDestroySemaphore(pimpl->device, pimpl->swapchain.acquireSemaphore, nullptr);
|
|
||||||
|
vkDestroyFence(pimpl->device, pimpl->inFlightFences[i], nullptr);
|
||||||
|
|
||||||
|
vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphores[i], nullptr);
|
||||||
|
vkDestroySemaphore(pimpl->device, pimpl->swapchain.acquireSemaphores[i], nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
for (VkImageView view : pimpl->swapchain.imageViews) {
|
for (VkImageView view : pimpl->swapchain.imageViews) {
|
||||||
vkDestroyImageView(pimpl->device, view, nullptr);
|
vkDestroyImageView(pimpl->device, view, nullptr);
|
||||||
}
|
}
|
||||||
@ -1067,13 +1101,15 @@ namespace engine {
|
|||||||
{
|
{
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
||||||
res = vkWaitForFences(pimpl->device, 1, &pimpl->inFlightFence, VK_TRUE, UINT64_MAX);
|
const uint32_t frameIndex = pimpl->FRAMECOUNT % FRAMES_IN_FLIGHT;
|
||||||
|
|
||||||
|
res = vkWaitForFences(pimpl->device, 1, &pimpl->inFlightFences[frameIndex], VK_TRUE, UINT64_MAX);
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
res = vkResetFences(pimpl->device, 1, &pimpl->inFlightFence);
|
res = vkResetFences(pimpl->device, 1, &pimpl->inFlightFences[frameIndex]);
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
uint32_t imageIndex = 0;
|
uint32_t imageIndex = 0;
|
||||||
res = vkAcquireNextImageKHR(pimpl->device, pimpl->swapchain.swapchain, UINT64_MAX, pimpl->swapchain.acquireSemaphore, VK_NULL_HANDLE, &imageIndex);
|
res = vkAcquireNextImageKHR(pimpl->device, pimpl->swapchain.swapchain, UINT64_MAX, pimpl->swapchain.acquireSemaphores[frameIndex], VK_NULL_HANDLE, &imageIndex);
|
||||||
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
// recreate swapchain
|
// recreate swapchain
|
||||||
waitIdle();
|
waitIdle();
|
||||||
@ -1084,7 +1120,7 @@ namespace engine {
|
|||||||
assert(res == VK_SUCCESS || res == VK_SUBOPTIMAL_KHR);
|
assert(res == VK_SUCCESS || res == VK_SUBOPTIMAL_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = vkResetCommandBuffer(pimpl->commandBuffer, 0);
|
res = vkResetCommandBuffer(pimpl->commandBuffers[frameIndex], 0);
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
// now record command buffer
|
// now record command buffer
|
||||||
@ -1092,7 +1128,7 @@ namespace engine {
|
|||||||
VkCommandBufferBeginInfo beginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
VkCommandBufferBeginInfo beginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||||
beginInfo.flags = 0;
|
beginInfo.flags = 0;
|
||||||
beginInfo.pInheritanceInfo = nullptr;
|
beginInfo.pInheritanceInfo = nullptr;
|
||||||
res = vkBeginCommandBuffer(pimpl->commandBuffer, &beginInfo);
|
res = vkBeginCommandBuffer(pimpl->commandBuffers[frameIndex], &beginInfo);
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
VkRenderPassBeginInfo renderPassInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
VkRenderPassBeginInfo renderPassInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||||
@ -1105,7 +1141,7 @@ namespace engine {
|
|||||||
renderPassInfo.clearValueCount = 1;
|
renderPassInfo.clearValueCount = 1;
|
||||||
renderPassInfo.pClearValues = &clearColor;
|
renderPassInfo.pClearValues = &clearColor;
|
||||||
|
|
||||||
vkCmdBeginRenderPass(pimpl->commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(pimpl->commandBuffers[frameIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
VkViewport viewport{};
|
VkViewport viewport{};
|
||||||
viewport.x = 0.0f;
|
viewport.x = 0.0f;
|
||||||
@ -1114,28 +1150,28 @@ namespace engine {
|
|||||||
viewport.height = (float)pimpl->swapchain.extent.height;
|
viewport.height = (float)pimpl->swapchain.extent.height;
|
||||||
viewport.minDepth = 0.0f;
|
viewport.minDepth = 0.0f;
|
||||||
viewport.maxDepth = 1.0f;
|
viewport.maxDepth = 1.0f;
|
||||||
vkCmdSetViewport(pimpl->commandBuffer, 0, 1, &viewport);
|
vkCmdSetViewport(pimpl->commandBuffers[frameIndex], 0, 1, &viewport);
|
||||||
|
|
||||||
VkRect2D scissor{};
|
VkRect2D scissor{};
|
||||||
scissor.offset = { 0, 0 };
|
scissor.offset = { 0, 0 };
|
||||||
scissor.extent = pimpl->swapchain.extent;
|
scissor.extent = pimpl->swapchain.extent;
|
||||||
vkCmdSetScissor(pimpl->commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(pimpl->commandBuffers[frameIndex], 0, 1, &scissor);
|
||||||
|
|
||||||
// run queued draw calls
|
// run queued draw calls
|
||||||
|
|
||||||
VkDeviceSize offsets[] = { 0 };
|
VkDeviceSize offsets[] = { 0 };
|
||||||
|
|
||||||
for (auto& [pipeline, queue] : pimpl->drawQueues) {
|
for (auto& [pipeline, queue] : pimpl->drawQueues) {
|
||||||
vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle);
|
vkCmdBindPipeline(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle);
|
||||||
while (queue.empty() == false) {
|
while (queue.empty() == false) {
|
||||||
DrawCall call = queue.front();
|
DrawCall call = queue.front();
|
||||||
vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &call.vertexBuffer->buffer, offsets);
|
vkCmdBindVertexBuffers(pimpl->commandBuffers[frameIndex], 0, 1, &call.vertexBuffer->buffer, offsets);
|
||||||
if (call.indexBuffer == nullptr) {
|
if (call.indexBuffer == nullptr) {
|
||||||
// do a simple draw call
|
// do a simple draw call
|
||||||
vkCmdDraw(pimpl->commandBuffer, call.count, 1, 0, 0);
|
vkCmdDraw(pimpl->commandBuffers[frameIndex], call.count, 1, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
vkCmdBindIndexBuffer(pimpl->commandBuffer, call.indexBuffer->buffer, 0, VK_INDEX_TYPE_UINT32);
|
vkCmdBindIndexBuffer(pimpl->commandBuffers[frameIndex], call.indexBuffer->buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
vkCmdDrawIndexed(pimpl->commandBuffer, call.count, 1, 0, 0, 0);
|
vkCmdDrawIndexed(pimpl->commandBuffers[frameIndex], call.count, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
queue.pop();
|
queue.pop();
|
||||||
}
|
}
|
||||||
@ -1143,9 +1179,9 @@ namespace engine {
|
|||||||
|
|
||||||
pimpl->drawQueues.clear();
|
pimpl->drawQueues.clear();
|
||||||
|
|
||||||
vkCmdEndRenderPass(pimpl->commandBuffer);
|
vkCmdEndRenderPass(pimpl->commandBuffers[frameIndex]);
|
||||||
|
|
||||||
res = vkEndCommandBuffer(pimpl->commandBuffer);
|
res = vkEndCommandBuffer(pimpl->commandBuffers[frameIndex]);
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1153,19 +1189,19 @@ namespace engine {
|
|||||||
|
|
||||||
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
submitInfo.waitSemaphoreCount = 1;
|
||||||
submitInfo.pWaitSemaphores = &pimpl->swapchain.acquireSemaphore;
|
submitInfo.pWaitSemaphores = &pimpl->swapchain.acquireSemaphores[frameIndex];
|
||||||
submitInfo.pWaitDstStageMask = waitStages;
|
submitInfo.pWaitDstStageMask = waitStages;
|
||||||
submitInfo.commandBufferCount = 1;
|
submitInfo.commandBufferCount = 1;
|
||||||
submitInfo.pCommandBuffers = &pimpl->commandBuffer;
|
submitInfo.pCommandBuffers = &pimpl->commandBuffers[frameIndex];
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
submitInfo.pSignalSemaphores = &pimpl->swapchain.releaseSemaphore;
|
submitInfo.pSignalSemaphores = &pimpl->swapchain.releaseSemaphores[frameIndex];
|
||||||
|
|
||||||
res = vkQueueSubmit(pimpl->gfxQueue.handle, 1, &submitInfo, pimpl->inFlightFence);
|
res = vkQueueSubmit(pimpl->gfxQueue.handle, 1, &submitInfo, pimpl->inFlightFences[frameIndex]);
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
VkPresentInfoKHR presentInfo{ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
VkPresentInfoKHR presentInfo{ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||||
presentInfo.waitSemaphoreCount = 1;
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
presentInfo.pWaitSemaphores = &pimpl->swapchain.releaseSemaphore;
|
presentInfo.pWaitSemaphores = &pimpl->swapchain.releaseSemaphores[frameIndex];
|
||||||
|
|
||||||
VkSwapchainKHR swapchains[] = { pimpl->swapchain.swapchain };
|
VkSwapchainKHR swapchains[] = { pimpl->swapchain.swapchain };
|
||||||
presentInfo.swapchainCount = 1;
|
presentInfo.swapchainCount = 1;
|
||||||
@ -1182,15 +1218,40 @@ namespace engine {
|
|||||||
else {
|
else {
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pimpl->FRAMECOUNT++;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat)
|
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize)
|
||||||
{
|
{
|
||||||
|
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
||||||
gfx::Pipeline* pipeline = new gfx::Pipeline;
|
gfx::Pipeline* pipeline = new gfx::Pipeline;
|
||||||
|
|
||||||
|
// create uniform buffers
|
||||||
|
pipeline->uniformBuffers.resize(FRAMES_IN_FLIGHT);
|
||||||
|
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||||
|
auto buf = new gfx::Buffer{};
|
||||||
|
buf->size = uniformBufferSize;
|
||||||
|
buf->type = gfx::BufferType::UNIFORM;
|
||||||
|
|
||||||
|
VkBufferCreateInfo bufferInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||||
|
bufferInfo.size = buf->size;
|
||||||
|
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||||
|
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo allocInfo{};
|
||||||
|
allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; // prefer CPU memory for uniforms
|
||||||
|
allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
|
|
||||||
|
res = vmaCreateBuffer(pimpl->allocator, &bufferInfo, &allocInfo, &buf->buffer, &buf->allocation, nullptr);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
|
pipeline->uniformBuffers[i] = buf;
|
||||||
|
}
|
||||||
|
|
||||||
// get vertex attrib layout:
|
// get vertex attrib layout:
|
||||||
VkVertexInputBindingDescription bindingDescription{ };
|
VkVertexInputBindingDescription bindingDescription{ };
|
||||||
bindingDescription.binding = 0;
|
bindingDescription.binding = 0;
|
||||||
@ -1320,9 +1381,8 @@ namespace engine {
|
|||||||
|
|
||||||
VkPipelineLayoutCreateInfo layoutInfo{};
|
VkPipelineLayoutCreateInfo layoutInfo{};
|
||||||
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
// everything is 0 because we're not using uniforms
|
layoutInfo.setLayoutCount = 1;
|
||||||
layoutInfo.setLayoutCount = 0;
|
layoutInfo.pSetLayouts = &pimpl->uboLayout;
|
||||||
layoutInfo.pSetLayouts = nullptr;
|
|
||||||
layoutInfo.pushConstantRangeCount = 0;
|
layoutInfo.pushConstantRangeCount = 0;
|
||||||
layoutInfo.pPushConstantRanges = nullptr;
|
layoutInfo.pPushConstantRanges = nullptr;
|
||||||
|
|
||||||
@ -1363,6 +1423,10 @@ namespace engine {
|
|||||||
vkDestroyPipeline(pimpl->device, pipeline->handle, nullptr);
|
vkDestroyPipeline(pimpl->device, pipeline->handle, nullptr);
|
||||||
vkDestroyPipelineLayout(pimpl->device, pipeline->layout, nullptr);
|
vkDestroyPipelineLayout(pimpl->device, pipeline->layout, nullptr);
|
||||||
|
|
||||||
|
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||||
|
destroyBuffer(pipeline->uniformBuffers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
delete pipeline;
|
delete pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user