hk: implement vkCmdClear*Image with fast-clears

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Mary Guillemard <mary.guillemard@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35662>
This commit is contained in:
Alyssa Rosenzweig 2025-01-30 11:31:37 -05:00 committed by Marge Bot
parent 7120f86035
commit 9cdf486f14
2 changed files with 101 additions and 139 deletions

View file

@ -4,6 +4,10 @@
* Copyright 2022-2023 Collabora Ltd. and Red Hat Inc.
* SPDX-License-Identifier: MIT
*/
#include "util/format/u_formats.h"
#include "util/macros.h"
#include "util/u_math.h"
#include "vulkan/vulkan_core.h"
#include "hk_cmd_buffer.h"
#include "layout.h"
@ -13,141 +17,113 @@
#include "hk_image_view.h"
#include "hk_physical_device.h"
#include "vk_format.h"
#include "vk_meta.h"
#include "libagx_dgc.h"
#include "libagx_shaders.h"
static VkImageViewType
render_view_type(VkImageType image_type, unsigned layer_count)
void
hk_clear_image(struct hk_cmd_buffer *cmd, struct hk_image *image,
enum pipe_format view_format, const uint32_t *clear_value,
const VkImageSubresourceRange *range, bool whole_3d)
{
switch (image_type) {
case VK_IMAGE_TYPE_1D:
return layer_count == 1 ? VK_IMAGE_VIEW_TYPE_1D
: VK_IMAGE_VIEW_TYPE_1D_ARRAY;
case VK_IMAGE_TYPE_2D:
return layer_count == 1 ? VK_IMAGE_VIEW_TYPE_2D
: VK_IMAGE_VIEW_TYPE_2D_ARRAY;
case VK_IMAGE_TYPE_3D:
return VK_IMAGE_VIEW_TYPE_3D;
default:
unreachable("Invalid image type");
const uint32_t level_count =
vk_image_subresource_level_count(&image->vk, range);
bool z = (range->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT);
bool s = (range->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT);
unsigned first_plane = (s && !z) ? 1 : 0;
unsigned last_plane = s ? 1 : 0;
if (image->plane_count == 1) {
first_plane = 0;
last_plane = 0;
}
}
static void
clear_image(struct hk_cmd_buffer *cmd, struct hk_image *image,
VkImageLayout image_layout, VkFormat format,
const VkClearValue *clear_value, uint32_t range_count,
const VkImageSubresourceRange *ranges)
{
struct hk_device *dev = hk_cmd_buffer_device(cmd);
ASSERTED VkResult result;
/* TODO: Use fast clear */
bool compressed = image->planes[0].layout.compressed;
perf_debug(cmd, "Image clear (%scompressed)", compressed ? "" : "un");
for (uint32_t r = 0; r < range_count; r++) {
const uint32_t level_count =
vk_image_subresource_level_count(&image->vk, &ranges[r]);
for (unsigned plane = first_plane; plane <= last_plane; ++plane) {
struct ail_layout *layout = &image->planes[plane].layout;
perf_debug(cmd, "Image clear (%scompressed)",
layout->compressed ? "" : "un");
for (uint32_t l = 0; l < level_count; l++) {
const uint32_t level = ranges[r].baseMipLevel + l;
const uint32_t level = range->baseMipLevel + l;
const VkExtent3D level_extent =
vk_image_mip_level_extent(&image->vk, level);
uint32_t base_array_layer, layer_count;
if (image->vk.image_type == VK_IMAGE_TYPE_3D) {
if (image->vk.image_type == VK_IMAGE_TYPE_3D && whole_3d) {
base_array_layer = 0;
layer_count = level_extent.depth;
} else {
base_array_layer = ranges[r].baseArrayLayer;
layer_count =
vk_image_subresource_layer_count(&image->vk, &ranges[r]);
base_array_layer = range->baseArrayLayer;
layer_count = vk_image_subresource_layer_count(&image->vk, range);
}
const VkImageViewUsageCreateInfo view_usage_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.usage = (ranges[r].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
: VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
};
const VkImageViewCreateInfo view_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.flags = VK_IMAGE_VIEW_CREATE_DRIVER_INTERNAL_BIT_MESA,
.pNext = &view_usage_info,
.image = hk_image_to_handle(image),
.viewType = render_view_type(image->vk.image_type, layer_count),
.format = format,
.subresourceRange =
{
.aspectMask = image->vk.aspects,
.baseMipLevel = level,
.levelCount = 1,
.baseArrayLayer = base_array_layer,
.layerCount = layer_count,
},
};
enum pipe_format format = view_format ? view_format : layout->format;
bool stencil = format == PIPE_FORMAT_S8_UINT;
/* We use vk_meta_create_image_view here for lifetime managemnt */
VkImageView view;
result =
vk_meta_create_image_view(&cmd->vk, &dev->meta, &view_info, &view);
assert(result == VK_SUCCESS);
VkRenderingInfo render = {
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.renderArea =
{
.offset = {0, 0},
.extent = {level_extent.width, level_extent.height},
},
.layerCount = layer_count,
};
VkRenderingAttachmentInfo vk_att = {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.imageView = view,
.imageLayout = image_layout,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = *clear_value,
};
if (ranges[r].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
render.colorAttachmentCount = 1;
render.pColorAttachments = &vk_att;
if (stencil) {
format = PIPE_FORMAT_R8_UINT;
} else if (format == PIPE_FORMAT_Z16_UNORM) {
format = PIPE_FORMAT_R16_UNORM;
} else if (format == PIPE_FORMAT_Z32_FLOAT) {
format = PIPE_FORMAT_R32_FLOAT;
}
if (ranges[r].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
render.pDepthAttachment = &vk_att;
if (ranges[r].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
render.pStencilAttachment = &vk_att;
hk_CmdBeginRendering(hk_cmd_buffer_to_handle(cmd), &render);
hk_CmdEndRendering(hk_cmd_buffer_to_handle(cmd));
uint32_t c[4];
util_format_pack_rgba(format, c, &clear_value[stencil ? 1 : 0], 1);
unsigned blocksize_B = util_format_get_blocksize(format);
assert(util_is_power_of_two_nonzero(blocksize_B) && blocksize_B <= 16);
/* Splat out to 128-bit */
uint8_t *bytes = (uint8_t *)c;
for (unsigned i = 1; i < 16; ++i) {
bytes[i] = bytes[i % blocksize_B];
}
uint64_t address =
image->planes[plane].addr +
ail_get_layer_level_B(layout, base_array_layer, level);
uint32_t size = ail_get_level_size_B(layout, level);
assert((layout->layer_stride_B % 16) == 0 && "aligned");
uint32_t layer_stride_uint4 = layout->layer_stride_B / 16;
if (ail_is_level_logically_compressed(layout, level)) {
assert((layout->compression_layer_stride_B % 16) == 0 && "aligned");
uint32_t meta_layer_stride_tl =
layout->compression_layer_stride_B / 8;
uint64_t meta_addr =
image->planes[plane].addr + layout->metadata_offset_B +
(base_array_layer * layout->compression_layer_stride_B) +
layout->level_offsets_compressed_B[level];
uint32_t word = (uint32_t)ail_tile_mode_solid(format);
struct agx_grid grid =
agx_3d(ail_metadata_width_tl(layout, level),
ail_metadata_height_tl(layout, level), layer_count);
struct ail_tile tilesize = layout->tilesize_el[level];
libagx_fast_clear(cmd, grid, AGX_BARRIER_ALL, meta_addr, address,
grid.count[0], grid.count[1], tilesize.width_el,
tilesize.height_el, meta_layer_stride_tl,
layer_stride_uint4, util_logbase2(blocksize_B),
util_logbase2(layout->sample_count_sa), c[0],
c[1], c[2], c[3], word);
} else {
libagx_fill_uint4(cmd, agx_2d(DIV_ROUND_UP(size, 16), layer_count),
AGX_BARRIER_ALL, address, layer_stride_uint4,
c[0], c[1], c[2], c[3]);
}
}
}
}
static VkFormat
vk_packed_int_format_for_size(unsigned size_B)
{
switch (size_B) {
case 1:
return VK_FORMAT_R8_UINT;
case 2:
return VK_FORMAT_R16_UINT;
case 4:
return VK_FORMAT_R32_UINT;
case 8:
return VK_FORMAT_R32G32_UINT;
case 16:
return VK_FORMAT_R32G32B32A32_UINT;
default:
unreachable("Invalid image format size");
}
}
VKAPI_ATTR void VKAPI_CALL
hk_CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage _image,
VkImageLayout imageLayout,
@ -157,28 +133,10 @@ hk_CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage _image,
VK_FROM_HANDLE(hk_cmd_buffer, cmd, commandBuffer);
VK_FROM_HANDLE(hk_image, image, _image);
VkClearValue clear_value = {
.color = *pColor,
};
VkFormat vk_format = image->vk.format;
if (vk_format == VK_FORMAT_R64_UINT || vk_format == VK_FORMAT_R64_SINT)
vk_format = VK_FORMAT_R32G32_UINT;
enum pipe_format p_format = hk_format_to_pipe_format(vk_format);
assert(p_format != PIPE_FORMAT_NONE);
if (!ail_pixel_format[p_format].renderable) {
memset(&clear_value, 0, sizeof(clear_value));
util_format_pack_rgba(p_format, clear_value.color.uint32, pColor->uint32,
1);
unsigned bpp = util_format_get_blocksize(p_format);
vk_format = vk_packed_int_format_for_size(bpp);
for (uint32_t r = 0; r < rangeCount; r++) {
hk_clear_image(cmd, image, PIPE_FORMAT_NONE, pColor->uint32, &pRanges[r],
true /* whole 3D */);
}
clear_image(cmd, image, imageLayout, vk_format, &clear_value, rangeCount,
pRanges);
}
VKAPI_ATTR void VKAPI_CALL
@ -191,10 +149,9 @@ hk_CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage _image,
VK_FROM_HANDLE(hk_cmd_buffer, cmd, commandBuffer);
VK_FROM_HANDLE(hk_image, image, _image);
const VkClearValue clear_value = {
.depthStencil = *pDepthStencil,
};
clear_image(cmd, image, imageLayout, image->vk.format, &clear_value,
rangeCount, pRanges);
for (uint32_t r = 0; r < rangeCount; r++) {
uint32_t colour[4] = {fui(pDepthStencil->depth), pDepthStencil->stencil};
hk_clear_image(cmd, image, PIPE_FORMAT_NONE, colour, &pRanges[r],
true /* whole 3D */);
}
}

View file

@ -135,3 +135,8 @@ hk_image_aspects_to_plane(const struct hk_image *image,
struct agx_device;
bool hk_can_compress_format(const struct agx_device *dev, VkFormat format);
struct hk_cmd_buffer;
void hk_clear_image(struct hk_cmd_buffer *cmd, struct hk_image *image,
enum pipe_format view_format, const uint32_t *clear_value,
const VkImageSubresourceRange *range, bool whole_3d);