anv: Rename cpp variable to "bs"
[mesa.git] / src / vulkan / anv_image.c
index 21099cb77301a5a271611fca7e27c7edc62745f8..8aa74c2e191a56f7fb0bc11a6d184401977eed0e 100644 (file)
 
 #include "anv_private.h"
 
-struct anv_image_view_info {
-   uint8_t surface_type; /**< RENDER_SURFACE_STATE.SurfaceType */
-   bool is_array:1; /**< RENDER_SURFACE_STATE.SurfaceArray */
-   bool is_cube:1; /**< RENDER_SURFACE_STATE.CubeFaceEnable* */
-};
-
 static const uint8_t anv_halign[] = {
     [4] = HALIGN4,
     [8] = HALIGN8,
@@ -51,7 +45,6 @@ static const uint8_t anv_surf_type_from_image_type[] = {
    [VK_IMAGE_TYPE_1D] = SURFTYPE_1D,
    [VK_IMAGE_TYPE_2D] = SURFTYPE_2D,
    [VK_IMAGE_TYPE_3D] = SURFTYPE_3D,
-
 };
 
 static const struct anv_image_view_info
@@ -67,12 +60,18 @@ anv_image_view_info_table[] = {
    #undef INFO
 };
 
+struct anv_image_view_info
+anv_image_view_info_for_vk_image_view_type(VkImageViewType type)
+{
+   return anv_image_view_info_table[type];
+}
+
 static const struct anv_surf_type_limits {
    int32_t width;
    int32_t height;
    int32_t depth;
 } anv_surf_type_limits[] = {
-   [SURFTYPE_1D]     = {16384,       0,   2048},
+   [SURFTYPE_1D]     = {16384,       1,   2048},
    [SURFTYPE_2D]     = {16384,   16384,   2048},
    [SURFTYPE_3D]     = {2048,     2048,   2048},
    [SURFTYPE_CUBE]   = {16384,   16384,    340},
@@ -103,28 +102,40 @@ static const struct anv_tile_info {
    [WMAJOR] = { 128, 32, 4096 },
 };
 
-static uint32_t
+static uint8_t
 anv_image_choose_tile_mode(const struct anv_image_create_info *anv_info)
 {
    if (anv_info->force_tile_mode)
       return anv_info->tile_mode;
 
-   if (anv_info->vk_info->format == VK_FORMAT_S8_UINT)
-      return WMAJOR;
+   /* The Sandybridge PRM says that the stencil buffer "is supported
+    * only in Tile W memory".
+    */
 
    switch (anv_info->vk_info->tiling) {
    case VK_IMAGE_TILING_LINEAR:
+      assert(anv_info->vk_info->format != VK_FORMAT_S8_UINT);
       return LINEAR;
    case VK_IMAGE_TILING_OPTIMAL:
-      return YMAJOR;
+      if (unlikely(anv_info->vk_info->format == VK_FORMAT_S8_UINT)) {
+         return WMAJOR;
+      } else {
+         return YMAJOR;
+      }
    default:
       assert(!"bad VKImageTiling");
       return LINEAR;
    }
 }
 
+
+/**
+ * The \a format argument is required and overrides any format in
+ * struct anv_image_create_info.
+ */
 static VkResult
 anv_image_make_surface(const struct anv_image_create_info *create_info,
+                       const struct anv_format *format,
                        uint64_t *inout_image_size,
                        uint32_t *inout_image_alignment,
                        struct anv_surface *out_surface)
@@ -136,36 +147,69 @@ anv_image_make_surface(const struct anv_image_create_info *create_info,
    const VkExtent3D *restrict extent = &create_info->vk_info->extent;
    const uint32_t levels = create_info->vk_info->mipLevels;
    const uint32_t array_size = create_info->vk_info->arraySize;
-
    const uint8_t tile_mode = anv_image_choose_tile_mode(create_info);
 
    const struct anv_tile_info *tile_info =
        &anv_tile_info_table[tile_mode];
 
-   const struct anv_format *format_info =
-      anv_format_for_vk_format(create_info->vk_info->format);
-
    const uint32_t i = 4; /* FINISHME: Stop hardcoding subimage alignment */
    const uint32_t j = 4; /* FINISHME: Stop hardcoding subimage alignment */
-   const uint32_t w0 = align_u32(extent->width, i);
-   const uint32_t h0 = align_u32(extent->height, j);
 
-   uint16_t qpitch;
-   uint32_t mt_width;
-   uint32_t mt_height;
+   uint16_t qpitch = min_qpitch;
+   uint32_t mt_width = 0;
+   uint32_t mt_height = 0;
 
-   if (levels == 1 && array_size == 1) {
-      qpitch = min_qpitch;
-      mt_width = w0;
-      mt_height = h0;
-   } else {
-      uint32_t w1 = align_u32(anv_minify(extent->width, 1), i);
-      uint32_t h1 = align_u32(anv_minify(extent->height, 1), j);
-      uint32_t w2 = align_u32(anv_minify(extent->width, 2), i);
+   switch (create_info->vk_info->imageType) {
+   case VK_IMAGE_TYPE_1D:
+      /* From the Broadwell PRM >> Memory Views >> Common Surface Formats >>
+       * Surface Layout >> 1D Surfaces:
+       *
+       *    One-dimensional surfaces are identical to 2D surfaces with height of one.
+       *
+       * So fallthrough...
+       */
+   case VK_IMAGE_TYPE_2D: {
+      const uint32_t w0 = align_u32(extent->width, i);
+      const uint32_t h0 = align_u32(extent->height, j);
+
+      if (levels == 1 && array_size == 1) {
+         qpitch = min_qpitch;
+         mt_width = w0;
+         mt_height = h0;
+      } else {
+         uint32_t w1 = align_u32(anv_minify(extent->width, 1), i);
+         uint32_t h1 = align_u32(anv_minify(extent->height, 1), j);
+         uint32_t w2 = align_u32(anv_minify(extent->width, 2), i);
+
+         /* The QPitch equation is found in the Broadwell PRM >> Volume 5: Memory
+          * Views >> Common Surface Formats >> Surface Layout >> 2D Surfaces >>
+          * Surface Arrays >> For All Surface Other Than Separate Stencil Buffer:
+          */
+         qpitch = h0 + h1 + 11 * j;
+         mt_width = MAX(w0, w1 + w2);
+         mt_height = array_size * qpitch;
+      }
+      break;
+   }
+   case VK_IMAGE_TYPE_3D:
+      /* The layout of 3D surfaces is described by the Broadwell PRM >>
+       * Volume 5: Memory Views >> Common Surface Formats >> Surface Layout >>
+       * 3D Surfaces.
+       */
+      for (uint32_t l = 0; l < levels; ++l) {
+         const uint32_t w_l = align_u32(anv_minify(extent->width, l), i);
+         const uint32_t h_l = align_u32(anv_minify(extent->height, l), j);
+         const uint32_t d_l = anv_minify(extent->depth, l);
+
+         const uint32_t max_layers_horiz = MIN(d_l, 1u << l);
+         const uint32_t max_layers_vert = align_u32(d_l, 1u << l) / (1u << l);
 
-      qpitch = h0 + h1 + 11 * j;
-      mt_width = MAX(w0, w1 + w2);
-      mt_height = array_size * qpitch;
+         mt_width = MAX(mt_width, w_l * max_layers_horiz);
+         mt_height += h_l * max_layers_vert;
+      }
+      break;
+   default:
+      unreachable(!"bad VkImageType");
    }
 
    assert(qpitch >= min_qpitch);
@@ -181,8 +225,10 @@ anv_image_make_surface(const struct anv_image_create_info *create_info,
     */
    assert(anv_is_aligned(qpitch, j));
 
-   const uint32_t stride = align_u32(mt_width * format_info->cpp,
-                                     tile_info->width);
+   uint32_t stride = align_u32(mt_width * format->bs, tile_info->width);
+   if (create_info->stride > 0)
+      stride = create_info->stride;
+
    const uint32_t size = stride * align_u32(mt_height, tile_info->height);
    const uint32_t offset = align_u32(*inout_image_size,
                                      tile_info->surface_alignment);
@@ -203,6 +249,26 @@ anv_image_make_surface(const struct anv_image_create_info *create_info,
    return VK_SUCCESS;
 }
 
+static VkImageUsageFlags
+anv_image_get_full_usage(const VkImageCreateInfo *info)
+{
+   VkImageUsageFlags usage = info->usage;
+
+   if (usage & VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT) {
+      /* Meta will transfer from the image by binding it as a texture. */
+      usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+   }
+
+   if (usage & VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT) {
+      /* Meta will transfer to the image by binding it as a color attachment,
+       * even if the image format is not a color format.
+       */
+      usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+   }
+
+   return usage;
+}
+
 VkResult
 anv_image_create(VkDevice _device,
                  const struct anv_image_create_info *create_info,
@@ -216,8 +282,6 @@ anv_image_create(VkDevice _device,
 
    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
 
-   /* XXX: We don't handle any of these */
-   anv_assert(pCreateInfo->imageType == VK_IMAGE_TYPE_2D);
    anv_assert(pCreateInfo->mipLevels > 0);
    anv_assert(pCreateInfo->arraySize > 0);
    anv_assert(pCreateInfo->samples == 1);
@@ -232,16 +296,10 @@ anv_image_create(VkDevice _device,
    const struct anv_surf_type_limits *limits =
       &anv_surf_type_limits[surf_type];
 
-   if (extent->width > limits->width ||
-       extent->height > limits->height ||
-       extent->depth > limits->depth) {
-      /* TODO(chadv): What is the correct error? */
-      anv_loge("image extent is too large");
-      return vk_error(VK_ERROR_INVALID_MEMORY_SIZE);
-   }
-
-   const struct anv_format *format_info =
-      anv_format_for_vk_format(pCreateInfo->format);
+   /* Errors should be caught by VkImageFormatProperties. */
+   assert(extent->width <= limits->width);
+   assert(extent->height <= limits->height);
+   assert(extent->depth <= limits->depth);
 
    image = anv_device_alloc(device, sizeof(*image), 8,
                             VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
@@ -251,36 +309,43 @@ anv_image_create(VkDevice _device,
    memset(image, 0, sizeof(*image));
    image->type = pCreateInfo->imageType;
    image->extent = pCreateInfo->extent;
-   image->format = pCreateInfo->format;
+   image->format = anv_format_for_vk_format(pCreateInfo->format);
    image->levels = pCreateInfo->mipLevels;
    image->array_size = pCreateInfo->arraySize;
-   image->surf_type = surf_type;
+   image->usage = anv_image_get_full_usage(pCreateInfo);
+   image->surface_type = surf_type;
 
-   if (likely(!format_info->has_stencil || format_info->depth_format)) {
-      /* The image's primary surface is a color or depth surface. */
-      r = anv_image_make_surface(create_info, &image->size, &image->alignment,
-                                 &image->primary_surface);
-      if (r != VK_SUCCESS)
-         goto fail;
+   if (image->usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
+                       VK_IMAGE_USAGE_STORAGE_BIT)) {
+      image->needs_nonrt_surface_state = true;
    }
 
-   if (format_info->has_stencil) {
-      /* From the GPU's perspective, the depth buffer and stencil buffer are
-       * separate buffers.  From Vulkan's perspective, though, depth and
-       * stencil reside in the same image.  To satisfy Vulkan and the GPU, we
-       * place the depth and stencil buffers in the same bo.
-       */
-      VkImageCreateInfo stencil_info = *pCreateInfo;
-      stencil_info.format = VK_FORMAT_S8_UINT;
-
-      r = anv_image_make_surface(
-            &(struct anv_image_create_info) {
-               .vk_info = &stencil_info,
-            },
-            &image->size, &image->alignment, &image->stencil_surface);
+   if (image->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
+      image->needs_color_rt_surface_state = true;
+   }
 
+   if (likely(anv_format_is_color(image->format))) {
+      r = anv_image_make_surface(create_info, image->format,
+                                 &image->size, &image->alignment,
+                                 &image->color_surface);
       if (r != VK_SUCCESS)
          goto fail;
+   } else {
+      if (image->format->depth_format) {
+         r = anv_image_make_surface(create_info, image->format,
+                                    &image->size, &image->alignment,
+                                    &image->depth_surface);
+         if (r != VK_SUCCESS)
+            goto fail;
+      }
+
+      if (image->format->has_stencil) {
+         r = anv_image_make_surface(create_info, anv_format_s8_uint,
+                                    &image->size, &image->alignment,
+                                    &image->stencil_surface);
+         if (r != VK_SUCCESS)
+            goto fail;
+      }
    }
 
    *pImage = anv_image_to_handle(image);
@@ -306,152 +371,63 @@ anv_CreateImage(VkDevice device,
       pImage);
 }
 
-VkResult
+void
 anv_DestroyImage(VkDevice _device, VkImage _image)
 {
    ANV_FROM_HANDLE(anv_device, device, _device);
 
    anv_device_free(device, anv_image_from_handle(_image));
+}
 
-   return VK_SUCCESS;
+static void
+anv_surface_get_subresource_layout(struct anv_image *image,
+                                   struct anv_surface *surface,
+                                   const VkImageSubresource *subresource,
+                                   VkSubresourceLayout *layout)
+{
+   /* If we are on a non-zero mip level or array slice, we need to
+    * calculate a real offset.
+    */
+   anv_assert(subresource->mipLevel == 0);
+   anv_assert(subresource->arrayLayer == 0);
+
+   layout->offset = surface->offset;
+   layout->rowPitch = surface->stride;
+   layout->depthPitch = surface->qpitch;
+
+   /* FINISHME: We really shouldn't be doing this calculation here */
+   if (image->array_size > 1)
+      layout->size = surface->qpitch * image->array_size;
+   else
+      layout->size = surface->stride * image->extent.height;
 }
 
 VkResult anv_GetImageSubresourceLayout(
     VkDevice                                    device,
-    VkImage                                     image,
+    VkImage                                     _image,
     const VkImageSubresource*                   pSubresource,
     VkSubresourceLayout*                        pLayout)
 {
-   stub_return(VK_UNSUPPORTED);
-}
-
-void
-anv_surface_view_fini(struct anv_device *device,
-                      struct anv_surface_view *view)
-{
-   anv_state_pool_free(&device->surface_state_pool, view->surface_state);
-}
-
-void
-anv_image_view_init(struct anv_image_view *iview,
-                    struct anv_device *device,
-                    const VkImageViewCreateInfo* pCreateInfo,
-                    struct anv_cmd_buffer *cmd_buffer)
-{
-   ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image);
-
-   const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange;
-   struct anv_surface_view *view = &iview->view;
-   struct anv_surface *surface;
+   ANV_FROM_HANDLE(anv_image, image, _image);
 
-   const struct anv_format *format_info =
-      anv_format_for_vk_format(pCreateInfo->format);
-
-   const struct anv_image_view_info *view_type_info
-      = &anv_image_view_info_table[pCreateInfo->viewType];
-
-   if (pCreateInfo->viewType != VK_IMAGE_VIEW_TYPE_2D)
-      anv_finishme("non-2D image views");
-
-   switch (pCreateInfo->subresourceRange.aspect) {
-   case VK_IMAGE_ASPECT_STENCIL:
-      anv_finishme("stencil image views");
-      abort();
+   switch (pSubresource->aspect) {
+   case VK_IMAGE_ASPECT_COLOR:
+      anv_surface_get_subresource_layout(image, &image->color_surface,
+                                         pSubresource, pLayout);
       break;
    case VK_IMAGE_ASPECT_DEPTH:
-   case VK_IMAGE_ASPECT_COLOR:
-      view->offset = image->offset;
-      surface = &image->primary_surface;
+      anv_surface_get_subresource_layout(image, &image->depth_surface,
+                                         pSubresource, pLayout);
       break;
-   default:
-      unreachable("");
+   case VK_IMAGE_ASPECT_STENCIL:
+      anv_surface_get_subresource_layout(image, &image->stencil_surface,
+                                         pSubresource, pLayout);
       break;
+   default:
+      return vk_error(VK_UNSUPPORTED);
    }
 
-   view->bo = image->bo;
-   view->offset = image->offset + surface->offset;
-   view->format = pCreateInfo->format;
-
-   iview->extent = (VkExtent3D) {
-      .width = anv_minify(image->extent.width, range->baseMipLevel),
-      .height = anv_minify(image->extent.height, range->baseMipLevel),
-      .depth = anv_minify(image->extent.depth, range->baseMipLevel),
-   };
-
-   uint32_t depth = 1;
-   if (range->arraySize > 1) {
-      depth = range->arraySize;
-   } else if (image->extent.depth > 1) {
-      depth = image->extent.depth;
-   }
-
-   static const uint32_t vk_to_gen_swizzle[] = {
-      [VK_CHANNEL_SWIZZLE_ZERO]                 = SCS_ZERO,
-      [VK_CHANNEL_SWIZZLE_ONE]                  = SCS_ONE,
-      [VK_CHANNEL_SWIZZLE_R]                    = SCS_RED,
-      [VK_CHANNEL_SWIZZLE_G]                    = SCS_GREEN,
-      [VK_CHANNEL_SWIZZLE_B]                    = SCS_BLUE,
-      [VK_CHANNEL_SWIZZLE_A]                    = SCS_ALPHA
-   };
-
-   struct GEN8_RENDER_SURFACE_STATE surface_state = {
-      .SurfaceType = view_type_info->surface_type,
-      .SurfaceArray = image->array_size > 1,
-      .SurfaceFormat = format_info->surface_format,
-      .SurfaceVerticalAlignment = anv_valign[surface->v_align],
-      .SurfaceHorizontalAlignment = anv_halign[surface->h_align],
-      .TileMode = surface->tile_mode,
-      .VerticalLineStride = 0,
-      .VerticalLineStrideOffset = 0,
-      .SamplerL2BypassModeDisable = true,
-      .RenderCacheReadWriteMode = WriteOnlyCache,
-      .MemoryObjectControlState = GEN8_MOCS,
-
-      /* The driver sets BaseMipLevel in SAMPLER_STATE, not here in
-       * RENDER_SURFACE_STATE. The Broadwell PRM says "it is illegal to have
-       * both Base Mip Level fields nonzero".
-       */
-      .BaseMipLevel = 0.0,
-
-      .SurfaceQPitch = surface->qpitch >> 2,
-      .Height = image->extent.height - 1,
-      .Width = image->extent.width - 1,
-      .Depth = depth - 1,
-      .SurfacePitch = surface->stride - 1,
-      .MinimumArrayElement = range->baseArraySlice,
-      .NumberofMultisamples = MULTISAMPLECOUNT_1,
-      .XOffset = 0,
-      .YOffset = 0,
-
-      /* For sampler surfaces, the hardware interprets field MIPCount/LOD as
-       * MIPCount.  The range of levels accessible by the sampler engine is
-       * [SurfaceMinLOD, SurfaceMinLOD + MIPCountLOD].
-       */
-      .MIPCountLOD = range->mipLevels - 1,
-      .SurfaceMinLOD = range->baseMipLevel,
-
-      .AuxiliarySurfaceMode = AUX_NONE,
-      .RedClearColor = 0,
-      .GreenClearColor = 0,
-      .BlueClearColor = 0,
-      .AlphaClearColor = 0,
-      .ShaderChannelSelectRed = vk_to_gen_swizzle[pCreateInfo->channels.r],
-      .ShaderChannelSelectGreen = vk_to_gen_swizzle[pCreateInfo->channels.g],
-      .ShaderChannelSelectBlue = vk_to_gen_swizzle[pCreateInfo->channels.b],
-      .ShaderChannelSelectAlpha = vk_to_gen_swizzle[pCreateInfo->channels.a],
-      .ResourceMinLOD = 0.0,
-      .SurfaceBaseAddress = { NULL, view->offset },
-   };
-
-   if (cmd_buffer) {
-      view->surface_state =
-         anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64);
-   } else {
-      view->surface_state =
-         anv_state_pool_alloc(&device->surface_state_pool, 64, 64);
-   }
-
-   GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state);
+   return VK_SUCCESS;
 }
 
 VkResult
@@ -463,7 +439,6 @@ anv_validate_CreateImageView(VkDevice _device,
    const VkImageSubresourceRange *subresource;
    const struct anv_image_view_info *view_info;
    const struct anv_format *view_format_info;
-   const struct anv_format *image_format_info;
 
    /* Validate structure type before dereferencing it. */
    assert(pCreateInfo);
@@ -478,7 +453,6 @@ anv_validate_CreateImageView(VkDevice _device,
    /* Validate format is in range before using it. */
    assert(pCreateInfo->format >= VK_FORMAT_BEGIN_RANGE);
    assert(pCreateInfo->format <= VK_FORMAT_END_RANGE);
-   image_format_info = anv_format_for_vk_format(image->format);
    view_format_info = anv_format_for_vk_format(pCreateInfo->format);
 
    /* Validate channel swizzles. */
@@ -492,46 +466,91 @@ anv_validate_CreateImageView(VkDevice _device,
    assert(pCreateInfo->channels.a <= VK_CHANNEL_SWIZZLE_END_RANGE);
 
    /* Validate subresource. */
-   assert(subresource->aspect >= VK_IMAGE_ASPECT_BEGIN_RANGE);
-   assert(subresource->aspect <= VK_IMAGE_ASPECT_END_RANGE);
+   assert(subresource->aspectMask != 0);
    assert(subresource->mipLevels > 0);
    assert(subresource->arraySize > 0);
    assert(subresource->baseMipLevel < image->levels);
    assert(subresource->baseMipLevel + subresource->mipLevels <= image->levels);
-   assert(subresource->baseArraySlice < image->array_size);
-   assert(subresource->baseArraySlice + subresource->arraySize <= image->array_size);
+   assert(subresource->baseArrayLayer < image->array_size);
+   assert(subresource->baseArrayLayer + subresource->arraySize <= image->array_size);
    assert(pView);
 
    if (view_info->is_cube) {
-      assert(subresource->baseArraySlice % 6 == 0);
+      assert(subresource->baseArrayLayer % 6 == 0);
       assert(subresource->arraySize % 6 == 0);
    }
 
+   const VkImageAspectFlags ds_flags = VK_IMAGE_ASPECT_DEPTH_BIT
+                                     | VK_IMAGE_ASPECT_STENCIL_BIT;
+
    /* Validate format. */
-   switch (subresource->aspect) {
-   case VK_IMAGE_ASPECT_COLOR:
-      assert(!image_format_info->depth_format);
-      assert(!image_format_info->has_stencil);
+   if (subresource->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
+      assert(subresource->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
+      assert(!image->format->depth_format);
+      assert(!image->format->has_stencil);
       assert(!view_format_info->depth_format);
       assert(!view_format_info->has_stencil);
-      assert(view_format_info->cpp == image_format_info->cpp);
+      assert(view_format_info->bs == image->format->bs);
+   } else if (subresource->aspectMask & ds_flags) {
+      assert((subresource->aspectMask & ~ds_flags) == 0);
+
+      if (subresource->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
+         assert(image->format->depth_format);
+         assert(view_format_info->depth_format);
+         assert(view_format_info->bs == image->format->bs);
+      }
+
+      if (subresource->aspectMask & VK_IMAGE_ASPECT_STENCIL) {
+         /* FINISHME: Is it legal to have an R8 view of S8? */
+         assert(image->format->has_stencil);
+         assert(view_format_info->has_stencil);
+      }
+   } else {
+      assert(!"bad VkImageSubresourceRange::aspectFlags");
+   }
+
+   return anv_CreateImageView(_device, pCreateInfo, pView);
+}
+
+void
+anv_image_view_init(struct anv_image_view *iview,
+                    struct anv_device *device,
+                    const VkImageViewCreateInfo* pCreateInfo,
+                    struct anv_cmd_buffer *cmd_buffer)
+{
+   ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image);
+   const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange;
+
+   assert(range->arraySize > 0);
+   assert(range->baseMipLevel < image->levels);
+   assert(image->usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
+                          VK_IMAGE_USAGE_STORAGE_BIT |
+                          VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+                          VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT));
+
+   switch (image->type) {
+   default:
+      unreachable("bad VkImageType");
+   case VK_IMAGE_TYPE_1D:
+   case VK_IMAGE_TYPE_2D:
+      assert(range->baseArrayLayer + range->arraySize - 1 <= image->array_size);
       break;
-   case VK_IMAGE_ASPECT_DEPTH:
-      assert(image_format_info->depth_format);
-      assert(view_format_info->depth_format);
-      assert(view_format_info->cpp == image_format_info->cpp);
+   case VK_IMAGE_TYPE_3D:
+      assert(range->baseArrayLayer + range->arraySize - 1
+             <= anv_minify(image->extent.depth, range->baseMipLevel));
       break;
-   case VK_IMAGE_ASPECT_STENCIL:
-      /* FINISHME: Is it legal to have an R8 view of S8? */
-      assert(image_format_info->has_stencil);
-      assert(view_format_info->has_stencil);
+   }
+
+   switch (device->info.gen) {
+   case 7:
+      gen7_image_view_init(iview, device, pCreateInfo, cmd_buffer);
       break;
-   default:
-      assert(!"bad VkImageAspect");
+   case 8:
+      gen8_image_view_init(iview, device, pCreateInfo, cmd_buffer);
       break;
+   default:
+      unreachable("unsupported gen\n");
    }
-
-   return anv_CreateImageView(_device, pCreateInfo, pView);
 }
 
 VkResult
@@ -554,192 +573,109 @@ anv_CreateImageView(VkDevice _device,
    return VK_SUCCESS;
 }
 
-VkResult
-anv_DestroyImageView(VkDevice _device, VkImageView _iview)
-{
-   ANV_FROM_HANDLE(anv_device, device, _device);
-   ANV_FROM_HANDLE(anv_image_view, iview, _iview);
-
-   anv_surface_view_fini(device, &iview->view);
-   anv_device_free(device, iview);
-
-   return VK_SUCCESS;
-}
-
-void
-anv_color_attachment_view_init(struct anv_color_attachment_view *aview,
-                               struct anv_device *device,
-                               const VkAttachmentViewCreateInfo* pCreateInfo,
-                               struct anv_cmd_buffer *cmd_buffer)
+static void
+anv_image_view_destroy(struct anv_device *device,
+                       struct anv_image_view *iview)
 {
-   ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image);
-   struct anv_surface_view *view = &aview->view;
-   struct anv_surface *surface = &image->primary_surface;
-   const struct anv_format *format_info =
-      anv_format_for_vk_format(pCreateInfo->format);
-
-   aview->base.attachment_type = ANV_ATTACHMENT_VIEW_TYPE_COLOR;
-
-   anv_assert(pCreateInfo->arraySize > 0);
-   anv_assert(pCreateInfo->mipLevel < image->levels);
-   anv_assert(pCreateInfo->baseArraySlice + pCreateInfo->arraySize <= image->array_size);
-
-   view->bo = image->bo;
-   view->offset = image->offset + surface->offset;
-   view->format = pCreateInfo->format;
-
-   aview->base.extent = (VkExtent3D) {
-      .width = anv_minify(image->extent.width, pCreateInfo->mipLevel),
-      .height = anv_minify(image->extent.height, pCreateInfo->mipLevel),
-      .depth = anv_minify(image->extent.depth, pCreateInfo->mipLevel),
-   };
-
-   uint32_t depth = 1;
-   if (pCreateInfo->arraySize > 1) {
-      depth = pCreateInfo->arraySize;
-   } else if (image->extent.depth > 1) {
-      depth = image->extent.depth;
+   if (iview->image->needs_color_rt_surface_state) {
+      anv_state_pool_free(&device->surface_state_pool,
+                          iview->color_rt_surface_state);
    }
 
-   if (cmd_buffer) {
-      view->surface_state =
-         anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64);
-   } else {
-      view->surface_state =
-         anv_state_pool_alloc(&device->surface_state_pool, 64, 64);
+   if (iview->image->needs_nonrt_surface_state) {
+      anv_state_pool_free(&device->surface_state_pool,
+                          iview->nonrt_surface_state);
    }
 
-   struct GEN8_RENDER_SURFACE_STATE surface_state = {
-      .SurfaceType = SURFTYPE_2D,
-      .SurfaceArray = image->array_size > 1,
-      .SurfaceFormat = format_info->surface_format,
-      .SurfaceVerticalAlignment = anv_valign[surface->v_align],
-      .SurfaceHorizontalAlignment = anv_halign[surface->h_align],
-      .TileMode = surface->tile_mode,
-      .VerticalLineStride = 0,
-      .VerticalLineStrideOffset = 0,
-      .SamplerL2BypassModeDisable = true,
-      .RenderCacheReadWriteMode = WriteOnlyCache,
-      .MemoryObjectControlState = GEN8_MOCS,
-
-      /* The driver sets BaseMipLevel in SAMPLER_STATE, not here in
-       * RENDER_SURFACE_STATE. The Broadwell PRM says "it is illegal to have
-       * both Base Mip Level fields nonzero".
-       */
-      .BaseMipLevel = 0.0,
-
-      .SurfaceQPitch = surface->qpitch >> 2,
-      .Height = image->extent.height - 1,
-      .Width = image->extent.width - 1,
-      .Depth = depth - 1,
-      .SurfacePitch = surface->stride - 1,
-      .MinimumArrayElement = pCreateInfo->baseArraySlice,
-      .NumberofMultisamples = MULTISAMPLECOUNT_1,
-      .XOffset = 0,
-      .YOffset = 0,
-
-      /* For render target surfaces, the hardware interprets field MIPCount/LOD as
-       * LOD. The Broadwell PRM says:
-       *
-       *    MIPCountLOD defines the LOD that will be rendered into.
-       *    SurfaceMinLOD is ignored.
-       */
-      .SurfaceMinLOD = 0,
-      .MIPCountLOD = pCreateInfo->mipLevel,
-
-      .AuxiliarySurfaceMode = AUX_NONE,
-      .RedClearColor = 0,
-      .GreenClearColor = 0,
-      .BlueClearColor = 0,
-      .AlphaClearColor = 0,
-      .ShaderChannelSelectRed = SCS_RED,
-      .ShaderChannelSelectGreen = SCS_GREEN,
-      .ShaderChannelSelectBlue = SCS_BLUE,
-      .ShaderChannelSelectAlpha = SCS_ALPHA,
-      .ResourceMinLOD = 0.0,
-      .SurfaceBaseAddress = { NULL, view->offset },
-   };
-
-   GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state);
-}
-
-static void
-anv_depth_stencil_view_init(struct anv_depth_stencil_view *view,
-                            const VkAttachmentViewCreateInfo *pCreateInfo)
-{
-   ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image);
-   struct anv_surface *depth_surface = &image->primary_surface;
-   struct anv_surface *stencil_surface = &image->stencil_surface;
-   const struct anv_format *format =
-      anv_format_for_vk_format(image->format);
-
-   view->base.attachment_type = ANV_ATTACHMENT_VIEW_TYPE_DEPTH_STENCIL;
-
-   /* XXX: We don't handle any of these */
-   anv_assert(pCreateInfo->mipLevel == 0);
-   anv_assert(pCreateInfo->baseArraySlice == 0);
-   anv_assert(pCreateInfo->arraySize == 1);
-
-   view->bo = image->bo;
-
-   view->depth_stride = depth_surface->stride;
-   view->depth_offset = image->offset + depth_surface->offset;
-   view->depth_format = format->depth_format;
-   view->depth_qpitch = 0; /* FINISHME: QPitch */
-
-   view->stencil_stride = stencil_surface->stride;
-   view->stencil_offset = image->offset + stencil_surface->offset;
-   view->stencil_qpitch = 0; /* FINISHME: QPitch */
+   anv_device_free(device, iview);
 }
 
-VkResult
-anv_CreateAttachmentView(VkDevice _device,
-                         const VkAttachmentViewCreateInfo *pCreateInfo,
-                         VkAttachmentView *pView)
+void
+anv_DestroyImageView(VkDevice _device, VkImageView _iview)
 {
    ANV_FROM_HANDLE(anv_device, device, _device);
+   ANV_FROM_HANDLE(anv_image_view, iview, _iview);
 
-   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO);
-
-   if (anv_is_vk_format_depth_or_stencil(pCreateInfo->format)) {
-      struct anv_depth_stencil_view *view =
-         anv_device_alloc(device, sizeof(*view), 8,
-                          VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
-      if (view == NULL)
-         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
-
-      anv_depth_stencil_view_init(view, pCreateInfo);
-
-      *pView = anv_attachment_view_to_handle(&view->base);
-   } else {
-      struct anv_color_attachment_view *view =
-         anv_device_alloc(device, sizeof(*view), 8,
-                          VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
-      if (view == NULL)
-         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
-
-      anv_color_attachment_view_init(view, device, pCreateInfo, NULL);
-
-      *pView = anv_attachment_view_to_handle(&view->base);
-   }
-
-   return VK_SUCCESS;
+   anv_image_view_destroy(device, iview);
 }
 
-VkResult
-anv_DestroyAttachmentView(VkDevice _device, VkAttachmentView _view)
+struct anv_surface *
+anv_image_get_surface_for_aspect_mask(struct anv_image *image, VkImageAspectFlags aspect_mask)
 {
-   ANV_FROM_HANDLE(anv_device, device, _device);
-   ANV_FROM_HANDLE(anv_attachment_view, view, _view);
-
-   if (view->attachment_type == ANV_ATTACHMENT_VIEW_TYPE_COLOR) {
-      struct anv_color_attachment_view *aview =
-         (struct anv_color_attachment_view *)view;
-
-      anv_surface_view_fini(device, &aview->view);
+   switch (aspect_mask) {
+   case VK_IMAGE_ASPECT_COLOR_BIT:
+      /* Dragons will eat you.
+       *
+       * Meta attaches all destination surfaces as color render targets. Guess
+       * what surface the Meta Dragons really want.
+       */
+      if (image->format->depth_format && image->format->has_stencil) {
+         anv_finishme("combined depth stencil formats");
+         return &image->depth_surface;
+      } else if (image->format->depth_format) {
+         return &image->depth_surface;
+      } else if (image->format->has_stencil) {
+         return &image->stencil_surface;
+      } else {
+         return &image->color_surface;
+      }
+      break;
+   case VK_IMAGE_ASPECT_DEPTH_BIT:
+      assert(image->format->depth_format);
+      return &image->depth_surface;
+   case VK_IMAGE_ASPECT_STENCIL_BIT:
+      assert(image->format->has_stencil);
+      return &image->stencil_surface;
+   case VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT:
+      if (image->format->depth_format && image->format->has_stencil) {
+         /* FINISHME: The Vulkan spec (git a511ba2) requires support for combined
+          * depth stencil formats. Specifically, it states:
+          *
+          *    At least one of ename:VK_FORMAT_D24_UNORM_S8_UINT or
+          *    ename:VK_FORMAT_D32_SFLOAT_S8_UINT must be supported.
+          */
+         anv_finishme("combined depthstencil aspect");
+         return &image->depth_surface;
+      } else if (image->format->depth_format) {
+         return &image->depth_surface;
+      } else if (image->format->has_stencil) {
+         return &image->stencil_surface;
+      }
+      /* fallthrough */
+    default:
+       unreachable("image does not have aspect");
+       return NULL;
    }
-
-   anv_device_free(device, view);
-
-   return VK_SUCCESS;
 }
+
+#if 0
+   VkImageAspectFlags aspect_mask = 0;
+   if (format->depth_format)
+      aspect_mask |= VK_IMAGE_ASPECT_DEPTH_BIT;
+   if (format->has_stencil)
+      aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
+   if (!aspect_mask)
+      aspect_mask |= VK_IMAGE_ASPECT_COLOR_BIT;
+
+   anv_image_view_init(iview, device,
+      &(VkImageViewCreateInfo) {
+         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+         .image = info->image,
+         .viewType = VK_IMAGE_VIEW_TYPE_2D,
+         .format = info->format,
+         .channels = {
+            .r = VK_CHANNEL_SWIZZLE_R,
+            .g = VK_CHANNEL_SWIZZLE_G,
+            .b = VK_CHANNEL_SWIZZLE_B,
+            .a = VK_CHANNEL_SWIZZLE_A,
+         },
+         .subresourceRange = {
+            .aspectMask = aspect_mask,
+            .baseMipLevel = info->mipLevel,
+            .mipLevels = 1,
+            .baseArrayLayer = info->baseArraySlice,
+            .arraySize = info->arraySize,
+         },
+      },
+      NULL);
+#endif