Code structure - snowzurfer/vulkan-forward-plus GitHub Wiki
The barriers before and after the compute stage are found in ```fplus_renderer.cpp:1565``:
void FPlusRenderer::SetupComputeCommandBuffers(const VulkanDevice &device) {
// Cache common settings to all command buffers
VkCommandBufferBeginInfo cmd_buff_begin_info =
tools::inits::CommandBufferBeginInfo(
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT);
cmd_buff_begin_info.pInheritanceInfo = nullptr;
VK_CHECK_RESULT(vkBeginCommandBuffer(
cmd_buff_compute_, &cmd_buff_begin_info));
// Use a barrier to allow the buffers to be read by the compute pipeline
eastl::array<VkBufferMemoryBarrier, 1U> barriers_before;
barriers_before[0U] = tools::inits::BufferMemoryBarrier(
VK_ACCESS_SHADER_READ_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
device.graphics_queue().index,
device.compute_queue().index,
light_idxs_buff_.buffer(),
0U,
light_idxs_buff_.size());
vkCmdPipelineBarrier(
cmd_buff_compute_,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0U,
0, nullptr,
barriers_before.size(),
barriers_before.data(),
0, nullptr);
lights_cull_material_->BindPipeline(cmd_buff_compute_, VK_PIPELINE_BIND_POINT_COMPUTE);
vkCmdBindDescriptorSets(
cmd_buff_compute_,
VK_PIPELINE_BIND_POINT_COMPUTE,
pipe_layouts_[PipeLayoutTypes::GENERIC],
0U,
DescSetLayoutTypes::MODELS,
desc_sets_.data(),
0U,
nullptr);
vkCmdDispatch(cmd_buff_compute_, kWidthInTiles, kHeightInTiles, 1U);
// Use a barrier to allow the buffers to be read by the compute pipeline
eastl::array<VkBufferMemoryBarrier, 1U> barriers_after;
barriers_after[0U] = tools::inits::BufferMemoryBarrier(
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
device.compute_queue().index,
device.graphics_queue().index,
light_idxs_buff_.buffer(),
0U,
light_idxs_buff_.size());
vkCmdPipelineBarrier(
cmd_buff_compute_,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0U,
0, nullptr,
barriers_after.size(),
barriers_after.data(),
0, nullptr);
VK_CHECK_RESULT(vkEndCommandBuffer(cmd_buff_compute_));
}
The shader which triggers the problem is fpshade.frag
, found in assets/shaders/
. The latest commit contains the shader as it triggers the exception. To stop it from triggering the exception, simply replace the line
uint li = 0;
for (uint i = 0; i < 50; ++i) {
if (i >= lights_count) {
break;
}
li = lights_idxs[idx];
lighting = lighting + CalcLighting(
li,
normal,
pos_vs,
diff_albedo,
spec_albedo,
spec_power);
++idx;
}
with
uint li = 0;
for (uint i = 0; i < 50; ++i) {
li = lights_idxs[idx];
lighting = lighting + CalcLighting(
0,
normal,
pos_vs,
diff_albedo,
spec_albedo,
spec_power);
++idx;
}
The command buffers are submitted like this:
void FPlusRenderer::Render() {
eastl::array<VkSemaphore, 2U> wait_semaphores = {
vulkan()->image_available_semaphore(),
light_culling_complete_semaphore_
};
VkSemaphore signal_semaphore = vulkan()->rendering_finished_semaphore();
eastl::array<VkPipelineStageFlags, 2U> wait_stages{ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
};
VkCommandBuffer cmd_buff =
cmd_buffers_[current_swapchain_img_];
VkSubmitInfo submit_info = tools::inits::SubmitInfo();
submit_info.waitSemaphoreCount = wait_semaphores.size();
submit_info.pWaitSemaphores = wait_semaphores.data();
submit_info.pWaitDstStageMask = wait_stages.data();
submit_info.commandBufferCount = 1U;
submit_info.pCommandBuffers = &cmd_buff;
submit_info.signalSemaphoreCount = 1U;
submit_info.pSignalSemaphores = &signal_semaphore;
VkSubmitInfo submit_info_depth_prepass = tools::inits::SubmitInfo();
submit_info_depth_prepass.waitSemaphoreCount = 0U;
submit_info_depth_prepass.pWaitSemaphores = nullptr;
submit_info_depth_prepass.pWaitDstStageMask = nullptr;
submit_info_depth_prepass.commandBufferCount = 1U;
submit_info_depth_prepass.pCommandBuffers = &cmd_buff_depth_prepass_;
submit_info_depth_prepass.signalSemaphoreCount = 1U;
submit_info_depth_prepass.pSignalSemaphores = &depth_prepass_complete_semaphore_;
VkPipelineStageFlags cull_wait_stage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
VkSubmitInfo submit_info_cull = tools::inits::SubmitInfo();
submit_info_cull.waitSemaphoreCount = 1U;
submit_info_cull.pWaitSemaphores = &depth_prepass_complete_semaphore_;
submit_info_cull.pWaitDstStageMask = &cull_wait_stage;
submit_info_cull.commandBufferCount = 1U;
submit_info_cull.pCommandBuffers = &cmd_buff_compute_;
submit_info_cull.signalSemaphoreCount = 1U;
submit_info_cull.pSignalSemaphores = &light_culling_complete_semaphore_;
eastl::array<VkSubmitInfo, 1U> queue_graphics_depth_infos = {
submit_info_depth_prepass,
};
eastl::array<VkSubmitInfo, 1U> queue_compute_infos = {
submit_info_cull
};
eastl::array<VkSubmitInfo, 1U> queue_graphics_infos = {
submit_info
};
VK_CHECK_RESULT(vkQueueSubmit(
vulkan()->device().graphics_queue().queue,
queue_graphics_depth_infos.size(),
queue_graphics_depth_infos.data(),
VK_NULL_HANDLE));
VK_CHECK_RESULT(vkQueueSubmit(
vulkan()->device().compute_queue().queue,
queue_compute_infos.size(),
queue_compute_infos.data(),
VK_NULL_HANDLE));
VK_CHECK_RESULT(vkQueueSubmit(
vulkan()->device().graphics_queue().queue,
queue_graphics_infos.size(),
queue_graphics_infos.data(),
VK_NULL_HANDLE));
}
The shaders are compiled at runtime using Google's shaderc library.
The main source file of the project are fplus/fplus_renderer.cpp
, and the rest of the files which implement the forward + are in fplus/
. The base
folder contains the framework.