vk/image: Enable 2d single-sample color miptrees
authorChad Versace <chad.versace@intel.com>
Sat, 27 Jun 2015 04:27:54 +0000 (21:27 -0700)
committerChad Versace <chad.versace@intel.com>
Sat, 27 Jun 2015 05:11:15 +0000 (22:11 -0700)
What's been tested, for both image views and color attachment views:

    - VK_FORMAT_R8G8B8A8_UNORM
    - VK_IMAGE_VIEW_TYPE_2D
    - mipLevels: 1, 2
    - baseMipLevel: 0, 1
    - arraySize: 1, 2
    - baseArraySlice: 0, 1

What's known to be broken:

    - Depth and stencil miptrees. To fix this, anv_depth_stencil_view
      needs major rework.
    - VkImageViewType != 2D
    - MSAA

Fixes Crucible tests:

  func.miptree.view-2d.levels02.array01.*
  func.miptree.view-2d.levels01.array02.*
  func.miptree.view-2d.levels02.array02.*

src/vulkan/image.c
src/vulkan/private.h

index 4a42aecba4133fc81aa35c7f25e2d4e1271e2485..9930d90aa41a3a94ed1c8aaa22ab721e5a0788b9 100644 (file)
@@ -110,13 +110,19 @@ anv_image_choose_tile_mode(const struct anv_image_create_info *anv_info)
    }
 }
 
-static void
+static VkResult
 anv_image_make_surface(const struct anv_image_create_info *create_info,
                        uint64_t *inout_image_size,
                        uint32_t *inout_image_alignment,
                        struct anv_surface *out_surface)
 {
+   /* See RENDER_SURFACE_STATE.SurfaceQPitch */
+   static const uint16_t min_qpitch UNUSED = 0x4;
+   static const uint16_t max_qpitch UNUSED = 0x1ffc;
+
    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);
 
@@ -126,11 +132,47 @@ anv_image_make_surface(const struct anv_image_create_info *create_info,
    const struct anv_format *format_info =
       anv_format_for_vk_format(create_info->vk_info->format);
 
-   uint32_t stride = align_u32(extent->width * format_info->cpp,
-                               tile_info->width);
-   uint32_t size = stride * align_u32(extent->height, tile_info->height);
-   uint32_t offset = align_u32(*inout_image_size,
-                               tile_info->surface_alignment);
+   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;
+
+   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);
+
+      qpitch = h0 + h1 + 11 * j;
+      mt_width = MAX(w0, w1 + w2);
+      mt_height = array_size * qpitch;
+   }
+
+   assert(qpitch >= min_qpitch);
+   if (qpitch > max_qpitch) {
+      anv_loge("image qpitch > 0x%x\n", max_qpitch);
+      return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
+   }
+
+   /* From the Broadwell PRM, RENDER_SURFACE_STATE.SurfaceQpitch:
+    *
+    *   This field must be set an integer multiple of the Surface Vertical
+    *   Alignment.
+    */
+   assert(anv_is_aligned(qpitch, j));
+
+   const uint32_t stride = align_u32(mt_width * format_info->cpp,
+                                     tile_info->width);
+   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);
 
    *inout_image_size = offset + size;
    *inout_image_alignment = MAX(*inout_image_alignment,
@@ -140,11 +182,12 @@ anv_image_make_surface(const struct anv_image_create_info *create_info,
       .offset = offset,
       .stride = stride,
       .tile_mode = tile_mode,
-
-      /* FINISHME: Stop hardcoding miptree subimage alignment */
-      .h_align = 4,
-      .v_align = 4,
+      .qpitch = qpitch,
+      .h_align = i,
+      .v_align = j,
    };
+
+   return VK_SUCCESS;
 }
 
 VkResult
@@ -155,18 +198,19 @@ anv_image_create(VkDevice _device,
    struct anv_device *device = (struct anv_device *) _device;
    const VkImageCreateInfo *pCreateInfo = create_info->vk_info;
    const VkExtent3D *restrict extent = &pCreateInfo->extent;
-   struct anv_image *image;
+   struct anv_image *image = NULL;
+   VkResult r;
 
    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 == 1);
-   anv_assert(pCreateInfo->arraySize == 1);
+   anv_assert(pCreateInfo->mipLevels > 0);
+   anv_assert(pCreateInfo->arraySize > 0);
    anv_assert(pCreateInfo->samples == 1);
    anv_assert(pCreateInfo->extent.width > 0);
    anv_assert(pCreateInfo->extent.height > 0);
