anv: Compact render targets
authorJason Ekstrand <jason.ekstrand@intel.com>
Tue, 8 Mar 2016 01:28:00 +0000 (17:28 -0800)
committerJason Ekstrand <jason.ekstrand@intel.com>
Tue, 8 Mar 2016 23:40:11 +0000 (15:40 -0800)
Previously, we would always emit all of the render targets in the subpass.
This commit changes it so that we compact render targets just like we do
with other resources.  Render targets are represented in the surface map by
using a descriptor set index of UINT16_MAX.

src/intel/vulkan/anv_cmd_buffer.c
src/intel/vulkan/anv_pipeline.c
src/intel/vulkan/anv_private.h
src/intel/vulkan/gen8_pipeline.c

index 9dca21d527aa95a19d67ce31266c2bb976934ce7..ac8bf5fc619044ac15246a76d9c7e63a65a62737 100644 (file)
@@ -736,10 +736,6 @@ anv_cmd_buffer_emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
    uint32_t bias, state_offset;
 
    switch (stage) {
-   case  MESA_SHADER_FRAGMENT:
-      map = &cmd_buffer->state.pipeline->bindings[stage];
-      bias = MAX_RTS;
-      break;
    case  MESA_SHADER_COMPUTE:
       map = &cmd_buffer->state.compute_pipeline->bindings[stage];
       bias = 1;
@@ -763,25 +759,6 @@ anv_cmd_buffer_emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
    if (bt_state->map == NULL)
       return VK_ERROR_OUT_OF_DEVICE_MEMORY;
 
-   if (stage == MESA_SHADER_FRAGMENT) {
-      if (subpass->color_count == 0) {
-         struct anv_state null_surface =
-            anv_cmd_buffer_alloc_null_surface_state(cmd_buffer,
-                                                    cmd_buffer->state.framebuffer);
-         bt_map[0] = null_surface.offset + state_offset;
-      } else {
-         for (uint32_t a = 0; a < subpass->color_count; a++) {
-            const struct anv_image_view *iview =
-               fb->attachments[subpass->color_attachments[a]];
-
-            assert(iview->color_rt_surface_state.alloc_size);
-            bt_map[a] = iview->color_rt_surface_state.offset + state_offset;
-            add_surface_state_reloc(cmd_buffer, iview->color_rt_surface_state,
-                                    iview->bo, iview->offset);
-         }
-      }
-   }
-
    if (stage == MESA_SHADER_COMPUTE &&
        get_cs_prog_data(cmd_buffer->state.compute_pipeline)->uses_num_work_groups) {
       struct anv_bo *bo = cmd_buffer->state.num_workgroups_bo;
@@ -815,14 +792,37 @@ anv_cmd_buffer_emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
    uint32_t image = 0;
    for (uint32_t s = 0; s < map->surface_count; s++) {
       struct anv_pipeline_binding *binding = &map->surface_to_descriptor[s];
-      struct anv_descriptor_set *set =
-         cmd_buffer->state.descriptors[binding->set];
-      struct anv_descriptor *desc = &set->descriptors[binding->offset];
 
       struct anv_state surface_state;
       struct anv_bo *bo;
       uint32_t bo_offset;
 
+      if (binding->set == ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS) {
+         /* Color attachment binding */
+         assert(stage == MESA_SHADER_FRAGMENT);
+         if (binding->offset < subpass->color_count) {
+            const struct anv_image_view *iview =
+               fb->attachments[subpass->color_attachments[binding->offset]];
+
+            assert(iview->color_rt_surface_state.alloc_size);
+            surface_state = iview->color_rt_surface_state;
+            add_surface_state_reloc(cmd_buffer, iview->color_rt_surface_state,
+                                    iview->bo, iview->offset);
+         } else {
+            /* Null render target */
+            struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
+            surface_state =
+               anv_cmd_buffer_alloc_null_surface_state(cmd_buffer, fb);
+         }
+
+         bt_map[bias + s] = surface_state.offset + state_offset;
+         continue;
+      }
+
+      struct anv_descriptor_set *set =
+         cmd_buffer->state.descriptors[binding->set];
+      struct anv_descriptor *desc = &set->descriptors[binding->offset];
+
       switch (desc->type) {
       case VK_DESCRIPTOR_TYPE_SAMPLER:
          /* Nothing for us to do here */
index 22af44d6020107af05a9dd2c91238187b4987e50..abe93a50af8e5eb0185604948ab9feafca054a83 100644 (file)
@@ -599,9 +599,6 @@ anv_pipeline_compile_fs(struct anv_pipeline *pipeline,
 
    populate_wm_prog_key(&pipeline->device->info, info, extra, &key);
 
-   if (pipeline->use_repclear)
-      key.nr_color_regions = 1;
-
    if (module->size > 0) {
       anv_hash_shader(sha1, &key, sizeof(key), module, entrypoint, spec_info);
       kernel = anv_pipeline_cache_search(cache, sha1, &stage_prog_data, &map);
@@ -613,7 +610,7 @@ anv_pipeline_compile_fs(struct anv_pipeline *pipeline,
       struct anv_pipeline_binding sampler_to_descriptor[256];
 
       map = (struct anv_pipeline_bind_map) {
-         .surface_to_descriptor = surface_to_descriptor,
+         .surface_to_descriptor = surface_to_descriptor + 8,
          .sampler_to_descriptor = sampler_to_descriptor
       };
 
@@ -623,6 +620,8 @@ anv_pipeline_compile_fs(struct anv_pipeline *pipeline,
       if (nir == NULL)
          return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
 
+      unsigned num_rts = 0;
+      struct anv_pipeline_binding rt_bindings[8];
       nir_function_impl *impl = nir_shader_get_entrypoint(nir)->impl;
       nir_foreach_variable_safe(var, &nir->outputs) {
          if (var->data.location < FRAG_RESULT_DATA0)
@@ -630,13 +629,52 @@ anv_pipeline_compile_fs(struct anv_pipeline *pipeline,
 
          unsigned rt = var->data.location - FRAG_RESULT_DATA0;
          if (rt >= key.nr_color_regions) {
+            /* Out-of-bounds, throw it away */
             var->data.mode = nir_var_local;
             exec_node_remove(&var->node);
             exec_list_push_tail(&impl->locals, &var->node);
+            continue;
+         }
+
+         /* Give it a new, compacted, location */
+         var->data.location = FRAG_RESULT_DATA0 + num_rts;
+
+         unsigned array_len =
+            glsl_type_is_array(var->type) ? glsl_get_length(var->type) : 1;
+         assert(num_rts + array_len <= 8);
+
+         for (unsigned i = 0; i < array_len; i++) {
+            rt_bindings[num_rts] = (struct anv_pipeline_binding) {
+               .set = ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS,
+               .offset = rt + i,
+            };
          }
+
+         num_rts += array_len;
+      }
+
+      if (pipeline->use_repclear) {
+         assert(num_rts == 1);
+         key.nr_color_regions = 1;
       }
 
-      anv_fill_binding_table(&prog_data.base, MAX_RTS);
+      if (num_rts == 0) {
+         /* If we have no render targets, we need a null render target */
+         rt_bindings[0] = (struct anv_pipeline_binding) {
+            .set = ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS,
+            .offset = UINT16_MAX,
+         };
+         num_rts = 1;
+      }
+
+      assert(num_rts <= 8);
+      map.surface_to_descriptor -= num_rts;
+      map.surface_count += num_rts;
+      assert(map.surface_count <= 256);
+      memcpy(map.surface_to_descriptor, rt_bindings,
+             num_rts * sizeof(*rt_bindings));
+
+      anv_fill_binding_table(&prog_data.base, num_rts);
 
       void *mem_ctx = ralloc_context(NULL);
 
index 7791bbc16491d530e365ea02324d9c53647573ca..f24ea20115ba1155b8788bfa66e622eb0f5957d9 100644 (file)
@@ -995,11 +995,16 @@ anv_descriptor_set_destroy(struct anv_device *device,
                            struct anv_descriptor_pool *pool,
                            struct anv_descriptor_set *set);
 
+#define ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS UINT16_MAX
+
 struct anv_pipeline_binding {
-   /* The descriptor set this surface corresponds to */
+   /* The descriptor set this surface corresponds to.  The special value of
+    * ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS indicates that the offset refers
+    * to a color attachment and not a regular descriptor.
+    */
    uint16_t set;
 
-   /* Offset into the descriptor set */
+   /* Offset into the descriptor set or attachment list. */
    uint16_t offset;
 };
 
@@ -1404,9 +1409,11 @@ struct anv_pipeline_bind_map {
    uint32_t surface_count;
    uint32_t sampler_count;
    uint32_t image_count;
+   uint32_t attachment_count;
 
    struct anv_pipeline_binding *                surface_to_descriptor;
    struct anv_pipeline_binding *                sampler_to_descriptor;
+   uint32_t *                                   surface_to_attachment;
 };
 
 struct anv_pipeline {
index 10dd6457fbc99dc9079c8d2e83f24bc38cda2116..71705d23200379aa2d443f05fc30bc24b44c4663 100644 (file)
@@ -114,9 +114,33 @@ emit_cb_state(struct anv_pipeline *pipeline,
       .AlphaToOneEnable = ms_info && ms_info->alphaToOneEnable,
    };
 
+   /* Default everything to disabled */
+   for (uint32_t i = 0; i < 8; i++) {
+      blend_state.Entry[i].WriteDisableAlpha = true;
+      blend_state.Entry[i].WriteDisableRed = true;
+      blend_state.Entry[i].WriteDisableGreen = true;
+      blend_state.Entry[i].WriteDisableBlue = true;
+   }
+
+   struct anv_pipeline_bind_map *map =
+      &pipeline->bindings[MESA_SHADER_FRAGMENT];
+
    bool has_writeable_rt = false;
-   for (uint32_t i = 0; i < info->attachmentCount; i++) {
-      const VkPipelineColorBlendAttachmentState *a = &info->pAttachments[i];
+   for (unsigned i = 0; i < map->surface_count; i++) {
+      struct anv_pipeline_binding *binding = &map->surface_to_descriptor[i];
+
+      /* All color attachments are at the beginning of the binding table */
+      if (binding->set != ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS)
+         break;
+
+      /* We can have at most 8 attachments */
+      assert(i < 8);
+
+      if (binding->offset >= info->attachmentCount)
+         continue;
+
+      const VkPipelineColorBlendAttachmentState *a =
+         &info->pAttachments[binding->offset];
 
       if (a->srcColorBlendFactor != a->srcAlphaBlendFactor ||
           a->dstColorBlendFactor != a->dstAlphaBlendFactor ||
@@ -165,13 +189,6 @@ emit_cb_state(struct anv_pipeline *pipeline,
       }
    }
 
-   for (uint32_t i = info->attachmentCount; i < 8; i++) {
-      blend_state.Entry[i].WriteDisableAlpha = true;
-      blend_state.Entry[i].WriteDisableRed = true;
-      blend_state.Entry[i].WriteDisableGreen = true;
-      blend_state.Entry[i].WriteDisableBlue = true;
-   }
-
    if (info->attachmentCount > 0) {
       struct GENX(BLEND_STATE_ENTRY) *bs = &blend_state.Entry[0];