From 5b3a1ceb83a2a47a4fcde38688d26e008ddda0eb Mon Sep 17 00:00:00 2001 From: Chad Versace Date: Fri, 26 Jun 2015 21:27:54 -0700 Subject: [PATCH] vk/image: Enable 2d single-sample color miptrees 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 | 200 ++++++++++++++++++++++++++++++++----------- src/vulkan/private.h | 4 + 2 files changed, 152 insertions(+), 52 deletions(-) diff --git a/src/vulkan/image.c b/src/vulkan/image.c index 4a42aecba41..9930d90aa41 100644 --- a/src/vulkan/image.c +++ b/src/vulkan/image.c @@ -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, diff --git a/src/vulkan/private.h b/src/vulkan/private.h index 9a1d0a2c53a..efb97391c56 100644 --- a/src/vulkan/private.h +++ b/src/vulkan/private.h @@ -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; -- 2.30.2