-   anv_assert(pCreateInfo->extent.depth == 1);
+   anv_assert(pCreateInfo->extent.depth > 0);
 
    /* TODO(chadv): How should we validate inputs? */
    const uint8_t surf_type =
@@ -195,12 +239,16 @@ anv_image_create(VkDevice _device,
    image->type = pCreateInfo->imageType;
    image->extent = pCreateInfo->extent;
    image->format = pCreateInfo->format;
+   image->levels = pCreateInfo->mipLevels;
+   image->array_size = pCreateInfo->arraySize;
    image->surf_type = surf_type;
 
    if (likely(!format_info->has_stencil || format_info->depth_format)) {
       /* The image's primary surface is a color or depth surface. */
-      anv_image_make_surface(create_info, &image->size, &image->alignment,
-                             &image->primary_surface);
+      r = anv_image_make_surface(create_info, &image->size, &image->alignment,
+                                 &image->primary_surface);
+      if (r != VK_SUCCESS)
+         goto fail;
    }
 
    if (format_info->has_stencil) {
@@ -212,16 +260,25 @@ anv_image_create(VkDevice _device,
       VkImageCreateInfo stencil_info = *pCreateInfo;
       stencil_info.format = VK_FORMAT_S8_UINT;
 
-      anv_image_make_surface(
-         &(struct anv_image_create_info) {
-            .vk_info = &stencil_info,
-         },
-         &image->size, &image->alignment, &image->stencil_surface);
+      r = anv_image_make_surface(
+            &(struct anv_image_create_info) {
+               .vk_info = &stencil_info,
+            },
+            &image->size, &image->alignment, &image->stencil_surface);
+
+      if (r != VK_SUCCESS)
+         goto fail;
    }
 
    *pImage = (VkImage) image;
 
    return VK_SUCCESS;
+
+fail:
+   if (image)
+      anv_device_free(device, image);
+
+   return r;
 }
 
 VkResult
@@ -268,20 +325,20 @@ anv_image_view_init(struct anv_surface_view *view,
                     const VkImageViewCreateInfo* pCreateInfo,
                     struct anv_cmd_buffer *cmd_buffer)
 {
+   const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange;
    struct anv_image *image = (struct anv_image *) pCreateInfo->image;
-   struct anv_surface *surface = NULL;
+   struct anv_surface *surface;
 
    const struct anv_format *format_info =
       anv_format_for_vk_format(pCreateInfo->format);
 
-   /* XXX: We don't handle any of these */
-   anv_assert(pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D);
-   anv_assert(pCreateInfo->subresourceRange.baseMipLevel == 0);
-   anv_assert(pCreateInfo->subresourceRange.mipLevels == 1);
-   anv_assert(pCreateInfo->subresourceRange.baseArraySlice == 0);
-   anv_assert(pCreateInfo->subresourceRange.arraySize == 1);
+   anv_assert(range->mipLevels > 0);
+   anv_assert(range->arraySize > 0);
+   anv_assert(range->baseMipLevel + range->mipLevels <= image->levels);
+   anv_assert(range->baseArraySlice + range->arraySize <= image->array_size);
 
-   view->bo = image->bo;
+   if (pCreateInfo->viewType != VK_IMAGE_VIEW_TYPE_2D)
+      anv_finishme("non-2D image views");
 
    switch (pCreateInfo->subresourceRange.aspect) {
    case VK_IMAGE_ASPECT_STENCIL:
@@ -298,10 +355,22 @@ anv_image_view_init(struct anv_surface_view *view,
       break;
    }
 
+   view->bo = image->bo;
    view->offset = image->offset + surface->offset;
+   view->format = pCreateInfo->format;
 
-   /* TODO: Miplevels */
-   view->extent = image->extent;
+   view->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,
@@ -314,7 +383,7 @@ anv_image_view_init(struct anv_surface_view *view,
 
    struct GEN8_RENDER_SURFACE_STATE surface_state = {
       .SurfaceType = anv_surf_type_from_image_view_type[pCreateInfo->viewType],
-      .SurfaceArray = false,
+      .SurfaceArray = image->array_size > 1,
       .SurfaceFormat = format_info->surface_format,
       .SurfaceVerticalAlignment = anv_valign[surface->v_align],
       .SurfaceHorizontalAlignment = anv_halign[surface->h_align],
@@ -324,18 +393,24 @@ anv_image_view_init(struct anv_surface_view *view,
       .SamplerL2BypassModeDisable = true,
       .RenderCacheReadWriteMode = WriteOnlyCache,
       .MemoryObjectControlState = GEN8_MOCS,
-      .BaseMipLevel = 0.0,
-      .SurfaceQPitch = 0,
+      .BaseMipLevel = (float) pCreateInfo->minLod,
+      .SurfaceQPitch = surface->qpitch >> 2,
       .Height = image->extent.height - 1,
       .Width = image->extent.width - 1,
-      .Depth = image->extent.depth - 1,
+      .Depth = depth - 1,
       .SurfacePitch = surface->stride - 1,
-      .MinimumArrayElement = 0,
+      .MinimumArrayElement = range->baseArraySlice,
       .NumberofMultisamples = MULTISAMPLECOUNT_1,
       .XOffset = 0,
       .YOffset = 0,
-      .SurfaceMinLOD = 0,
-      .MIPCountLOD = 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,
@@ -391,20 +466,33 @@ anv_color_attachment_view_init(struct anv_surface_view *view,
 {
    struct anv_image *image = (struct anv_image *) pCreateInfo->image;
    struct anv_surface *surface = &image->primary_surface;
-   const struct anv_format *format =
+   const struct anv_format *format_info =
       anv_format_for_vk_format(pCreateInfo->format);
 
-   /* XXX: We don't handle any of these */
-   anv_assert(pCreateInfo->mipLevel == 0);
-   anv_assert(pCreateInfo->baseArraySlice == 0);
-   anv_assert(pCreateInfo->arraySize == 1);
-   anv_assert(pCreateInfo->msaaResolveImage == 0);
+   anv_assert(pCreateInfo->arraySize > 0);
+   anv_assert(pCreateInfo->mipLevel < image->levels);
+   anv_assert(pCreateInfo->baseArraySlice + pCreateInfo->arraySize <= image->array_size);
+
+   if (pCreateInfo->msaaResolveImage)
+      anv_finishme("msaaResolveImage");
 
    view->bo = image->bo;
-   view->offset = image->offset;
-   view->extent = image->extent;
+   view->offset = image->offset + surface->offset;
    view->format = pCreateInfo->format;
 
+   view->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 (cmd_buffer)
       view->surface_state =
          anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64);
@@ -414,8 +502,8 @@ anv_color_attachment_view_init(struct anv_surface_view *view,
 
    struct GEN8_RENDER_SURFACE_STATE surface_state = {
       .SurfaceType = SURFTYPE_2D,
-      .SurfaceArray = false,
-      .SurfaceFormat = format->surface_format,
+      .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,
@@ -425,17 +513,25 @@ anv_color_attachment_view_init(struct anv_surface_view *view,
       .RenderCacheReadWriteMode = WriteOnlyCache,
       .MemoryObjectControlState = GEN8_MOCS,
       .BaseMipLevel = 0.0,
-      .SurfaceQPitch = 0,
+      .SurfaceQPitch = surface->qpitch >> 2,
       .Height = image->extent.height - 1,
       .Width = image->extent.width - 1,
-      .Depth = image->extent.depth - 1,
+      .Depth = depth - 1,
       .SurfacePitch = surface->stride - 1,
-      .MinimumArrayElement = 0,
+      .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 = 0,
+      .MIPCountLOD = pCreateInfo->mipLevel,
+
       .AuxiliarySurfaceMode = AUX_NONE,
       .RedClearColor = 0,
       .GreenClearColor = 0,
index 9a1d0a2c53a45da2284da3feec2fb4abdb1f0724..efb97391c56748e558eb8696383e72bfabf80a9a 100644 (file)
@@ -794,6 +794,7 @@ struct anv_surface {
    uint32_t offset;
 
    uint32_t stride; /**< RENDER_SURFACE_STATE.SurfacePitch */
+   uint16_t qpitch; /**< RENDER_SURFACE_STATE.QPitch */
 
    /**
     * \name Alignment of miptree images, in units of pixels.
@@ -814,6 +815,9 @@ struct anv_image {
    VkImageType type;
    VkExtent3D extent;
    VkFormat format;
+   uint32_t levels;
+   uint32_t array_size;
+
    VkDeviceSize size;
    uint32_t alignment;