Răsfoiți Sursa

vulkan: Experiment with switching over to dynamic rendering

It's a lot less of a headache than dealing with the implicit layout transitions, and we can more easily stop and start rendering if we need to eg. switch cube map index

There's one point of annoyance, which is that we can't do pipeline barriers mid-render anymore... that's annoying, and it could be an issue if we're using a texture as both a storage image and a sampled image in the same pass, but maybe this is a good restriction to enforce on the Panda end

If we want to support pre-1.3 Vulkan, we could emulate dynamic rendering by creating one render pass per fb config that doesn't do any clears or discards or transitions
rdb 1 an în urmă
părinte
comite
a3f759b5f4

+ 5 - 0
panda/src/vulkandisplay/vulkanFrameData.cxx

@@ -142,6 +142,11 @@ end_transfer_cmd() {
         barrier.offset = 0;
         barrier.offset = 0;
         barrier.size = VK_WHOLE_SIZE;
         barrier.size = VK_WHOLE_SIZE;
       }
       }
+
+      tc->_initial_src_access_mask = 0;
+      tc->_initial_dst_access_mask = 0;
+      tc->_initial_src_layout = VK_IMAGE_LAYOUT_UNDEFINED;
+      tc->_initial_dst_layout = VK_IMAGE_LAYOUT_UNDEFINED;
     }
     }
     vkCmdPipelineBarrier(_transfer_cmd, _initial_barrier_src_stage_mask,
     vkCmdPipelineBarrier(_transfer_cmd, _initial_barrier_src_stage_mask,
                          _initial_barrier_dst_stage_mask, 0,
                          _initial_barrier_dst_stage_mask, 0,

+ 91 - 9
panda/src/vulkandisplay/vulkanGraphicsBuffer.cxx

@@ -144,7 +144,84 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   VulkanFrameData &frame_data = vkgsg->get_frame_data();
   VulkanFrameData &frame_data = vkgsg->get_frame_data();
   VkCommandBuffer cmd = frame_data._cmd;
   VkCommandBuffer cmd = frame_data._cmd;
 
 
-  VkClearValue *clears = (VkClearValue *)
+  VkRenderingAttachmentInfo *color_attachments = (VkRenderingAttachmentInfo *)
+    alloca(_attachments.size() * sizeof(VkRenderingAttachmentInfo));
+  VkRenderingAttachmentInfo depth_attachment;
+  //VkRenderingAttachmentInfo stencil_attachment;
+
+  VkRenderingInfo render_info = {VK_STRUCTURE_TYPE_RENDERING_INFO};
+  render_info.layerCount = 1;
+  render_info.renderArea.extent.width = _framebuffer_size[0];
+  render_info.renderArea.extent.height = _framebuffer_size[1];
+  render_info.colorAttachmentCount = 0;
+  render_info.pColorAttachments = color_attachments;
+
+  for (size_t i = 0; i < _attachments.size(); ++i) {
+    Attachment &attach = _attachments[i];
+    nassertr(!attach._tc->is_used_this_frame(frame_data), false);
+    attach._tc->mark_used_this_frame(frame_data);
+
+    VkImageLayout layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+    VkAccessFlags write_access_mask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    VkAccessFlags read_access_mask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+    VkPipelineStageFlags stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+
+    if (attach._plane == RTP_stencil || attach._plane == RTP_depth ||
+        attach._plane == RTP_depth_stencil) {
+      depth_attachment = {VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
+      render_info.pDepthAttachment = &depth_attachment;
+      vkgsg->_fb_depth_tc = attach._tc;
+
+      layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+      stage_mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+                 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+      write_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+      read_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+
+      if (get_clear_depth_active()) {
+        depth_attachment.clearValue.depthStencil.depth = get_clear_depth();
+        depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+      } else {
+        depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+      }
+      depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+      depth_attachment.imageView = attach._tc->get_image_view(0);
+      depth_attachment.imageLayout = layout;
+    }
+    else if (attach._plane == RTP_color) {
+      VkRenderingAttachmentInfo &color_attachment =
+        color_attachments[render_info.colorAttachmentCount++];
+      color_attachment = {VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
+      vkgsg->_fb_color_tc = attach._tc;
+
+      if (get_clear_active(attach._plane)) {
+        LColor clear_color = get_clear_value(attach._plane);
+        color_attachment.clearValue.color.float32[0] = clear_color[0];
+        color_attachment.clearValue.color.float32[1] = clear_color[1];
+        color_attachment.clearValue.color.float32[2] = clear_color[2];
+        color_attachment.clearValue.color.float32[3] = clear_color[3];
+        color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+      } else {
+        color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+      }
+      color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+      color_attachment.imageView = attach._tc->get_image_view(0);
+      color_attachment.imageLayout = layout;
+    }
+
+    if (attach._tc->_layout != layout ||
+        (attach._tc->_write_stage_mask & ~stage_mask) != 0 ||
+        (attach._tc->_read_stage_mask & ~stage_mask) != 0) {
+      frame_data.add_initial_barrier(attach._tc,
+        layout, stage_mask, read_access_mask | write_access_mask);
+    }
+  }
+
+  vkgsg->_vkCmdBeginRendering(cmd, &render_info);
+  vkgsg->_fb_config = _fb_config_id;
+  return true;
+
+  /*VkClearValue *clears = (VkClearValue *)
     alloca(sizeof(VkClearValue) * _attachments.size());
     alloca(sizeof(VkClearValue) * _attachments.size());
 
 
   VkRenderPassBeginInfo begin_info;
   VkRenderPassBeginInfo begin_info;
@@ -205,7 +282,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
 
 
   vkCmdBeginRenderPass(cmd, &begin_info, VK_SUBPASS_CONTENTS_INLINE);
   vkCmdBeginRenderPass(cmd, &begin_info, VK_SUBPASS_CONTENTS_INLINE);
   vkgsg->_render_pass = _render_pass;
   vkgsg->_render_pass = _render_pass;
-  vkgsg->_fb_config = _fb_config_id;
+  vkgsg->_fb_config = _fb_config_id;*/
 
 
   return true;
   return true;
 }
 }
@@ -225,7 +302,8 @@ end_frame(FrameMode mode, Thread *current_thread) {
     VkCommandBuffer cmd = vkgsg->_frame_data->_cmd;
     VkCommandBuffer cmd = vkgsg->_frame_data->_cmd;
     nassertv(cmd != VK_NULL_HANDLE);
     nassertv(cmd != VK_NULL_HANDLE);
 
 
-    vkCmdEndRenderPass(cmd);
+    vkgsg->_vkCmdEndRendering(cmd);
+    /*vkCmdEndRenderPass(cmd);
     vkgsg->_render_pass = VK_NULL_HANDLE;
     vkgsg->_render_pass = VK_NULL_HANDLE;
 
 
     // The driver implicitly transitioned this to the final layout.
     // The driver implicitly transitioned this to the final layout.
@@ -234,7 +312,7 @@ end_frame(FrameMode mode, Thread *current_thread) {
 
 
       // This seems to squelch a validation warning, not sure about this yet
       // This seems to squelch a validation warning, not sure about this yet
       attach._tc->_write_stage_mask |= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
       attach._tc->_write_stage_mask |= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-    }
+    }*/
 
 
     // Now we can do copy-to-texture, now that the render pass has ended.
     // Now we can do copy-to-texture, now that the render pass has ended.
     copy_to_textures();
     copy_to_textures();
@@ -332,6 +410,8 @@ open_buffer() {
  */
  */
 bool VulkanGraphicsBuffer::
 bool VulkanGraphicsBuffer::
 setup_render_pass() {
 setup_render_pass() {
+  return true;
+
   VulkanGraphicsStateGuardian *vkgsg;
   VulkanGraphicsStateGuardian *vkgsg;
   DCAST_INTO_R(vkgsg, _gsg, false);
   DCAST_INTO_R(vkgsg, _gsg, false);
 
 
@@ -531,14 +611,14 @@ destroy_framebuffer() {
   }
   }
   _attachments.clear();
   _attachments.clear();
 
 
-  if (_framebuffer != VK_NULL_HANDLE) {
+  /*if (_framebuffer != VK_NULL_HANDLE) {
     if (vkgsg->_last_frame_data != nullptr) {
     if (vkgsg->_last_frame_data != nullptr) {
       vkgsg->_last_frame_data->_pending_destroy_framebuffers.push_back(_framebuffer);
       vkgsg->_last_frame_data->_pending_destroy_framebuffers.push_back(_framebuffer);
     } else {
     } else {
       vkDestroyFramebuffer(device, _framebuffer, nullptr);
       vkDestroyFramebuffer(device, _framebuffer, nullptr);
     }
     }
     _framebuffer = VK_NULL_HANDLE;
     _framebuffer = VK_NULL_HANDLE;
-  }
+  }*/
 
 
   _is_valid = false;
   _is_valid = false;
 }
 }
@@ -552,8 +632,6 @@ create_framebuffer(CDReader &cdata) {
   VulkanGraphicsStateGuardian *vkgsg;
   VulkanGraphicsStateGuardian *vkgsg;
   DCAST_INTO_R(vkpipe, _pipe, false);
   DCAST_INTO_R(vkpipe, _pipe, false);
   DCAST_INTO_R(vkgsg, _gsg, false);
   DCAST_INTO_R(vkgsg, _gsg, false);
-  VkDevice device = vkgsg->_device;
-  VkResult err;
 
 
   PT(Texture) color_texture;
   PT(Texture) color_texture;
   PT(Texture) depth_texture;
   PT(Texture) depth_texture;
@@ -579,6 +657,10 @@ create_framebuffer(CDReader &cdata) {
     }
     }
   }
   }
 
 
+  /*
+  VkDevice device = vkgsg->_device;
+  VkResult err;
+
   uint32_t num_attachments = _attachments.size();
   uint32_t num_attachments = _attachments.size();
   VkImageView *attach_views = (VkImageView *)alloca(sizeof(VkImageView) * num_attachments);
   VkImageView *attach_views = (VkImageView *)alloca(sizeof(VkImageView) * num_attachments);
 
 
@@ -601,7 +683,7 @@ create_framebuffer(CDReader &cdata) {
   if (err) {
   if (err) {
     vulkan_error(err, "Failed to create framebuffer");
     vulkan_error(err, "Failed to create framebuffer");
     return false;
     return false;
-  }
+  }*/
 
 
   _framebuffer_size = _size;
   _framebuffer_size = _size;
   _is_valid = true;
   _is_valid = true;

+ 13 - 2
panda/src/vulkandisplay/vulkanGraphicsPipe.cxx

@@ -147,8 +147,8 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
   app_info.engineVersion = PANDA_NUMERIC_VERSION;
   app_info.engineVersion = PANDA_NUMERIC_VERSION;
   app_info.apiVersion = VK_API_VERSION_1_0;
   app_info.apiVersion = VK_API_VERSION_1_0;
 
 
-  if (inst_version >= VK_MAKE_VERSION(1, 1, 0)) {
-    app_info.apiVersion = VK_MAKE_VERSION(1, 1, 0);
+  if (inst_version >= VK_MAKE_VERSION(1, 3, 0)) {
+    app_info.apiVersion = VK_MAKE_VERSION(1, 3, 0);
   }
   }
 
 
   VkInstanceCreateInfo inst_info;
   VkInstanceCreateInfo inst_info;
@@ -310,6 +310,15 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
   if (pVkGetPhysicalDeviceFeatures2 != nullptr) {
   if (pVkGetPhysicalDeviceFeatures2 != nullptr) {
     VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
     VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
 
 
+    VkPhysicalDeviceDynamicRenderingFeatures dr_features = {
+      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
+      features2.pNext,
+    };
+    if (_gpu_properties.apiVersion >= VK_MAKE_VERSION(1, 3, 0) ||
+        has_device_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME)) {
+      features2.pNext = &dr_features;
+    }
+
     VkPhysicalDeviceCustomBorderColorFeaturesEXT cbc_features = {
     VkPhysicalDeviceCustomBorderColorFeaturesEXT cbc_features = {
       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
       features2.pNext,
       features2.pNext,
@@ -353,6 +362,7 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
 
 
     pVkGetPhysicalDeviceFeatures2(_gpu, &features2);
     pVkGetPhysicalDeviceFeatures2(_gpu, &features2);
     _gpu_features = features2.features;
     _gpu_features = features2.features;
+    _gpu_supports_dynamic_rendering = dr_features.dynamicRendering;
     _gpu_supports_custom_border_colors = cbc_features.customBorderColors
     _gpu_supports_custom_border_colors = cbc_features.customBorderColors
                                       && cbc_features.customBorderColorWithoutFormat;
                                       && cbc_features.customBorderColorWithoutFormat;
     _gpu_supports_null_descriptor = ro2_features.nullDescriptor;
     _gpu_supports_null_descriptor = ro2_features.nullDescriptor;
@@ -364,6 +374,7 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
   }
   }
   else {
   else {
     vkGetPhysicalDeviceFeatures(_gpu, &_gpu_features);
     vkGetPhysicalDeviceFeatures(_gpu, &_gpu_features);
+    _gpu_supports_dynamic_rendering = false;
     _gpu_supports_custom_border_colors = false;
     _gpu_supports_custom_border_colors = false;
     _gpu_supports_null_descriptor = false;
     _gpu_supports_null_descriptor = false;
     _gpu_supports_vertex_attrib_divisor = false;
     _gpu_supports_vertex_attrib_divisor = false;

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

@@ -74,6 +74,7 @@ public:
   VkPhysicalDevice _gpu;
   VkPhysicalDevice _gpu;
   VkPhysicalDeviceFeatures _gpu_features;
   VkPhysicalDeviceFeatures _gpu_features;
   VkPhysicalDeviceProperties _gpu_properties;
   VkPhysicalDeviceProperties _gpu_properties;
+  bool _gpu_supports_dynamic_rendering = false;
   bool _gpu_supports_custom_border_colors = false;
   bool _gpu_supports_custom_border_colors = false;
   bool _gpu_supports_null_descriptor = false;
   bool _gpu_supports_null_descriptor = false;
   bool _gpu_supports_vertex_attrib_divisor = false;
   bool _gpu_supports_vertex_attrib_divisor = false;

+ 66 - 7
panda/src/vulkandisplay/vulkanGraphicsStateGuardian.cxx

@@ -136,6 +136,22 @@ reset() {
   enabled_features.features.textureCompressionBC = features.textureCompressionBC;
   enabled_features.features.textureCompressionBC = features.textureCompressionBC;
   enabled_features.features.shaderFloat64 = features.shaderFloat64;
   enabled_features.features.shaderFloat64 = features.shaderFloat64;
 
 
+  VkPhysicalDeviceDynamicRenderingFeatures dr_features = {
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
+    enabled_features.pNext,
+  };
+  if (pipe->_gpu_supports_dynamic_rendering) {
+    dr_features.dynamicRendering = VK_TRUE;
+    enabled_features.pNext = &dr_features;
+
+    if (pipe->_gpu_properties.apiVersion < VK_MAKE_VERSION(1, 3, 0)) {
+      extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
+    }
+    _supports_dynamic_rendering = true;
+  } else {
+    _supports_dynamic_rendering = false;
+  }
+
   VkPhysicalDeviceCustomBorderColorFeaturesEXT cbc_features = {
   VkPhysicalDeviceCustomBorderColorFeaturesEXT cbc_features = {
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
     enabled_features.pNext,
     enabled_features.pNext,
@@ -294,6 +310,11 @@ reset() {
   _vkCmdPushConstants = (PFN_vkCmdPushConstants)vkGetDeviceProcAddr(_device, "vkCmdPushConstants");
   _vkCmdPushConstants = (PFN_vkCmdPushConstants)vkGetDeviceProcAddr(_device, "vkCmdPushConstants");
   _vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)vkGetDeviceProcAddr(_device, "vkUpdateDescriptorSets");
   _vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)vkGetDeviceProcAddr(_device, "vkUpdateDescriptorSets");
 
 
+  if (_supports_dynamic_rendering) {
+    _vkCmdBeginRendering = (PFN_vkCmdBeginRendering)vkGetDeviceProcAddr(_device, "vkCmdBeginRendering");
+    _vkCmdEndRendering = (PFN_vkCmdEndRendering)vkGetDeviceProcAddr(_device, "vkCmdEndRendering");
+  }
+
   if (_supports_extended_dynamic_state2) {
   if (_supports_extended_dynamic_state2) {
     _vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)vkGetDeviceProcAddr(_device, "vkCmdSetPrimitiveTopologyEXT");
     _vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)vkGetDeviceProcAddr(_device, "vkCmdSetPrimitiveTopologyEXT");
     _vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT)vkGetDeviceProcAddr(_device, "vkCmdSetPrimitiveRestartEnableEXT");
     _vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT)vkGetDeviceProcAddr(_device, "vkCmdSetPrimitiveRestartEnableEXT");
@@ -467,6 +488,21 @@ reset() {
     }
     }
   }
   }
 
 
+  // Make a descriptor set that we apply when there are no lights.
+  {
+    VkDescriptorSetAllocateInfo alloc_info;
+    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    alloc_info.pNext = nullptr;
+    alloc_info.descriptorPool = _descriptor_pool;
+    alloc_info.descriptorSetCount = 1;
+    alloc_info.pSetLayouts = &_lattr_descriptor_set_layout;
+    VkResult err = vkAllocateDescriptorSets(_device, &alloc_info, &_empty_lattr_descriptor_set);
+    if (err) {
+      vulkan_error(err, "Failed to allocate descriptor set for empty light attribute");
+      return;
+    }
+  }
+
   // Create a uniform buffer that we'll use for everything.
   // Create a uniform buffer that we'll use for everything.
   // Some cards set aside 256 MiB of device-local host-visible memory for data
   // Some cards set aside 256 MiB of device-local host-visible memory for data
   // like this, so we use that.
   // like this, so we use that.
@@ -937,6 +973,12 @@ use_texture(Texture *texture, VkImageLayout layout,
   VulkanTextureContext *tc;
   VulkanTextureContext *tc;
   DCAST_INTO_R(tc, texture->prepare_now(_prepared_objects, this), nullptr);
   DCAST_INTO_R(tc, texture->prepare_now(_prepared_objects, this), nullptr);
 
 
+  if (_fb_color_tc == tc || _fb_depth_tc == tc) {
+    vulkandisplay_cat.warning()
+      << "Attempt to use framebuffer texture " << *texture << " during render!\n";
+    return nullptr;
+  }
+
   // We only update the texture the first time it is used in a frame.
   // We only update the texture the first time it is used in a frame.
   // Otherwise, we would have to invalidate the descriptor sets.
   // Otherwise, we would have to invalidate the descriptor sets.
   if (!tc->is_used_this_frame(frame_data)) {
   if (!tc->is_used_this_frame(frame_data)) {
@@ -2640,12 +2682,17 @@ set_state_and_transform(const RenderState *state,
 
 
   uint32_t first_set = 0;
   uint32_t first_set = 0;
   const LightAttrib *target_light;
   const LightAttrib *target_light;
-  state->get_attrib_def(target_light);
+  state->get_attrib(target_light);
   if (shader_changed ||
   if (shader_changed ||
-      target_light != _state_rs->get_attrib_def(LightAttrib::get_class_slot())) {
-    if (get_attrib_descriptor_set(descriptor_sets[DS_light_attrib],
-                                  _lattr_descriptor_set_layout,
-                                  target_light)) {
+      target_light != _state_rs->get_attrib(LightAttrib::get_class_slot())) {
+    if (!sc->_uses_lattr_descriptors ||
+        target_light == nullptr ||
+        target_light->is_identity()) {
+      descriptor_sets[DS_light_attrib] = _empty_lattr_descriptor_set;
+    }
+    else if (get_attrib_descriptor_set(descriptor_sets[DS_light_attrib],
+                                      _lattr_descriptor_set_layout,
+                                      target_light)) {
       // The first time this set is bound in this frame, we update it.  Once we
       // The first time this set is bound in this frame, we update it.  Once we
       // use it in a command buffer, we can't update it again anyway.
       // use it in a command buffer, we can't update it again anyway.
       update_lattr_descriptor_set(descriptor_sets[DS_light_attrib], target_light);
       update_lattr_descriptor_set(descriptor_sets[DS_light_attrib], target_light);
@@ -4579,6 +4626,18 @@ make_pipeline(VulkanShaderContext *sc,
   pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
   pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
   pipeline_info.basePipelineIndex = 0;
   pipeline_info.basePipelineIndex = 0;
 
 
+  VkPipelineRenderingCreateInfo render_info;
+  if (_render_pass == VK_NULL_HANDLE) {
+    pipeline_info.pNext = &render_info;
+    render_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
+    render_info.pNext = nullptr;
+    render_info.viewMask = 0;
+    render_info.colorAttachmentCount = fb_config._color_formats.size();
+    render_info.pColorAttachmentFormats = fb_config._color_formats.data();
+    render_info.depthAttachmentFormat = fb_config._depth_format;
+    render_info.stencilAttachmentFormat = fb_config._stencil_format;
+  }
+
   VkResult err;
   VkResult err;
   VkPipeline pipeline;
   VkPipeline pipeline;
   err = vkCreateGraphicsPipelines(_device, _pipeline_cache, 1, &pipeline_info, nullptr, &pipeline);
   err = vkCreateGraphicsPipelines(_device, _pipeline_cache, 1, &pipeline_info, nullptr, &pipeline);
@@ -4748,8 +4807,8 @@ update_lattr_descriptor_set(VkDescriptorSet ds, const LightAttrib *attr) {
 
 
     VkDescriptorImageInfo &image_info = image_infos[i];
     VkDescriptorImageInfo &image_info = image_infos[i];
     image_info.sampler = VK_NULL_HANDLE;
     image_info.sampler = VK_NULL_HANDLE;
-    image_info.imageView = tc->get_image_view(0);
-    image_info.imageLayout = tc->_layout;
+    image_info.imageView = tc ? tc->get_image_view(0) : VK_NULL_HANDLE;
+    image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
 
     VkWriteDescriptorSet &write = writes[i];
     VkWriteDescriptorSet &write = writes[i];
     write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;

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

@@ -281,6 +281,7 @@ private:
   // The others are shader-dependent and stored in VulkanShaderContext.
   // The others are shader-dependent and stored in VulkanShaderContext.
   VkSampler _shadow_sampler;
   VkSampler _shadow_sampler;
   VkDescriptorSetLayout _lattr_descriptor_set_layout;
   VkDescriptorSetLayout _lattr_descriptor_set_layout;
+  VkDescriptorSet _empty_lattr_descriptor_set;
 
 
   // Keep track of all the individual allocations.
   // Keep track of all the individual allocations.
   Mutex _allocator_lock;
   Mutex _allocator_lock;
@@ -298,6 +299,7 @@ private:
   uint64_t _last_finished_frame = 0;
   uint64_t _last_finished_frame = 0;
 
 
   // Feature checks.
   // Feature checks.
+  bool _supports_dynamic_rendering = false;
   bool _supports_custom_border_colors = false;
   bool _supports_custom_border_colors = false;
   bool _supports_vertex_attrib_divisor = false;
   bool _supports_vertex_attrib_divisor = false;
   bool _supports_vertex_attrib_zero_divisor = false;
   bool _supports_vertex_attrib_zero_divisor = false;
@@ -305,11 +307,13 @@ private:
   bool _supports_extended_dynamic_state2_patch_control_points = false;
   bool _supports_extended_dynamic_state2_patch_control_points = false;
 
 
   // Function pointers.
   // Function pointers.
+  PFN_vkCmdBeginRendering _vkCmdBeginRendering;
   PFN_vkCmdBindIndexBuffer _vkCmdBindIndexBuffer;
   PFN_vkCmdBindIndexBuffer _vkCmdBindIndexBuffer;
   PFN_vkCmdBindPipeline _vkCmdBindPipeline;
   PFN_vkCmdBindPipeline _vkCmdBindPipeline;
   PFN_vkCmdBindVertexBuffers _vkCmdBindVertexBuffers;
   PFN_vkCmdBindVertexBuffers _vkCmdBindVertexBuffers;
   PFN_vkCmdDraw _vkCmdDraw;
   PFN_vkCmdDraw _vkCmdDraw;
   PFN_vkCmdDrawIndexed _vkCmdDrawIndexed;
   PFN_vkCmdDrawIndexed _vkCmdDrawIndexed;
+  PFN_vkCmdEndRendering _vkCmdEndRendering;
   PFN_vkCmdPushConstants _vkCmdPushConstants;
   PFN_vkCmdPushConstants _vkCmdPushConstants;
   PFN_vkCmdSetPatchControlPointsEXT _vkCmdSetPatchControlPointsEXT;
   PFN_vkCmdSetPatchControlPointsEXT _vkCmdSetPatchControlPointsEXT;
   PFN_vkCmdSetPrimitiveRestartEnableEXT _vkCmdSetPrimitiveRestartEnableEXT;
   PFN_vkCmdSetPrimitiveRestartEnableEXT _vkCmdSetPrimitiveRestartEnableEXT;

+ 105 - 20
panda/src/vulkandisplay/vulkanGraphicsWindow.cxx

@@ -89,7 +89,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
       << "Drawing " << this << ": exposed.\n";
       << "Drawing " << this << ": exposed.\n";
   }
   }
 
 
-  /*if (mode != FM_render) {
+  /*if (mode == FM_refresh) {
     return true;
     return true;
   }*/
   }*/
 
 
@@ -103,10 +103,10 @@ begin_frame(FrameMode mode, Thread *current_thread) {
       _image_available = VK_NULL_HANDLE;
       _image_available = VK_NULL_HANDLE;
     }
     }
     destroy_swapchain();
     destroy_swapchain();
-    if (_render_pass != VK_NULL_HANDLE) {
+    /*if (_render_pass != VK_NULL_HANDLE) {
       vkDestroyRenderPass(vkgsg->_device, _render_pass, nullptr);
       vkDestroyRenderPass(vkgsg->_device, _render_pass, nullptr);
       _render_pass = VK_NULL_HANDLE;
       _render_pass = VK_NULL_HANDLE;
-    }
+    }*/
     vkgsg->reset_if_new();
     vkgsg->reset_if_new();
   }
   }
 
 
@@ -114,14 +114,14 @@ begin_frame(FrameMode mode, Thread *current_thread) {
     return false;
     return false;
   }
   }
 
 
-  if (_current_clear_mask != _clear_mask || _render_pass == VK_NULL_HANDLE) {
+  /*if (_current_clear_mask != _clear_mask || _render_pass == VK_NULL_HANDLE) {
     // The clear flags have changed.  Recreate the render pass.  Note that the
     // The clear flags have changed.  Recreate the render pass.  Note that the
     // clear flags don't factor into render pass compatibility, so we don't
     // clear flags don't factor into render pass compatibility, so we don't
     // need to recreate the framebuffer.
     // need to recreate the framebuffer.
     if (!setup_render_pass()) {
     if (!setup_render_pass()) {
       return false;
       return false;
     }
     }
-  }
+  }*/
 
 
   if (_swapchain_size != _size) {
   if (_swapchain_size != _size) {
     // Uh-oh, the window must have resized.  Recreate the swapchain.
     // Uh-oh, the window must have resized.  Recreate the swapchain.
@@ -143,7 +143,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
 
 
   copy_async_screenshot();
   copy_async_screenshot();
 
 
-  if (mode != FM_render) {
+  if (mode == FM_refresh) {
     return true;
     return true;
   }
   }
 
 
@@ -174,7 +174,89 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   // transition the swapchain images into the valid state for rendering into.
   // transition the swapchain images into the valid state for rendering into.
   VkCommandBuffer cmd = frame_data._cmd;
   VkCommandBuffer cmd = frame_data._cmd;
 
 
-  VkClearValue clears[2];
+  VkRenderingInfo render_info = {VK_STRUCTURE_TYPE_RENDERING_INFO};
+  render_info.layerCount = 1;
+  render_info.renderArea.extent.width = _swapchain_size[0];
+  render_info.renderArea.extent.height = _swapchain_size[1];
+  render_info.colorAttachmentCount = 1;
+
+  VkRenderingAttachmentInfo color_attachment = {VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
+  color_attachment.imageView = color_tc->get_image_view(0);
+  color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+  render_info.pColorAttachments = &color_attachment;
+
+  if (get_clear_color_active()) {
+    LColor clear_color = get_clear_color();
+    color_attachment.clearValue.color.float32[0] = clear_color[0];
+    color_attachment.clearValue.color.float32[1] = clear_color[1];
+    color_attachment.clearValue.color.float32[2] = clear_color[2];
+    color_attachment.clearValue.color.float32[3] = clear_color[3];
+    color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+  } else {
+    color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+  }
+  color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+
+  if (color_tc->_layout != color_attachment.imageLayout ||
+      (color_tc->_write_stage_mask & ~VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT) != 0 ||
+      (color_tc->_read_stage_mask & ~VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT) != 0) {
+    frame_data.add_initial_barrier(color_tc,
+      color_attachment.imageLayout,
+      VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+      VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
+  }
+
+  VkRenderingAttachmentInfo depth_attachment = {VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
+  VkRenderingAttachmentInfo stencil_attachment = {VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
+  if (_depth_stencil_tc != nullptr) {
+    nassertr(!_depth_stencil_tc->is_used_this_frame(frame_data), false);
+    _depth_stencil_tc->mark_used_this_frame(frame_data);
+
+    if (_depth_stencil_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
+      render_info.pDepthAttachment = &depth_attachment;
+
+      if (get_clear_depth_active()) {
+        depth_attachment.clearValue.depthStencil.depth = get_clear_depth();
+        depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+      } else {
+        depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+      }
+      depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+      depth_attachment.imageView = _depth_stencil_tc->get_image_view(0);
+      depth_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+    }
+
+    if (_depth_stencil_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
+      render_info.pStencilAttachment = &stencil_attachment;
+
+      if (get_clear_stencil_active()) {
+        stencil_attachment.clearValue.depthStencil.stencil = get_clear_stencil();
+        stencil_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+      } else {
+        stencil_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+      }
+      stencil_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+      stencil_attachment.imageView = _depth_stencil_tc->get_image_view(0);
+      stencil_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+    }
+
+    if (_depth_stencil_tc->_layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
+        (_depth_stencil_tc->_write_stage_mask & ~VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT) != 0 ||
+        (_depth_stencil_tc->_read_stage_mask & ~VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT) != 0) {
+      frame_data.add_initial_barrier(_depth_stencil_tc,
+        VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+        VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
+        VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
+    }
+  }
+
+  vkgsg->_vkCmdBeginRendering(cmd, &render_info);
+  vkgsg->_fb_color_tc = color_tc;
+  vkgsg->_fb_depth_tc = _depth_stencil_tc;
+  vkgsg->_fb_config = _fb_config_id;
+  return true;
+
+  /*VkClearValue clears[2];
 
 
   VkRenderPassBeginInfo begin_info;
   VkRenderPassBeginInfo begin_info;
   begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
   begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@@ -261,7 +343,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   vkgsg->_fb_color_tc = color_tc;
   vkgsg->_fb_color_tc = color_tc;
   vkgsg->_fb_depth_tc = _depth_stencil_tc;
   vkgsg->_fb_depth_tc = _depth_stencil_tc;
   vkgsg->_fb_config = _fb_config_id;
   vkgsg->_fb_config = _fb_config_id;
-  return true;
+  return true;*/
 }
 }
 
 
 /**
 /**
@@ -281,17 +363,18 @@ end_frame(FrameMode mode, Thread *current_thread) {
   SwapBuffer &buffer = _swap_buffers[_image_index];
   SwapBuffer &buffer = _swap_buffers[_image_index];
 
 
   VkSemaphore signal_done = VK_NULL_HANDLE;
   VkSemaphore signal_done = VK_NULL_HANDLE;
-  if (mode == FM_render) {
-    vkCmdEndRenderPass(cmd);
+  if (mode != FM_refresh) {
+    vkgsg->_vkCmdEndRendering(cmd);
+/*    vkCmdEndRenderPass(cmd);
     vkgsg->_render_pass = VK_NULL_HANDLE;
     vkgsg->_render_pass = VK_NULL_HANDLE;
 
 
     // The driver implicitly transitioned this to the final layout.
     // The driver implicitly transitioned this to the final layout.
-    buffer._tc->_layout = _final_layout;
+    buffer._tc->_layout = _final_layout;*/
     buffer._tc->mark_written(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
     buffer._tc->mark_written(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                              VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
                              VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
 
 
     if (_depth_stencil_tc != nullptr) {
     if (_depth_stencil_tc != nullptr) {
-      _depth_stencil_tc->_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+      //_depth_stencil_tc->_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
       _depth_stencil_tc->mark_written(
       _depth_stencil_tc->mark_written(
         VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
         VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
@@ -465,10 +548,10 @@ close_window() {
     vkQueueWaitIdle(vkgsg->_queue);
     vkQueueWaitIdle(vkgsg->_queue);
     destroy_swapchain();
     destroy_swapchain();
 
 
-    if (_render_pass != VK_NULL_HANDLE) {
+    /*if (_render_pass != VK_NULL_HANDLE) {
       vkDestroyRenderPass(vkgsg->_device, _render_pass, nullptr);
       vkDestroyRenderPass(vkgsg->_device, _render_pass, nullptr);
       _render_pass = VK_NULL_HANDLE;
       _render_pass = VK_NULL_HANDLE;
-    }
+    }*/
 
 
     _gsg.clear();
     _gsg.clear();
   }
   }
@@ -651,6 +734,8 @@ open_window() {
  */
  */
 bool VulkanGraphicsWindow::
 bool VulkanGraphicsWindow::
 setup_render_pass() {
 setup_render_pass() {
+  return true;
+
   VulkanGraphicsStateGuardian *vkgsg;
   VulkanGraphicsStateGuardian *vkgsg;
   DCAST_INTO_R(vkgsg, _gsg, false);
   DCAST_INTO_R(vkgsg, _gsg, false);
 
 
@@ -835,7 +920,7 @@ destroy_swapchain() {
   // Destroy the resources held for each link in the swap chain.
   // Destroy the resources held for each link in the swap chain.
   for (SwapBuffer &buffer : _swap_buffers) {
   for (SwapBuffer &buffer : _swap_buffers) {
     // Destroy the framebuffers that use the swapchain images.
     // Destroy the framebuffers that use the swapchain images.
-    vkDestroyFramebuffer(device, buffer._framebuffer, nullptr);
+    //vkDestroyFramebuffer(device, buffer._framebuffer, nullptr);
     buffer._tc->_image = VK_NULL_HANDLE;
     buffer._tc->_image = VK_NULL_HANDLE;
     buffer._tc->destroy_now(device);
     buffer._tc->destroy_now(device);
     delete buffer._tc;
     delete buffer._tc;
@@ -879,7 +964,7 @@ create_swapchain() {
 
 
   if (vulkandisplay_cat.is_debug()) {
   if (vulkandisplay_cat.is_debug()) {
     vulkandisplay_cat.debug()
     vulkandisplay_cat.debug()
-      << "Creating swap chain and framebuffers for VulkanGraphicsWindow " << this << "\n";
+      << "Creating swap chain for VulkanGraphicsWindow " << this << "\n";
   }
   }
 
 
   // Get the surface capabilities to make sure we make a compatible swapchain.
   // Get the surface capabilities to make sure we make a compatible swapchain.
@@ -1099,7 +1184,7 @@ create_swapchain() {
   }
   }
 
 
   // Now finally create a framebuffer for each link in the swap chain.
   // Now finally create a framebuffer for each link in the swap chain.
-  VkImageView attach_views[3];
+  /*VkImageView attach_views[3];
   uint32_t num_views = 1;
   uint32_t num_views = 1;
 
 
   if (ms_color_view != VK_NULL_HANDLE) {
   if (ms_color_view != VK_NULL_HANDLE) {
@@ -1120,11 +1205,11 @@ create_swapchain() {
   fb_info.pAttachments = attach_views;
   fb_info.pAttachments = attach_views;
   fb_info.width = swapchain_info.imageExtent.width;
   fb_info.width = swapchain_info.imageExtent.width;
   fb_info.height = swapchain_info.imageExtent.height;
   fb_info.height = swapchain_info.imageExtent.height;
-  fb_info.layers = 1;
+  fb_info.layers = 1;*/
 
 
   for (uint32_t i = 0; i < num_images; ++i) {
   for (uint32_t i = 0; i < num_images; ++i) {
     SwapBuffer &buffer = _swap_buffers[i];
     SwapBuffer &buffer = _swap_buffers[i];
-    if (_ms_color_tc != nullptr) {
+    /*if (_ms_color_tc != nullptr) {
       attach_views[num_views - 1] = buffer._tc->get_image_view(0);
       attach_views[num_views - 1] = buffer._tc->get_image_view(0);
     } else {
     } else {
       attach_views[0] = buffer._tc->get_image_view(0);
       attach_views[0] = buffer._tc->get_image_view(0);
@@ -1133,7 +1218,7 @@ create_swapchain() {
     if (err) {
     if (err) {
       vulkan_error(err, "Failed to create framebuffer");
       vulkan_error(err, "Failed to create framebuffer");
       return false;
       return false;
-    }
+    }*/
 
 
     // Don't start rendering until the image has been acquired.
     // Don't start rendering until the image has been acquired.
     buffer._tc->mark_written(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0);
     buffer._tc->mark_written(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0);

+ 52 - 9
panda/src/vulkandisplay/vulkanShaderContext.cxx

@@ -68,6 +68,7 @@ create_modules(VkDevice device, const ShaderType::Struct *push_constant_block_ty
   // Abuse the var id field in the access chain to store the parameter index.
   // Abuse the var id field in the access chain to store the parameter index.
   // Later we replace it with the id, because the id is unique per-module.
   // Later we replace it with the id, because the id is unique per-module.
   pvector<AccessChain> tattr_set_params;
   pvector<AccessChain> tattr_set_params;
+  pvector<AccessChain> lattr_set_params;
   pvector<AccessChain> sattr_set_params;
   pvector<AccessChain> sattr_set_params;
 
 
   ShaderType::Struct shader_input_block_struct;
   ShaderType::Struct shader_input_block_struct;
@@ -86,13 +87,21 @@ create_modules(VkDevice device, const ShaderType::Struct *push_constant_block_ty
     const ShaderType *remaining_type = r_extract_resources(param, chain, descriptors, param._type, num_resources);
     const ShaderType *remaining_type = r_extract_resources(param, chain, descriptors, param._type, num_resources);
 
 
     if (num_resources > 0) {
     if (num_resources > 0) {
-      if (param._binding->get_state_dep() & Shader::D_texture) {
+      int state_dep = param._binding->get_state_dep();
+      if (state_dep & Shader::D_texture) {
         for (auto &item : descriptors) {
         for (auto &item : descriptors) {
           tattr_set_params.push_back(item.first);
           tattr_set_params.push_back(item.first);
           _tattr_descriptors.push_back(std::move(item.second));
           _tattr_descriptors.push_back(std::move(item.second));
         }
         }
         _num_tattr_descriptor_elements += num_resources;
         _num_tattr_descriptor_elements += num_resources;
-      } else {
+      }
+      else if (state_dep & Shader::D_light) {
+        for (auto &item : descriptors) {
+          lattr_set_params.push_back(item.first);
+        }
+        _uses_lattr_descriptors = true;
+      }
+      else {
         for (auto &item : descriptors) {
         for (auto &item : descriptors) {
           sattr_set_params.push_back(item.first);
           sattr_set_params.push_back(item.first);
           _sattr_descriptors.push_back(std::move(item.second));
           _sattr_descriptors.push_back(std::move(item.second));
@@ -195,6 +204,20 @@ create_modules(VkDevice device, const ShaderType::Struct *push_constant_block_ty
         tattr_set_ids[i] = spv_module->get_parameter(index).id;
         tattr_set_ids[i] = spv_module->get_parameter(index).id;
       }
       }
     }
     }
+    pvector<uint32_t> lattr_set_ids(lattr_set_params.size(), 0u);
+    for (size_t i = 0; i < lattr_set_params.size(); ++i) {
+      const AccessChain &chain = lattr_set_params[i];
+      int index = spv_module->find_parameter(_shader->_parameters[chain._var_id]._name);
+      if (index < 0) {
+        continue;
+      }
+      if (chain.size() > 0) {
+        // In a struct, need to hoist.
+        needs_hoist = true;
+      } else {
+        lattr_set_ids[i] = spv_module->get_parameter(index).id;
+      }
+    }
     pvector<uint32_t> sattr_set_ids(sattr_set_params.size(), 0u);
     pvector<uint32_t> sattr_set_ids(sattr_set_params.size(), 0u);
     for (size_t i = 0; i < sattr_set_params.size(); ++i) {
     for (size_t i = 0; i < sattr_set_params.size(); ++i) {
       const AccessChain &chain = sattr_set_params[i];
       const AccessChain &chain = sattr_set_params[i];
@@ -233,6 +256,22 @@ create_modules(VkDevice device, const ShaderType::Struct *push_constant_block_ty
           }
           }
         }
         }
       }
       }
+      for (size_t i = 0; i < lattr_set_params.size(); ++i) {
+        AccessChain chain = lattr_set_params[i];
+        if (chain.size() > 0) {
+          int index = spv_module->find_parameter(_shader->_parameters[chain._var_id]._name);
+          if (index > 0) {
+            chain._var_id = spv_module->get_parameter(index).id;
+            auto it = hoist_pass._hoisted_vars.find(chain);
+            if (it != hoist_pass._hoisted_vars.end()) {
+              // Check if it hasn't been removed due to being unused.
+              if (transformer.get_db().has_definition(it->second)) {
+                lattr_set_ids[i] = it->second;
+              }
+            }
+          }
+        }
+      }
       for (size_t i = 0; i < sattr_set_params.size(); ++i) {
       for (size_t i = 0; i < sattr_set_params.size(); ++i) {
         AccessChain chain = sattr_set_params[i];
         AccessChain chain = sattr_set_params[i];
         if (chain.size() > 0) {
         if (chain.size() > 0) {
@@ -279,6 +318,9 @@ create_modules(VkDevice device, const ShaderType::Struct *push_constant_block_ty
     if (!tattr_set_ids.empty()) {
     if (!tattr_set_ids.empty()) {
       transformer.bind_descriptor_set(VulkanGraphicsStateGuardian::DS_texture_attrib, tattr_set_ids);
       transformer.bind_descriptor_set(VulkanGraphicsStateGuardian::DS_texture_attrib, tattr_set_ids);
     }
     }
+    if (!lattr_set_ids.empty()) {
+      transformer.bind_descriptor_set(VulkanGraphicsStateGuardian::DS_light_attrib, lattr_set_ids);
+    }
     if (!sattr_set_ids.empty()) {
     if (!sattr_set_ids.empty()) {
       if (_shader_input_block._size > 0) {
       if (_shader_input_block._size > 0) {
         // Make room for the uniform buffer binding.
         // Make room for the uniform buffer binding.
@@ -310,7 +352,8 @@ create_modules(VkDevice device, const ShaderType::Struct *push_constant_block_ty
       success = false;
       success = false;
     }
     }
 
 
-    if (spv_module->get_stage() == Shader::Stage::FRAGMENT) {
+    if (spv_module->get_stage() == Shader::Stage::FRAGMENT &&
+        !_shader->_subsumes_alpha_test) {
       // Set us up to easily create versions of the shader for various alpha
       // Set us up to easily create versions of the shader for various alpha
       // testing modes.
       // testing modes.
       SpirVInjectAlphaTestPass pass(SpirVInjectAlphaTestPass::M_greater, 0, true);
       SpirVInjectAlphaTestPass pass(SpirVInjectAlphaTestPass::M_greater, 0, true);
@@ -662,8 +705,8 @@ fetch_descriptor(VulkanGraphicsStateGuardian *gsg, const Descriptor &desc,
 
 
       VkDescriptorImageInfo &image_info = *image_infos++;
       VkDescriptorImageInfo &image_info = *image_infos++;
       image_info.sampler = sc->_sampler;
       image_info.sampler = sc->_sampler;
-      image_info.imageView = tc->get_image_view(view);
-      image_info.imageLayout = tc->_layout;
+      image_info.imageView = tc ? tc->get_image_view(view) : VK_NULL_HANDLE;
+      image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
     }
     }
     break;
     break;
 
 
@@ -682,7 +725,7 @@ fetch_descriptor(VulkanGraphicsStateGuardian *gsg, const Descriptor &desc,
                             VK_ACCESS_SHADER_READ_BIT);
                             VK_ACCESS_SHADER_READ_BIT);
 
 
       VkBufferView &texel_buffer_view = *texel_buffer_views++;
       VkBufferView &texel_buffer_view = *texel_buffer_views++;
-      texel_buffer_view = tc->get_buffer_view(view);
+      texel_buffer_view = tc ? tc->get_buffer_view(view) : VK_NULL_HANDLE;
     }
     }
     break;
     break;
 
 
@@ -716,12 +759,12 @@ fetch_descriptor(VulkanGraphicsStateGuardian *gsg, const Descriptor &desc,
       int view = gsg->get_current_tex_view_offset();
       int view = gsg->get_current_tex_view_offset();
       if (desc._type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
       if (desc._type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
         VkBufferView &texel_buffer_view = *texel_buffer_views++;
         VkBufferView &texel_buffer_view = *texel_buffer_views++;
-        texel_buffer_view = tc->get_buffer_view(view);
+        texel_buffer_view = tc ? tc->get_buffer_view(view) : VK_NULL_HANDLE;
       } else {
       } else {
         VkDescriptorImageInfo &image_info = *image_infos++;
         VkDescriptorImageInfo &image_info = *image_infos++;
         image_info.sampler = VK_NULL_HANDLE;
         image_info.sampler = VK_NULL_HANDLE;
-        image_info.imageView = tc->get_image_view(view);
-        image_info.imageLayout = tc->_layout;
+        image_info.imageView = tc ? tc->get_image_view(view) : VK_NULL_HANDLE;
+        image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
       }
       }
     }
     }
     break;
     break;

+ 2 - 0
panda/src/vulkandisplay/vulkanShaderContext.h

@@ -157,6 +157,8 @@ private:
   pvector<Descriptor> _sattr_descriptors;
   pvector<Descriptor> _sattr_descriptors;
   size_t _num_sattr_descriptor_elements = 0;
   size_t _num_sattr_descriptor_elements = 0;
 
 
+  bool _uses_lattr_descriptors = false;
+
   VkDescriptorSet _uniform_descriptor_set = VK_NULL_HANDLE;
   VkDescriptorSet _uniform_descriptor_set = VK_NULL_HANDLE;
   VkBuffer _uniform_buffer = VK_NULL_HANDLE;
   VkBuffer _uniform_buffer = VK_NULL_HANDLE;
   uint32_t _dynamic_uniform_offset = 0;
   uint32_t _dynamic_uniform_offset = 0;