/* render.c Vulkan render manager Copyright (C) 2023 Bill Currie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_MATH_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include "QF/Vulkan/command.h" #include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/render.h" #include "QF/Vulkan/pipeline.h" #include "vid_vulkan.h" static void run_pipeline (qfv_pipeline_t *pipeline, VkCommandBuffer cmd, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkCmdBindPipeline (cmd, pipeline->bindPoint, pipeline->pipeline); dfunc->vkCmdSetViewport (cmd, 0, 1, &pipeline->viewport); dfunc->vkCmdSetScissor (cmd, 0, 1, &pipeline->scissor); if (pipeline->num_descriptor_sets) { dfunc->vkCmdBindDescriptorSets (cmd, pipeline->bindPoint, pipeline->layout, pipeline->first_descriptor_set, pipeline->num_descriptor_sets, pipeline->descriptor_sets, 0, 0); } if (pipeline->num_push_constants) { QFV_PushConstants (device, cmd, pipeline->layout, pipeline->num_push_constants, pipeline->push_constants); } } // https://themaister.net/blog/2019/08/14/yet-another-blog-explaining-vulkan-synchronization/ static void run_subpass (qfv_subpass_t_ *sp, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; __auto_type cmd = sp->cmd; dfunc->vkResetCommandBuffer (cmd, 0); dfunc->vkBeginCommandBuffer (cmd, &sp->beginInfo); QFV_duCmdBeginLabel (device, cmd, sp->label.name, {VEC4_EXP (sp->label.color)}); for (uint32_t i = 0; i < sp->pipline_count; i++) { __auto_type pipeline = &sp->pipelines[i]; run_pipeline (pipeline, cmd, ctx); } QFV_duCmdEndLabel (device, cmd); dfunc->vkEndCommandBuffer (cmd); } void QFV_RunRenderPass (qfv_renderpass_t_ *rp, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; __auto_type cmd = rp->cmd; VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; dfunc->vkResetCommandBuffer (cmd, 0); dfunc->vkBeginCommandBuffer (cmd, &beginInfo); QFV_duCmdBeginLabel (device, cmd, rp->label.name, {VEC4_EXP (rp->label.color)}); dfunc->vkCmdBeginRenderPass (cmd, &rp->beginInfo, rp->subpassContents); for (uint32_t i = 0; i < rp->subpass_count; i++) { __auto_type sp = &rp->subpasses[i]; run_subpass (sp, ctx); dfunc->vkCmdExecuteCommands (cmd, 1, &sp->cmd); //FIXME comment is a bit off as exactly one buffer is always submitted // //Regardless of whether any commands were submitted for this //subpass, must step through each and every subpass, otherwise //the attachments won't be transitioned correctly. //However, only if not the last (or only) subpass. if (i < rp->subpass_count - 1) { dfunc->vkCmdNextSubpass (cmd, rp->subpassContents); } } QFV_CmdEndLabel (device, cmd); }