summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/rune/render/renderer.h10
-rw-r--r--render/vulkan/renderer.c142
-rw-r--r--render/vulkan/renderpass.c57
3 files changed, 180 insertions, 29 deletions
diff --git a/include/rune/render/renderer.h b/include/rune/render/renderer.h
index ebf8602..7a1ea3b 100644
--- a/include/rune/render/renderer.h
+++ b/include/rune/render/renderer.h
@@ -23,15 +23,15 @@
#define RUNE_RENDER_RENDERER_H
#include <rune/util/types.h>
-#include <rune/ui/app_window.h>
+#include <rune/ui/window.h>
-struct rune_renderer {
+typedef struct rune_renderer {
void (*close)(void);
void (*draw)(void);
void (*clear)(void);
-};
+} renderer_t;
-RAPI struct rune_renderer* select_render_vulkan(struct rune_window *window);
-RAPI struct rune_renderer* select_render_directx(struct rune_window *window);
+RAPI renderer_t* select_render_vulkan(window_t *window);
+RAPI renderer_t* select_render_directx(window_t *window);
#endif
diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c
index 0facddf..679abef 100644
--- a/render/vulkan/renderer.c
+++ b/render/vulkan/renderer.c
@@ -1,19 +1,46 @@
-#include <vulkan/vulkan.h>
-#include <GLFW/glfw3.h>
+/*
+ * Rune Game Engine
+ * Copyright 2024 Danny Holman <dholman@gymli.org>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include "vk_types.h"
+#include "renderpass.h"
+#include "framebuffer.h"
+#include "swapchain.h"
+#include "device.h"
+#include "context.h"
+#include "image.h"
+#include "fence.h"
+#include "vkassert.h"
#include <rune/render/renderer.h>
#include <rune/core/logging.h>
#include <rune/core/alloc.h>
#include <rune/core/abort.h>
-#include "context.h"
-#include "image.h"
+#include <rune/core/config.h>
#include <sys/time.h>
-static struct vkcontext *context = NULL;
+static vkcontext_t *context = NULL;
void _init_cmdbuffers(void) {
uint32_t num_buffers = context->swapchain->img_count;
if (context->cmdbuffers == NULL)
- context->cmdbuffers = rune_calloc(0, sizeof(struct vkcmdbuffer*) * num_buffers);
+ context->cmdbuffers = rune_calloc(0, sizeof(vkcmdbuffer_t*) * num_buffers);
for (uint32_t i = 0; i < num_buffers; i++) {
if (context->cmdbuffers[i] != NULL)
@@ -37,7 +64,7 @@ void _destroy_cmdbuffers(void) {
void _init_framebuffers(void) {
uint32_t num_buffers = context->swapchain->img_count;
if (context->framebuffers == NULL)
- context->framebuffers = rune_calloc(0, sizeof(struct vkframebuffer*) * num_buffers);
+ context->framebuffers = rune_calloc(0, sizeof(vkframebuffer_t*) * num_buffers);
uint32_t at_count = 2;
for (uint32_t i = 0; i < num_buffers; i++) {
@@ -67,16 +94,22 @@ void _destroy_framebuffers(void) {
log_output(LOG_DEBUG, "Destroyed %d frame buffers", num_buffers);
}
-int _init_vulkan(struct rune_window *window) {
+int _init_vulkan(window_t *window) {
+ log_output(LOG_DEBUG, "Initializing Vulkan");
struct timeval start;
struct timeval stop;
gettimeofday(&start, NULL);
- struct ext_container ext;
+ ext_container_t ext;
ext.extensions = glfwGetRequiredInstanceExtensions(&ext.ext_count);
- struct vklayer_container *vklayers = init_vklayers(&ext);
+
+ if (rune_get_vk_debug() == 1) {
+ vklayer_container_t *vklayers = init_vklayers(&ext);
+ context = create_vkcontext(vklayers, &ext);
+ } else {
+ context = create_vkcontext(NULL, &ext);
+ }
- context = create_vkcontext(vklayers, &ext);
if (context == NULL)
return -1;
@@ -111,7 +144,7 @@ int _init_vulkan(struct rune_window *window) {
context->image_semaphores = rune_alloc(sizeof(VkSemaphore) * context->swapchain->max_frames);
context->queue_semaphores = rune_alloc(sizeof(VkSemaphore) * context->swapchain->max_frames);
- context->fences_in_flight = rune_calloc(0, sizeof(struct vkfence*) * context->swapchain->max_frames);
+ context->fences_in_flight = rune_calloc(0, sizeof(vkfence_t*) * context->swapchain->max_frames);
VkSemaphoreCreateInfo scinfo;
for (uint8_t i = 0; i < context->swapchain->max_frames; i++) {
@@ -122,7 +155,7 @@ int _init_vulkan(struct rune_window *window) {
vkCreateSemaphore(context->dev->ldev, &scinfo, NULL, &context->queue_semaphores[i]);
context->fences_in_flight[i] = create_vkfence(context->dev, 1);
}
- context->images_in_flight = rune_calloc(0, sizeof(struct vkfence*) * context->swapchain->img_count);
+ context->images_in_flight = rune_calloc(0, sizeof(vkfence_t*) * context->swapchain->img_count);
gettimeofday(&stop, NULL);
log_output(LOG_INFO, "Finished initializing Vulkan in %lums", (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec);
@@ -145,19 +178,92 @@ void _close_vulkan(void) {
destroy_swapchain(context->swapchain, context->dev);
destroy_vkdev(context->dev);
destroy_vkcontext(context);
- rune_free(renderer);
+}
+
+int _begin_frame(float time) {
+ vkfence_t *frame_fence = context->fences_in_flight[context->swapchain->frame];
+ if (fence_lock(frame_fence, context->dev, UINT64_MAX) == -1) {
+ log_output(LOG_WARN, "Error locking in-flight fence");
+ return -1;
+ }
+
+ uint32_t next_img = vkswapchain_get_next_img(context->swapchain,
+ context->dev,
+ UINT64_MAX,
+ NULL,
+ context->image_semaphores[context->swapchain->frame]);
+
+ if (next_img == -1)
+ return -1;
+
+ context->img_index = next_img;
+ vkcmdbuffer_t *cmdbuf = context->cmdbuffers[context->img_index];
+ cmdbuf_begin(cmdbuf, 0, 0, 0);
+
+ VkViewport vport;
+ vport.x = 0;
+ vport.y = (float)context->surface->height;
+ vport.width = (float)context->surface->width;
+ vport.height = (float)context->surface->height;
+ vport.minDepth = 0;
+ vport.maxDepth = 1;
+
+ VkRect2D scissor;
+ scissor.offset.x = 0;
+ scissor.offset.y = 0;
+ scissor.extent.width = context->surface->width;
+ scissor.extent.height = context->surface->height;
+
+ vkCmdSetViewport(cmdbuf->handle, 0, 1, &vport);
+ vkCmdSetScissor(cmdbuf->handle, 0, 1, &scissor);
+
+ context->rendpass->area[2] = context->surface->width;
+ context->rendpass->area[3] = context->surface->height;
+
+ VkFramebuffer framebuf = context->framebuffers[context->img_index]->handle;
+ renderpass_begin(cmdbuf, context->rendpass, framebuf);
+ return 0;
+}
+
+int _end_frame(float time) {
+ vkcmdbuffer_t *cmdbuf = context->cmdbuffers[context->img_index];
+ renderpass_end(cmdbuf, context->rendpass);
+ cmdbuf_end(cmdbuf);
+
+ vkfence_t** img_in_flight = &context->images_in_flight[context->img_index];
+ if (*img_in_flight != NULL)
+ fence_lock(*img_in_flight, context->dev, UINT64_MAX);
+
+ context->images_in_flight[context->img_index] = context->fences_in_flight[context->swapchain->frame];
+ *img_in_flight = context->fences_in_flight[context->swapchain->frame];
+ fence_unlock(*img_in_flight, context->dev);
+
+ cmdbuf_submit(cmdbuf,
+ &context->queue_semaphores[context->swapchain->frame],
+ &context->image_semaphores[context->swapchain->frame],
+ context->dev->queues[0].handle,
+ (*img_in_flight)->handle);
+
+ vkswapchain_present(context->swapchain,
+ context->dev,
+ &context->queue_semaphores[context->swapchain->frame],
+ &context->img_index);
+
+ cmdbuf_reset(cmdbuf);
+
+ return 0;
}
void _draw_vulkan(void) {
- if (fence_lock(context->fences_in_flight[context->swapchain->frame], context->dev, UINT64_MAX) != 0)
- log_output(LOG_WARN, "In-flight fence locking failure");
+ _begin_frame(0);
+ _end_frame(0);
}
void _clear_vulkan(void) {
}
-struct rune_renderer* select_render_vulkan(struct rune_window *window) {
- struct rune_renderer *ret = rune_alloc(sizeof(struct rune_renderer));
+renderer_t* select_render_vulkan(window_t *window) {
+ renderer_t *ret = rune_alloc(sizeof(renderer_t));
ret->close = _close_vulkan;
ret->draw = _draw_vulkan;
ret->clear = _clear_vulkan;
diff --git a/render/vulkan/renderpass.c b/render/vulkan/renderpass.c
index ea3dd5b..981039a 100644
--- a/render/vulkan/renderpass.c
+++ b/render/vulkan/renderpass.c
@@ -46,7 +46,12 @@ void destroy_vkcmdbuffer(vkcmdbuffer_t *cmdbuffer, vkdev_t *dev) {
rune_free(cmdbuffer);
}
-void cmdbuf_begin(struct vkcmdbuffer *cmdbuffer, int single, int rpass_cont, int sim_use) {
+void cmdbuf_begin(vkcmdbuffer_t *cmdbuffer, int single, int rpass_cont, int sim_use) {
+ if (cmdbuffer->state != CMDBUF_INITIAL) {
+ log_output(LOG_FATAL, "Attempted to record to a command buffer not in initial state");
+ rune_abort();
+ }
+
VkCommandBufferBeginInfo binfo;
binfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
binfo.flags = 0;
@@ -61,13 +66,43 @@ void cmdbuf_begin(struct vkcmdbuffer *cmdbuffer, int single, int rpass_cont, int
cmdbuffer->state = CMDBUF_RECORDING;
}
-void cmdbuf_end(struct vkcmdbuffer *cmdbuffer) {
+void cmdbuf_end(vkcmdbuffer_t *cmdbuffer) {
+ if (cmdbuffer->state != CMDBUF_RECORDING) {
+ log_output(LOG_FATAL, "Attempted to end command buffer not in recording state");
+ rune_abort();
+ }
+
vkassert(vkEndCommandBuffer(cmdbuffer->handle));
cmdbuffer->state = CMDBUF_READY;
}
-struct vkcmdbuffer* cmdbuf_begin_single_use(struct vkdev *dev) {
- struct vkcmdbuffer *ret = create_vkcmdbuffer(dev, 1);
+void cmdbuf_submit(vkcmdbuffer_t *cmdbuffer, VkSemaphore *signal, VkSemaphore *wait, VkQueue queue_handle, VkFence fence_handle) {
+ if (cmdbuffer->state != CMDBUF_READY) {
+ log_output(LOG_FATAL, "Attempted to submit command buffer not in ready state");
+ return;
+ }
+
+ VkSubmitInfo sinfo;
+ sinfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ sinfo.pNext = NULL;
+ sinfo.commandBufferCount = 1;
+ sinfo.pCommandBuffers = &cmdbuffer->handle;
+ sinfo.signalSemaphoreCount = 1;
+ sinfo.pSignalSemaphores = signal;
+ sinfo.waitSemaphoreCount = 1;
+ sinfo.pWaitSemaphores = wait;
+ VkPipelineStageFlags flags[1] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
+ sinfo.pWaitDstStageMask = flags;
+ vkassert(vkQueueSubmit(queue_handle, 1, &sinfo, fence_handle));
+ cmdbuffer->state = CMDBUF_SUBMITTED;
+}
+
+void cmdbuf_reset(vkcmdbuffer_t *cmdbuffer) {
+ cmdbuffer->state = CMDBUF_INITIAL;
+}
+
+vkcmdbuffer_t* cmdbuf_begin_single_use(vkdev_t *dev) {
+ vkcmdbuffer_t *ret = create_vkcmdbuffer(dev, 1);
cmdbuf_begin(ret, 1, 0, 0);
return ret;
}
@@ -173,7 +208,12 @@ void destroy_vkrendpass(vkrendpass_t *rendpass, vkdev_t *dev) {
rune_free(rendpass);
}
-void renderpass_begin(struct vkcmdbuffer *buf, struct vkrendpass *rendpass, VkFramebuffer framebuf) {
+void renderpass_begin(vkcmdbuffer_t *buf, vkrendpass_t *rendpass, VkFramebuffer framebuf) {
+ if (buf->state != CMDBUF_RECORDING) {
+ log_output(LOG_FATAL, "Attempted to place command buffer not in recording state in a render pass");
+ rune_abort();
+ }
+
VkClearValue cvals[2];
cvals[0].color.float32[0] = rendpass->color[0];
cvals[0].color.float32[1] = rendpass->color[1];
@@ -198,7 +238,12 @@ void renderpass_begin(struct vkcmdbuffer *buf, struct vkrendpass *rendpass, VkFr
buf->state = CMDBUF_IN_RENDERPASS;
}
-void renderpass_end(struct vkcmdbuffer *buf, struct vkrendpass *rendpass) {
+void renderpass_end(vkcmdbuffer_t *buf, vkrendpass_t *rendpass) {
+ if (buf->state != CMDBUF_IN_RENDERPASS) {
+ log_output(LOG_FATAL, "Attempted to purge command buffer not in render pass");
+ rune_abort();
+ }
+
vkCmdEndRenderPass(buf->handle);
buf->state = CMDBUF_RECORDING;
}