Просмотр исходного кода

Update Vulkan support to 1.0.5 SDK, issue proper barriers, add collectors

rdb 9 лет назад
Родитель
Сommit
dc802f3779

+ 4 - 1
panda/src/gobj/shader.cxx

@@ -2508,7 +2508,8 @@ spirv_analyze_shader(const string &data) {
     string _name;
     ShaderArgType _type;
     int _location;
-  } def_var = {string(), SAT_unknown, -1};
+    int _set;
+  } def_var = {string(), SAT_unknown, -1, -1};
 
   pvector<ShaderVar> vars(bound, def_var);
 
@@ -2691,6 +2692,8 @@ spirv_analyze_shader(const string &data) {
       // that variables can specify both.
       if (words[2] == SpvDecorationLocation || words[2] == SpvDecorationBinding) {
         vars[words[1]]._location = words[3];
+      } else if (words[2] == SpvDecorationDescriptorSet) {
+        vars[words[1]]._set = words[3];
       }
       break;
     }

+ 1 - 1
panda/src/vulkandisplay/vulkanGraphicsPipe.cxx

@@ -72,7 +72,7 @@ VulkanGraphicsPipe() {
   app_info.applicationVersion = 0;
   app_info.pEngineName = "Panda3D";
   app_info.engineVersion = PANDA_NUMERIC_VERSION;
-  app_info.apiVersion = VK_API_VERSION;
+  app_info.apiVersion = VK_MAKE_VERSION(1, 0, 0); // Minimum requirement
 
   VkInstanceCreateInfo inst_info;
   inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;

+ 35 - 6
panda/src/vulkandisplay/vulkanGraphicsStateGuardian.cxx

@@ -37,6 +37,7 @@ VulkanGraphicsStateGuardian(GraphicsEngine *engine, VulkanGraphicsPipe *pipe,
   _device(VK_NULL_HANDLE),
   _queue(VK_NULL_HANDLE),
   _dma_queue(VK_NULL_HANDLE),
+  _graphics_queue_family_index(queue_family_index),
   _cmd_pool(VK_NULL_HANDLE),
   _cmd(VK_NULL_HANDLE),
   _transfer_cmd(VK_NULL_HANDLE),
@@ -61,7 +62,7 @@ VulkanGraphicsStateGuardian(GraphicsEngine *engine, VulkanGraphicsPipe *pipe,
   queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
   queue_info.pNext = NULL;
   queue_info.flags = 0;
-  queue_info.queueFamilyIndex = queue_family_index;
+  queue_info.queueFamilyIndex = _graphics_queue_family_index;
   queue_info.queueCount = 2;
   queue_info.pQueuePriorities = queue_priorities;
 
@@ -84,8 +85,8 @@ VulkanGraphicsStateGuardian(GraphicsEngine *engine, VulkanGraphicsPipe *pipe,
     return;
   }
 
-  vkGetDeviceQueue(_device, queue_family_index, 0, &_queue);
-  vkGetDeviceQueue(_device, queue_family_index, 1, &_dma_queue);
+  vkGetDeviceQueue(_device, _graphics_queue_family_index, 0, &_queue);
+  vkGetDeviceQueue(_device, _graphics_queue_family_index, 1, &_dma_queue);
 
   // Create a fence to signal when the command buffers have finished.
   VkFenceCreateInfo fence_info;
@@ -104,7 +105,7 @@ VulkanGraphicsStateGuardian(GraphicsEngine *engine, VulkanGraphicsPipe *pipe,
   cmd_pool_info.pNext = NULL;
   cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
                         VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
-  cmd_pool_info.queueFamilyIndex = queue_family_index;
+  cmd_pool_info.queueFamilyIndex = _graphics_queue_family_index;
 
   err = vkCreateCommandPool(_device, &cmd_pool_info, NULL, &_cmd_pool);
   if (err) {
@@ -355,6 +356,8 @@ TextureContext *VulkanGraphicsStateGuardian::
 prepare_texture(Texture *texture, int view) {
   nassertr(_transfer_cmd != VK_NULL_HANDLE, (TextureContext *)NULL);
 
+  PStatTimer timer(_prepare_texture_pcollector);
+
   VulkanGraphicsPipe *vkpipe;
   DCAST_INTO_R(vkpipe, get_pipe(), NULL);
 
@@ -404,7 +407,7 @@ prepare_texture(Texture *texture, int view) {
   image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
   image_info.queueFamilyIndexCount = 0;
   image_info.pQueueFamilyIndices = NULL;
-  image_info.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
+  image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
   // Check if the format is actually supported.
   VkFormatProperties fmt_props;
@@ -663,6 +666,23 @@ prepare_texture(Texture *texture, int view) {
   tc->update_data_size_bytes(alloc_info.allocationSize);
   tc->mark_loaded();
 
+  // Issue a command to transition the image into a layout optimal for
+  // transferring into.
+  VkImageMemoryBarrier barrier;
+  barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+  barrier.pNext = NULL;
+  barrier.srcAccessMask = 0;
+  barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+  barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+  barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+  barrier.srcQueueFamilyIndex = _graphics_queue_family_index;
+  barrier.dstQueueFamilyIndex = _graphics_queue_family_index;
+  barrier.image = image;
+  barrier.subresourceRange = view_info.subresourceRange;
+  vkCmdPipelineBarrier(_transfer_cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                       VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
+                       0, NULL, 0, NULL, 1, &barrier);
+
   // Do we even have an image to upload?
   if (texture->get_ram_image().is_null()) {
     if (texture->has_clear_color()) {
@@ -810,7 +830,8 @@ prepare_texture(Texture *texture, int view) {
       }
 
       // Schedule a copy from the staging buffer.
-      vkCmdCopyBufferToImage(_transfer_cmd, buffer, image, image_info.initialLayout, 1, &region);
+      vkCmdCopyBufferToImage(_transfer_cmd, buffer, image,
+                             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
       region.bufferOffset += src_size;
       _data_transferred_pcollector.add_level(src_size);
 
@@ -886,6 +907,8 @@ extract_texture_data(Texture *) {
  */
 SamplerContext *VulkanGraphicsStateGuardian::
 prepare_sampler(const SamplerState &sampler) {
+  PStatTimer timer(_prepare_sampler_pcollector);
+
   VkSamplerAddressMode wrap_map[] = {VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
                                      VK_SAMPLER_ADDRESS_MODE_REPEAT,
                                      VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
@@ -967,6 +990,8 @@ prepare_shader(Shader *shader) {
     return (ShaderContext *)NULL;
   }
 
+  PStatTimer timer(_prepare_shader_pcollector);
+
   VkResult err;
   const Shader::ShaderType shader_types[] = {Shader::ST_vertex, Shader::ST_fragment};
   VulkanShaderContext *sc = new VulkanShaderContext(shader);
@@ -1016,6 +1041,8 @@ release_shader(ShaderContext *context) {
  */
 VertexBufferContext *VulkanGraphicsStateGuardian::
 prepare_vertex_buffer(GeomVertexArrayData *array_data) {
+  PStatTimer timer(_prepare_vertex_buffer_pcollector);
+
   VulkanGraphicsPipe *vkpipe;
   DCAST_INTO_R(vkpipe, get_pipe(), NULL);
 
@@ -1106,6 +1133,8 @@ release_vertex_buffer(VertexBufferContext *context) {
  */
 IndexBufferContext *VulkanGraphicsStateGuardian::
 prepare_index_buffer(GeomPrimitive *primitive) {
+  PStatTimer timer(_prepare_index_buffer_pcollector);
+
   VulkanGraphicsPipe *vkpipe;
   DCAST_INTO_R(vkpipe, get_pipe(), NULL);
 

+ 1 - 0
panda/src/vulkandisplay/vulkanGraphicsStateGuardian.h

@@ -138,6 +138,7 @@ private:
   VkDevice _device;
   VkQueue _queue;
   VkQueue _dma_queue;
+  uint32_t _graphics_queue_family_index;
   VkFence _fence;
   VkBuffer _null_vertex_buffer;
   VkCommandPool _cmd_pool;

+ 133 - 16
panda/src/vulkandisplay/vulkanGraphicsWindow.cxx

@@ -32,7 +32,8 @@ VulkanGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
   _swapchain(VK_NULL_HANDLE),
   _render_pass(VK_NULL_HANDLE),
   _present_complete(VK_NULL_HANDLE),
-  _image_index(0)
+  _image_index(0),
+  _layout_defined(false)
 {
 }
 
@@ -101,9 +102,56 @@ begin_frame(FrameMode mode, Thread *current_thread) {
     clear_cube_map_selection();
   }*/
 
-  // Now that we have a command buffer, start our render pass.
+  // Now that we have a command buffer, start our render pass.  First
+  // transition the swapchain images into the valid state for rendering into.
   VkCommandBuffer cmd = vkgsg->_cmd;
 
+  VkImageMemoryBarrier barriers[2];
+  barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+  barriers[0].pNext = NULL;
+  barriers[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+  barriers[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+  barriers[0].oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+  barriers[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+  barriers[0].srcQueueFamilyIndex = vkgsg->_graphics_queue_family_index; //TODO support separate present queue.
+  barriers[0].dstQueueFamilyIndex = vkgsg->_graphics_queue_family_index;
+  barriers[0].image = _images[_image_index];
+  barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+  barriers[0].subresourceRange.baseMipLevel = 0;
+  barriers[0].subresourceRange.levelCount = 1;
+  barriers[0].subresourceRange.baseArrayLayer = 0;
+  barriers[0].subresourceRange.layerCount = 1;
+
+  barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+  barriers[1].pNext = NULL;
+  barriers[1].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+  barriers[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+  barriers[1].oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+  barriers[1].newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+  barriers[1].srcQueueFamilyIndex = vkgsg->_graphics_queue_family_index; //TODO support separate present queue.
+  barriers[1].dstQueueFamilyIndex = vkgsg->_graphics_queue_family_index;
+  barriers[1].image = _depth_stencil_image;
+  barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT |
+                                            VK_IMAGE_ASPECT_STENCIL_BIT;
+  barriers[1].subresourceRange.baseMipLevel = 0;
+  barriers[1].subresourceRange.levelCount = 1;
+  barriers[1].subresourceRange.baseArrayLayer = 0;
+  barriers[1].subresourceRange.layerCount = 1;
+
+  if (!_layout_defined) {
+    // If this is the first time we are using these images, they are still
+    // in the UNDEFINED layout.
+    barriers[0].srcAccessMask = 0;
+    barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    barriers[1].srcAccessMask = 0;
+    barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    _layout_defined = true;
+  }
+
+  vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                       VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
+                       0, NULL, 0, NULL, 2, barriers);
+
   VkClearValue clears[2];
   LColor clear_color = get_clear_color();
   clears[0].color.float32[0] = clear_color[0];
@@ -207,6 +255,9 @@ end_flip() {
   VkFence fence = vkgsg->_fence;
 
   nassertv(_present_complete != VK_NULL_HANDLE);
+  nassertv(_layout_defined);
+
+  VkCommandBuffer cmdbufs[2] = {vkgsg->_cmd, _present_cmds[_image_index]};
 
   // Submit the GSG's command buffers to the queue.
   VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
@@ -216,8 +267,8 @@ end_flip() {
   submit_info.waitSemaphoreCount = 1;
   submit_info.pWaitSemaphores = &_present_complete;
   submit_info.pWaitDstStageMask = &stage_flags;
-  submit_info.commandBufferCount = 1;
-  submit_info.pCommandBuffers = &vkgsg->_cmd;
+  submit_info.commandBufferCount = 2;
+  submit_info.pCommandBuffers = cmdbufs;
   submit_info.signalSemaphoreCount = 0;
   submit_info.pSignalSemaphores = NULL;
 
@@ -232,8 +283,10 @@ end_flip() {
   VkPresentInfoKHR present;
   present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
   present.pNext = NULL;
-  present.waitSemaphoreCount = 1;
-  present.pWaitSemaphores = &_present_complete;
+  present.waitSemaphoreCount = 0;
+  present.pWaitSemaphores = NULL;
+  //present.waitSemaphoreCount = 1;
+  //present.pWaitSemaphores = &_present_complete;
   present.swapchainCount = 1;
   present.pSwapchains = &_swapchain;
   present.pImageIndices = &_image_index;
@@ -296,10 +349,10 @@ open_window() {
 
   // Make sure we have a GSG, which manages a VkDevice.
   VulkanGraphicsStateGuardian *vkgsg;
+  uint32_t queue_family_index = 0;
   if (_gsg == NULL) {
     // Find a queue suitable both for graphics and for presenting to our
     // surface.  TODO: fall back to separate graphics/present queues?
-    uint32_t queue_family_index;
     if (!vkpipe->find_queue_family_for_surface(queue_family_index, _surface, VK_QUEUE_GRAPHICS_BIT)) {
       vulkan_error(err, "Failed to find graphics queue that can present to surface");
       return false;
@@ -399,12 +452,12 @@ open_window() {
 
   // Get the images in the swap chain, which may be more than requested.
   vkGetSwapchainImagesKHR(device, _swapchain, &num_images, NULL);
+  _images.resize(num_images);
   _image_views.resize(num_images);
   _framebuffers.resize(num_images);
   _fb_properties.set_back_buffers(num_images - 1);
 
-  VkImage *images = (VkImage *)alloca(sizeof(VkImage) * num_images);
-  vkGetSwapchainImagesKHR(device, _swapchain, &num_images, images);
+  vkGetSwapchainImagesKHR(device, _swapchain, &num_images, &_images[0]);
 
   // Now create an image view for each image.
   for (uint32_t i = 0; i < num_images; ++i) {
@@ -412,7 +465,7 @@ open_window() {
     view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
     view_info.pNext = NULL;
     view_info.flags = 0;
-    view_info.image = images[i];
+    view_info.image = _images[i];
     view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
     view_info.format = swapchain_info.imageFormat;
     view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
@@ -449,7 +502,7 @@ open_window() {
   depth_img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
   depth_img_info.queueFamilyIndexCount = 0;
   depth_img_info.pQueueFamilyIndices = NULL;
-  depth_img_info.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+  depth_img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
   // Choose a suitable format that satisfies the requirements.
   if (_fb_properties.get_depth_bits() > 24 ||
@@ -467,8 +520,7 @@ open_window() {
     _fb_properties.set_stencil_bits(8);
   }
 
-  VkImage depth_image;
-  err = vkCreateImage(device, &depth_img_info, NULL, &depth_image);
+  err = vkCreateImage(device, &depth_img_info, NULL, &_depth_stencil_image);
   if (err) {
     vulkan_error(err, "Failed to create depth image");
     return false;
@@ -476,7 +528,7 @@ open_window() {
 
   // Get the memory requirements, and find an appropriate heap to alloc in.
   VkMemoryRequirements mem_reqs;
-  vkGetImageMemoryRequirements(device, depth_image, &mem_reqs);
+  vkGetImageMemoryRequirements(device, _depth_stencil_image, &mem_reqs);
 
   VkMemoryAllocateInfo alloc_info;
   alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
@@ -496,7 +548,7 @@ open_window() {
   }
 
   // Bind memory to image.
-  err = vkBindImageMemory(device, depth_image, depth_mem, 0);
+  err = vkBindImageMemory(device, _depth_stencil_image, depth_mem, 0);
   if (err) {
     vulkan_error(err, "Failed to bind memory to depth image");
     return false;
@@ -506,7 +558,7 @@ open_window() {
   view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
   view_info.pNext = NULL;
   view_info.flags = 0;
-  view_info.image = depth_image;
+  view_info.image = _depth_stencil_image;
   view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
   view_info.format = depth_img_info.format;
   view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
@@ -613,5 +665,70 @@ open_window() {
     }
   }
 
+  // Prerecord the command buffers to transition the images into a presentable
+  // state.
+  VkCommandBufferAllocateInfo cmd_alloc;
+  cmd_alloc.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+  cmd_alloc.pNext = NULL;
+  cmd_alloc.commandPool = vkgsg->_cmd_pool;
+  cmd_alloc.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+  cmd_alloc.commandBufferCount = num_images;
+
+  VkCommandBuffer *cmd_bufs =
+    (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * num_images);
+  err = vkAllocateCommandBuffers(device, &cmd_alloc, cmd_bufs);
+  if (err) {
+    vulkan_error(err, "Failed to create command buffer");
+    return false;
+  }
+
+  for (uint32_t i = 0; i < num_images; ++i) {
+    VkCommandBufferBeginInfo begin_info;
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    begin_info.pNext = NULL;
+    begin_info.flags = 0;
+    begin_info.pInheritanceInfo = NULL;
+
+    err = vkBeginCommandBuffer(cmd_bufs[i], &begin_info);
+    if (err) {
+      vulkan_error(err, "Can't begin command buffer");
+      return false;
+    }
+
+    VkImageMemoryBarrier barriers[2];
+    barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    barriers[0].pNext = NULL;
+    barriers[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    barriers[0].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+    barriers[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+    barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+    barriers[0].srcQueueFamilyIndex = queue_family_index;
+    barriers[0].dstQueueFamilyIndex = queue_family_index; //TODO support separate present queue.
+    barriers[0].image = _images[i];
+    barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    barriers[0].subresourceRange.baseMipLevel = 0;
+    barriers[0].subresourceRange.levelCount = 1;
+    barriers[0].subresourceRange.baseArrayLayer = 0;
+    barriers[0].subresourceRange.layerCount = 1;
+
+    barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    barriers[1].pNext = NULL;
+    barriers[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+    barriers[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+    barriers[1].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+    barriers[1].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+    barriers[1].srcQueueFamilyIndex = queue_family_index;
+    barriers[1].dstQueueFamilyIndex = queue_family_index; //TODO support separate present queue.
+    barriers[1].image = _depth_stencil_image;
+    barriers[1].subresourceRange = view_info.subresourceRange;
+
+    vkCmdPipelineBarrier(cmd_bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+                         VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
+                         0, NULL, 0, NULL, 2, barriers);
+
+    vkEndCommandBuffer(cmd_bufs[i]);
+    _present_cmds.push_back(cmd_bufs[i]);
+  }
+
   return true;
 }

+ 4 - 0
panda/src/vulkandisplay/vulkanGraphicsWindow.h

@@ -57,10 +57,14 @@ private:
   VkRenderPass _render_pass;
   VkSemaphore _present_complete;
 
+  bool _layout_defined;
+  pvector<VkImage> _images;
   pvector<VkImageView> _image_views;
+  VkImage _depth_stencil_image;
   VkImageView _depth_stencil_view;
   pvector<VkFramebuffer> _framebuffers;
   uint32_t _image_index;
+  pvector<VkCommandBuffer> _present_cmds;
 
 public:
   static TypeHandle get_class_type() {