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.