[metal] Use pipeline layout to query set and binding count

This avoids mutating the `active_count` in the command buffer state.
diff --git a/experimental/metal/direct_command_buffer.m b/experimental/metal/direct_command_buffer.m
index 45f1448..a1cf125 100644
--- a/experimental/metal/direct_command_buffer.m
+++ b/experimental/metal/direct_command_buffer.m
@@ -206,8 +206,6 @@
     // So we need to cache the descriptor information by ourselves and record them at dispatch time.
     struct {
       iree_hal_metal_descriptor_t bindings[IREE_HAL_METAL_MAX_DESCRIPTOR_SET_BINDING_COUNT];
-      // The number of binding slots (not max binding slot number) that are active.
-      uint32_t active_count;
     } descriptor_sets[IREE_HAL_METAL_PUSH_CONSTANT_BUFFER_INDEX];
 
     // All available push constants updated each time push_constants is called. Reset only with the
@@ -855,18 +853,12 @@
 
   IREE_TRACE_ZONE_BEGIN(z0);
 
-  // Push a descriptor set invalidate all sets with the given number and larger ones.
   IREE_ASSERT(set < IREE_HAL_METAL_PUSH_CONSTANT_BUFFER_INDEX);
-  for (iree_host_size_t i = set + 1; i < IREE_HAL_METAL_PUSH_CONSTANT_BUFFER_INDEX; ++i) {
-    command_buffer->state.descriptor_sets[i].active_count = 0;
-  }
-
   const iree_hal_descriptor_set_layout_t* set_layout =
       iree_hal_metal_pipeline_layout_descriptor_set_layout(pipeline_layout, set);
   iree_hal_metal_descriptor_t* descriptors = command_buffer->state.descriptor_sets[set].bindings;
 
   // Update descriptors in the current set.
-  command_buffer->state.descriptor_sets[set].active_count = binding_count;
   for (iree_host_size_t i = 0; i < binding_count; ++i) {
     iree_hal_metal_descriptor_t* descriptor = &descriptors[i];
 
@@ -913,10 +905,14 @@
   // Allocate the command segment and keep track of all necessary API data.
   uint8_t* storage_base = NULL;
   iree_hal_metal_command_segment_t* segment = NULL;
+  const iree_host_size_t set_count =
+      iree_hal_metal_pipeline_layout_descriptor_set_count(kernel_params.layout);
   iree_host_size_t descriptor_count = 0;
   // Calculate the total number of bindings across all descriptor sets.
-  for (iree_host_size_t i = 0; i < IREE_HAL_METAL_PUSH_CONSTANT_BUFFER_INDEX; ++i) {
-    descriptor_count += command_buffer->state.descriptor_sets[i].active_count;
+  for (iree_host_size_t i = 0; i < set_count; ++i) {
+    const iree_hal_descriptor_set_layout_t* set_layout =
+        iree_hal_metal_pipeline_layout_descriptor_set_layout(kernel_params.layout, i);
+    descriptor_count += iree_hal_metal_descriptor_set_layout_binding_count(set_layout);
   }
   iree_host_size_t descriptor_length = descriptor_count * sizeof(iree_hal_metal_descriptor_t);
   iree_host_size_t push_constant_count =
@@ -938,9 +934,11 @@
   segment->dispatch.descriptor_count = descriptor_count;
   uint8_t* descriptor_ptr = storage_base + sizeof(*segment);
   segment->dispatch.descriptors = (iree_hal_metal_descriptor_t*)descriptor_ptr;
-  for (iree_host_size_t i = 0; i < IREE_HAL_METAL_PUSH_CONSTANT_BUFFER_INDEX; ++i) {
-    iree_host_size_t current_size =
-        command_buffer->state.descriptor_sets[i].active_count * sizeof(iree_hal_metal_descriptor_t);
+  for (iree_host_size_t i = 0; i < set_count; ++i) {
+    const iree_hal_descriptor_set_layout_t* set_layout =
+        iree_hal_metal_pipeline_layout_descriptor_set_layout(kernel_params.layout, i);
+    iree_host_size_t binding_count = iree_hal_metal_descriptor_set_layout_binding_count(set_layout);
+    iree_host_size_t current_size = binding_count * sizeof(iree_hal_metal_descriptor_t);
     memcpy(descriptor_ptr, command_buffer->state.descriptor_sets[i].bindings, current_size);
     descriptor_ptr += current_size;
   }
diff --git a/experimental/metal/pipeline_layout.h b/experimental/metal/pipeline_layout.h
index 99de799..63ed66b 100644
--- a/experimental/metal/pipeline_layout.h
+++ b/experimental/metal/pipeline_layout.h
@@ -91,6 +91,10 @@
 iree_hal_metal_pipeline_layout_descriptor_set_layout(
     const iree_hal_pipeline_layout_t* pipeline_layout, uint32_t set);
 
+// Returns the descriptor set count in the given |pipeline_layout|.
+iree_host_size_t iree_hal_metal_pipeline_layout_descriptor_set_count(
+    const iree_hal_pipeline_layout_t* pipeline_layout);
+
 // Returns the push constant count in the given |pipeline_layout|.
 iree_host_size_t iree_hal_metal_pipeline_layout_push_constant_count(
     const iree_hal_pipeline_layout_t* pipeline_layout);
diff --git a/experimental/metal/pipeline_layout.m b/experimental/metal/pipeline_layout.m
index 056804f..4a687ed 100644
--- a/experimental/metal/pipeline_layout.m
+++ b/experimental/metal/pipeline_layout.m
@@ -182,6 +182,13 @@
   return NULL;
 }
 
+iree_host_size_t iree_hal_metal_pipeline_layout_descriptor_set_count(
+    const iree_hal_pipeline_layout_t* base_pipeline_layout) {
+  const iree_hal_metal_pipeline_layout_t* pipeline_layout =
+      iree_hal_metal_pipeline_layout_const_cast(base_pipeline_layout);
+  return pipeline_layout->set_layout_count;
+}
+
 iree_host_size_t iree_hal_metal_pipeline_layout_push_constant_count(
     const iree_hal_pipeline_layout_t* base_pipeline_layout) {
   const iree_hal_metal_pipeline_layout_t* pipeline_layout =