mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-27 01:28:12 +02:00
Needed for maintenance5. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com> Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34648>
616 lines
23 KiB
C
616 lines
23 KiB
C
/*
|
|
* Copyright © 2021 Collabora Ltd.
|
|
*
|
|
* Derived from tu_image.c which is:
|
|
* Copyright © 2016 Red Hat.
|
|
* Copyright © 2016 Bas Nieuwenhuizen
|
|
* Copyright © 2015 Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "pan_props.h"
|
|
|
|
#include "panvk_device.h"
|
|
#include "panvk_device_memory.h"
|
|
#include "panvk_entrypoints.h"
|
|
#include "panvk_image.h"
|
|
#include "panvk_instance.h"
|
|
#include "panvk_physical_device.h"
|
|
|
|
#include "drm-uapi/drm_fourcc.h"
|
|
#include "util/u_atomic.h"
|
|
#include "util/u_debug.h"
|
|
#include "util/u_drm.h"
|
|
|
|
#include "vk_format.h"
|
|
#include "vk_log.h"
|
|
#include "vk_object.h"
|
|
#include "vk_util.h"
|
|
|
|
static bool
|
|
panvk_image_can_use_mod(struct panvk_image *image, uint64_t mod)
|
|
{
|
|
struct panvk_physical_device *phys_dev =
|
|
to_panvk_physical_device(image->vk.base.device->physical);
|
|
unsigned arch = pan_arch(phys_dev->kmod.props.gpu_prod_id);
|
|
struct panvk_instance *instance =
|
|
to_panvk_instance(image->vk.base.device->physical->instance);
|
|
enum pipe_format pfmt = vk_format_to_pipe_format(image->vk.format);
|
|
bool forced_linear = (instance->debug_flags & PANVK_DEBUG_LINEAR) ||
|
|
image->vk.tiling == VK_IMAGE_TILING_LINEAR ||
|
|
image->vk.image_type == VK_IMAGE_TYPE_1D;
|
|
|
|
/* If the image is meant to be linear, don't bother testing the
|
|
* other cases. */
|
|
if (forced_linear)
|
|
return mod == DRM_FORMAT_MOD_LINEAR;
|
|
|
|
if (drm_is_afbc(mod)) {
|
|
/* Disallow AFBC if either of these is true
|
|
* - PANVK_DEBUG does not have the 'afbc' flag set
|
|
* - storage image views are requested
|
|
* - this is a multisample image
|
|
* - the GPU doesn't support AFBC
|
|
* - the format is not AFBC-able
|
|
* - tiling is set to linear
|
|
* - this is a 1D image
|
|
* - this is a 3D image on a pre-v7 GPU
|
|
* - this is a mutable format image on v7
|
|
*/
|
|
if (!(instance->debug_flags & PANVK_DEBUG_AFBC) ||
|
|
((image->vk.usage | image->vk.stencil_usage) &
|
|
VK_IMAGE_USAGE_STORAGE_BIT) ||
|
|
image->vk.samples > 1 ||
|
|
!panfrost_query_afbc(&phys_dev->kmod.props) ||
|
|
!panfrost_format_supports_afbc(arch, pfmt) ||
|
|
image->vk.tiling == VK_IMAGE_TILING_LINEAR ||
|
|
image->vk.image_type == VK_IMAGE_TYPE_1D ||
|
|
(image->vk.image_type == VK_IMAGE_TYPE_3D && arch < 7) ||
|
|
((image->vk.create_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) &&
|
|
arch == 7))
|
|
return false;
|
|
|
|
const struct util_format_description *fdesc =
|
|
util_format_description(pfmt);
|
|
bool is_rgb = fdesc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
|
|
fdesc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB;
|
|
|
|
if ((mod & AFBC_FORMAT_MOD_YTR) && (!is_rgb || fdesc->nr_channels >= 3))
|
|
return false;
|
|
|
|
/* We assume all other unsupported AFBC modes have been filtered out
|
|
* through pan_best_modifiers[]. */
|
|
return true;
|
|
}
|
|
|
|
if (mod == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
|
|
/* Multiplanar YUV with U-interleaving isn't supported by the HW. We
|
|
* also need to make sure images that can be aliased to planes of
|
|
* multi-planar images remain compatible with the aliased images, so
|
|
* don't allow U-interleaving for those either.
|
|
*/
|
|
if (vk_format_get_plane_count(image->vk.format) > 1 ||
|
|
vk_image_can_be_aliased_to_yuv_plane(&image->vk))
|
|
return false;
|
|
|
|
/* If we're dealing with a compressed format that requires non-compressed
|
|
* views we can't use U_INTERLEAVED tiling because the tiling is different
|
|
* between compressed and non-compressed formats. If we wanted to support
|
|
* format re-interpretation we would have to specialize the shaders
|
|
* accessing non-compressed image views (coordinate patching for
|
|
* sampled/storage image, frag_coord patching for color attachments). Let's
|
|
* keep things simple for now and make all compressed images that
|
|
* have VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT set linear. */
|
|
return !(image->vk.create_flags &
|
|
VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT);
|
|
}
|
|
|
|
/* If we get there, it must be linear to be supported. */
|
|
return mod == DRM_FORMAT_MOD_LINEAR;
|
|
}
|
|
|
|
static uint64_t
|
|
panvk_image_get_explicit_mod(
|
|
struct panvk_image *image,
|
|
const VkImageDrmFormatModifierExplicitCreateInfoEXT *explicit)
|
|
{
|
|
uint64_t mod = explicit->drmFormatModifier;
|
|
|
|
assert(!vk_format_is_depth_or_stencil(image->vk.format));
|
|
assert(image->vk.samples == 1);
|
|
assert(image->vk.array_layers == 1);
|
|
assert(image->vk.image_type != VK_IMAGE_TYPE_3D);
|
|
assert(explicit->drmFormatModifierPlaneCount == 1);
|
|
assert(panvk_image_can_use_mod(image, mod));
|
|
|
|
return mod;
|
|
}
|
|
|
|
static uint64_t
|
|
panvk_image_get_mod_from_list(struct panvk_image *image,
|
|
const uint64_t *mods, uint32_t mod_count)
|
|
{
|
|
for (unsigned i = 0; i < PAN_MODIFIER_COUNT; ++i) {
|
|
if (!panvk_image_can_use_mod(image, pan_best_modifiers[i]))
|
|
continue;
|
|
|
|
if (!mod_count ||
|
|
drm_find_modifier(pan_best_modifiers[i], mods, mod_count))
|
|
return pan_best_modifiers[i];
|
|
}
|
|
|
|
/* If we reached that point without finding a proper modifier, there's
|
|
* a serious issue. */
|
|
assert(!"Invalid modifier");
|
|
return DRM_FORMAT_MOD_INVALID;
|
|
}
|
|
|
|
static uint64_t
|
|
panvk_image_get_mod(struct panvk_image *image,
|
|
const VkImageCreateInfo *pCreateInfo)
|
|
{
|
|
if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
|
|
const VkImageDrmFormatModifierListCreateInfoEXT *mod_list =
|
|
vk_find_struct_const(pCreateInfo->pNext,
|
|
IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
|
|
const VkImageDrmFormatModifierExplicitCreateInfoEXT *explicit_mod =
|
|
vk_find_struct_const(
|
|
pCreateInfo->pNext,
|
|
IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
|
|
|
|
if (explicit_mod)
|
|
return panvk_image_get_explicit_mod(image, explicit_mod);
|
|
|
|
if (mod_list)
|
|
return panvk_image_get_mod_from_list(image,
|
|
mod_list->pDrmFormatModifiers,
|
|
mod_list->drmFormatModifierCount);
|
|
|
|
assert(!"Missing modifier info");
|
|
}
|
|
|
|
return panvk_image_get_mod_from_list(image, NULL, 0);
|
|
}
|
|
|
|
static enum mali_texture_dimension
|
|
panvk_image_type_to_mali_tex_dim(VkImageType type)
|
|
{
|
|
switch (type) {
|
|
case VK_IMAGE_TYPE_1D:
|
|
return MALI_TEXTURE_DIMENSION_1D;
|
|
case VK_IMAGE_TYPE_2D:
|
|
return MALI_TEXTURE_DIMENSION_2D;
|
|
case VK_IMAGE_TYPE_3D:
|
|
return MALI_TEXTURE_DIMENSION_3D;
|
|
default:
|
|
unreachable("Invalid image type");
|
|
}
|
|
}
|
|
|
|
static void
|
|
panvk_image_init_layouts(struct panvk_image *image,
|
|
const VkImageCreateInfo *pCreateInfo)
|
|
{
|
|
struct panvk_physical_device *phys_dev =
|
|
to_panvk_physical_device(image->vk.base.device->physical);
|
|
unsigned arch = pan_arch(phys_dev->kmod.props.gpu_prod_id);
|
|
const VkImageDrmFormatModifierExplicitCreateInfoEXT *explicit_info =
|
|
vk_find_struct_const(
|
|
pCreateInfo->pNext,
|
|
IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
|
|
|
|
image->plane_count = vk_format_get_plane_count(pCreateInfo->format);
|
|
|
|
/* Z32_S8X24 is not supported on v9+, and we don't want to use it
|
|
* on v7- anyway, because it's less efficient than the multiplanar
|
|
* alternative.
|
|
*/
|
|
if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT)
|
|
image->plane_count = 2;
|
|
|
|
for (uint8_t plane = 0; plane < image->plane_count; plane++) {
|
|
VkFormat format;
|
|
|
|
if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT)
|
|
format = plane == 0 ? VK_FORMAT_D32_SFLOAT : VK_FORMAT_S8_UINT;
|
|
else
|
|
format = vk_format_get_plane_format(image->vk.format, plane);
|
|
|
|
struct pan_image_explicit_layout plane_layout;
|
|
if (explicit_info)
|
|
plane_layout = (struct pan_image_explicit_layout){
|
|
.offset = explicit_info->pPlaneLayouts[plane].offset,
|
|
.row_stride = explicit_info->pPlaneLayouts[plane].rowPitch,
|
|
};
|
|
|
|
image->planes[plane].layout = (struct pan_image_layout){
|
|
.format = vk_format_to_pipe_format(format),
|
|
.dim = panvk_image_type_to_mali_tex_dim(image->vk.image_type),
|
|
.width = vk_format_get_plane_width(image->vk.format, plane,
|
|
image->vk.extent.width),
|
|
.height = vk_format_get_plane_height(image->vk.format, plane,
|
|
image->vk.extent.height),
|
|
.depth = image->vk.extent.depth,
|
|
.array_size = image->vk.array_layers,
|
|
.nr_samples = image->vk.samples,
|
|
.nr_slices = image->vk.mip_levels,
|
|
};
|
|
|
|
image->planes[plane].layout.modifier = image->vk.drm_format_mod;
|
|
pan_image_layout_init(arch, &image->planes[plane].layout,
|
|
explicit_info ? &plane_layout : NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
panvk_image_pre_mod_select_meta_adjustments(struct panvk_image *image)
|
|
{
|
|
const VkImageAspectFlags aspects = vk_format_aspects(image->vk.format);
|
|
const VkImageUsageFlags all_usage =
|
|
image->vk.usage | image->vk.stencil_usage;
|
|
|
|
/* We do image blit/resolve with vk_meta, so when an image is flagged as
|
|
* being a potential transfer source, we also need to add the sampled usage.
|
|
*/
|
|
if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
|
|
image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
if (image->vk.stencil_usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
|
|
image->vk.stencil_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
|
|
/* Similarly, image that can be a transfer destination can be attached
|
|
* as a color or depth-stencil attachment by vk_meta. */
|
|
if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
|
|
if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
|
|
image->vk.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
|
|
|
if (aspects & VK_IMAGE_ASPECT_COLOR_BIT) {
|
|
image->vk.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
image->vk.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
|
}
|
|
}
|
|
|
|
if (image->vk.stencil_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
|
|
image->vk.stencil_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
|
|
|
/* vk_meta creates 2D array views of 3D images. */
|
|
if (all_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT &&
|
|
image->vk.image_type == VK_IMAGE_TYPE_3D)
|
|
image->vk.create_flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
|
|
|
|
/* Needed for resolve operations. */
|
|
if (image->vk.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
|
image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
|
|
if (image->vk.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT &&
|
|
aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
|
|
image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
|
|
if (image->vk.stencil_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
|
image->vk.stencil_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
|
|
if ((image->vk.usage &
|
|
(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) &&
|
|
vk_format_is_compressed(image->vk.format)) {
|
|
/* We need to be able to create RGBA views of compressed formats for
|
|
* vk_meta copies. */
|
|
image->vk.create_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT |
|
|
VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
|
|
}
|
|
}
|
|
|
|
static uint64_t
|
|
panvk_image_get_total_size(const struct panvk_image *image)
|
|
{
|
|
uint64_t size = 0;
|
|
for (uint8_t plane = 0; plane < image->plane_count; plane++)
|
|
size += image->planes[plane].layout.data_size;
|
|
return size;
|
|
}
|
|
|
|
static bool
|
|
is_disjoint(const struct panvk_image *image)
|
|
{
|
|
assert((image->plane_count > 1 &&
|
|
image->vk.format != VK_FORMAT_D32_SFLOAT_S8_UINT) ||
|
|
(image->vk.create_flags & VK_IMAGE_CREATE_ALIAS_BIT) ||
|
|
!(image->vk.create_flags & VK_IMAGE_CREATE_DISJOINT_BIT));
|
|
return image->vk.create_flags & VK_IMAGE_CREATE_DISJOINT_BIT;
|
|
}
|
|
|
|
static void
|
|
panvk_image_init(struct panvk_image *image,
|
|
const VkImageCreateInfo *pCreateInfo)
|
|
{
|
|
/* Add any create/usage flags that might be needed for meta operations.
|
|
* This is run before the modifier selection because some
|
|
* usage/create_flags influence the modifier selection logic. */
|
|
panvk_image_pre_mod_select_meta_adjustments(image);
|
|
|
|
/* Now that we've patched the create/usage flags, we can proceed with the
|
|
* modifier selection. */
|
|
image->vk.drm_format_mod = panvk_image_get_mod(image, pCreateInfo);
|
|
panvk_image_init_layouts(image, pCreateInfo);
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL
|
|
panvk_CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator, VkImage *pImage)
|
|
{
|
|
VK_FROM_HANDLE(panvk_device, dev, device);
|
|
struct panvk_physical_device *phys_dev =
|
|
to_panvk_physical_device(dev->vk.physical);
|
|
|
|
const VkImageSwapchainCreateInfoKHR *swapchain_info =
|
|
vk_find_struct_const(pCreateInfo->pNext, IMAGE_SWAPCHAIN_CREATE_INFO_KHR);
|
|
if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) {
|
|
return wsi_common_create_swapchain_image(&phys_dev->wsi_device,
|
|
pCreateInfo,
|
|
swapchain_info->swapchain,
|
|
pImage);
|
|
}
|
|
|
|
struct panvk_image *image =
|
|
vk_image_create(&dev->vk, pCreateInfo, pAllocator, sizeof(*image));
|
|
if (!image)
|
|
return panvk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
panvk_image_init(image, pCreateInfo);
|
|
|
|
/*
|
|
* From the Vulkan spec:
|
|
*
|
|
* If the size of the resultant image would exceed maxResourceSize, then
|
|
* vkCreateImage must fail and return VK_ERROR_OUT_OF_DEVICE_MEMORY.
|
|
*/
|
|
if (panvk_image_get_total_size(image) > UINT32_MAX) {
|
|
vk_image_destroy(&dev->vk, pAllocator, &image->vk);
|
|
return panvk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
|
}
|
|
|
|
*pImage = panvk_image_to_handle(image);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
panvk_DestroyImage(VkDevice _device, VkImage _image,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
VK_FROM_HANDLE(panvk_device, device, _device);
|
|
VK_FROM_HANDLE(panvk_image, image, _image);
|
|
|
|
if (!image)
|
|
return;
|
|
|
|
if (image->bo)
|
|
pan_kmod_bo_put(image->bo);
|
|
|
|
vk_image_destroy(&device->vk, pAllocator, &image->vk);
|
|
}
|
|
|
|
static void
|
|
get_image_subresource_layout(const struct panvk_image *image,
|
|
const VkImageSubresource2 *subres2,
|
|
VkSubresourceLayout2 *layout2)
|
|
{
|
|
const VkImageSubresource *subres = &subres2->imageSubresource;
|
|
VkSubresourceLayout *layout = &layout2->subresourceLayout;
|
|
unsigned plane = panvk_plane_index(image->vk.format, subres->aspectMask);
|
|
assert(plane < PANVK_MAX_PLANES);
|
|
|
|
const struct pan_image_slice_layout *slice_layout =
|
|
&image->planes[plane].layout.slices[subres->mipLevel];
|
|
|
|
uint64_t base_offset = 0;
|
|
if (!is_disjoint(image)) {
|
|
for (uint8_t plane_idx = 0; plane_idx < plane; plane_idx++)
|
|
base_offset += image->planes[plane_idx].layout.data_size;
|
|
}
|
|
|
|
layout->offset = base_offset +
|
|
slice_layout->offset + (subres->arrayLayer *
|
|
image->planes[plane].layout.array_stride);
|
|
layout->size = slice_layout->size;
|
|
layout->rowPitch = slice_layout->row_stride;
|
|
layout->arrayPitch = image->planes[plane].layout.array_stride;
|
|
layout->depthPitch = slice_layout->surface_stride;
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
panvk_GetImageSubresourceLayout2(VkDevice device, VkImage image,
|
|
const VkImageSubresource2 *pSubresource,
|
|
VkSubresourceLayout2 *pLayout)
|
|
{
|
|
VK_FROM_HANDLE(panvk_image, img, image);
|
|
|
|
get_image_subresource_layout(img, pSubresource, pLayout);
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
panvk_GetDeviceImageSubresourceLayoutKHR(
|
|
VkDevice device, const VkDeviceImageSubresourceInfoKHR *pInfo,
|
|
VkSubresourceLayout2KHR *pLayout)
|
|
{
|
|
VK_FROM_HANDLE(panvk_device, dev, device);
|
|
struct panvk_image image = {0};
|
|
|
|
vk_image_init(&dev->vk, &image.vk, pInfo->pCreateInfo);
|
|
panvk_image_init(&image, pInfo->pCreateInfo);
|
|
get_image_subresource_layout(&image, pInfo->pSubresource, pLayout);
|
|
vk_image_finish(&image.vk);
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
panvk_GetImageMemoryRequirements2(VkDevice device,
|
|
const VkImageMemoryRequirementsInfo2 *pInfo,
|
|
VkMemoryRequirements2 *pMemoryRequirements)
|
|
{
|
|
VK_FROM_HANDLE(panvk_image, image, pInfo->image);
|
|
|
|
const uint64_t alignment = 4096;
|
|
const VkImagePlaneMemoryRequirementsInfo *plane_info =
|
|
vk_find_struct_const(pInfo->pNext, IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO);
|
|
const bool disjoint = is_disjoint(image);
|
|
const VkImageAspectFlags aspects =
|
|
plane_info ? plane_info->planeAspect : image->vk.aspects;
|
|
uint8_t plane = panvk_plane_index(image->vk.format, aspects);
|
|
const uint64_t size =
|
|
disjoint ? image->planes[plane].layout.data_size :
|
|
panvk_image_get_total_size(image);
|
|
|
|
pMemoryRequirements->memoryRequirements.memoryTypeBits = 1;
|
|
pMemoryRequirements->memoryRequirements.alignment = alignment;
|
|
pMemoryRequirements->memoryRequirements.size = size;
|
|
|
|
vk_foreach_struct_const(ext, pMemoryRequirements->pNext) {
|
|
switch (ext->sType) {
|
|
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
|
|
VkMemoryDedicatedRequirements *dedicated = (void *)ext;
|
|
dedicated->requiresDedicatedAllocation = false;
|
|
dedicated->prefersDedicatedAllocation = dedicated->requiresDedicatedAllocation;
|
|
break;
|
|
}
|
|
default:
|
|
vk_debug_ignored_stype(ext->sType);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
panvk_GetDeviceImageMemoryRequirements(VkDevice device,
|
|
const VkDeviceImageMemoryRequirements *pInfo,
|
|
VkMemoryRequirements2 *pMemoryRequirements)
|
|
{
|
|
VK_FROM_HANDLE(panvk_device, dev, device);
|
|
|
|
struct panvk_image image;
|
|
vk_image_init(&dev->vk, &image.vk, pInfo->pCreateInfo);
|
|
panvk_image_init(&image, pInfo->pCreateInfo);
|
|
|
|
VkImageMemoryRequirementsInfo2 info2 = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
|
|
.image = panvk_image_to_handle(&image),
|
|
};
|
|
panvk_GetImageMemoryRequirements2(device, &info2, pMemoryRequirements);
|
|
vk_image_finish(&image.vk);
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
panvk_GetImageSparseMemoryRequirements2(
|
|
VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo,
|
|
uint32_t *pSparseMemoryRequirementCount,
|
|
VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
|
|
{
|
|
/* Sparse images are not yet supported. */
|
|
*pSparseMemoryRequirementCount = 0;
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
panvk_GetDeviceImageSparseMemoryRequirements(VkDevice device,
|
|
const VkDeviceImageMemoryRequirements *pInfo,
|
|
uint32_t *pSparseMemoryRequirementCount,
|
|
VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
|
|
{
|
|
/* Sparse images are not yet supported. */
|
|
*pSparseMemoryRequirementCount = 0;
|
|
}
|
|
|
|
static void
|
|
panvk_image_plane_bind(struct pan_image *plane, struct pan_kmod_bo *bo,
|
|
uint64_t base, uint64_t offset)
|
|
{
|
|
plane->data.base = base;
|
|
plane->data.offset = offset;
|
|
/* Reset the AFBC headers */
|
|
if (drm_is_afbc(plane->layout.modifier)) {
|
|
/* Transient CPU mapping */
|
|
void *bo_base = pan_kmod_bo_mmap(bo, 0, pan_kmod_bo_size(bo),
|
|
PROT_WRITE, MAP_SHARED, NULL);
|
|
|
|
assert(bo_base != MAP_FAILED);
|
|
|
|
for (unsigned layer = 0; layer < plane->layout.array_size;
|
|
layer++) {
|
|
for (unsigned level = 0; level < plane->layout.nr_slices;
|
|
level++) {
|
|
void *header = bo_base + plane->data.offset +
|
|
(layer * plane->layout.array_stride) +
|
|
plane->layout.slices[level].offset;
|
|
memset(header, 0,
|
|
plane->layout.slices[level].afbc.header_size);
|
|
}
|
|
}
|
|
|
|
ASSERTED int ret = os_munmap(bo_base, pan_kmod_bo_size(bo));
|
|
assert(!ret);
|
|
}
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL
|
|
panvk_BindImageMemory2(VkDevice device, uint32_t bindInfoCount,
|
|
const VkBindImageMemoryInfo *pBindInfos)
|
|
{
|
|
const VkBindImageMemorySwapchainInfoKHR *swapchain_info =
|
|
vk_find_struct_const(pBindInfos->pNext, BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR);
|
|
|
|
for (uint32_t i = 0; i < bindInfoCount; ++i) {
|
|
VK_FROM_HANDLE(panvk_image, image, pBindInfos[i].image);
|
|
struct pan_kmod_bo *old_bo = image->bo;
|
|
|
|
if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) {
|
|
VkImage wsi_vk_image = wsi_common_get_image(swapchain_info->swapchain,
|
|
swapchain_info->imageIndex);
|
|
VK_FROM_HANDLE(panvk_image, wsi_image, wsi_vk_image);
|
|
|
|
assert(image->plane_count == 1);
|
|
assert(wsi_image->plane_count == 1);
|
|
|
|
image->bo = pan_kmod_bo_get(wsi_image->bo);
|
|
panvk_image_plane_bind(&image->planes[0], image->bo,
|
|
wsi_image->planes[0].data.base,
|
|
wsi_image->planes[0].data.offset);
|
|
} else {
|
|
VK_FROM_HANDLE(panvk_device_memory, mem, pBindInfos[i].memory);
|
|
assert(mem);
|
|
image->bo = pan_kmod_bo_get(mem->bo);
|
|
uint64_t offset = pBindInfos[i].memoryOffset;
|
|
if (is_disjoint(image)) {
|
|
const VkBindImagePlaneMemoryInfo *plane_info =
|
|
vk_find_struct_const(pBindInfos[i].pNext,
|
|
BIND_IMAGE_PLANE_MEMORY_INFO);
|
|
uint8_t plane =
|
|
panvk_plane_index(image->vk.format, plane_info->planeAspect);
|
|
panvk_image_plane_bind(&image->planes[plane], image->bo,
|
|
mem->addr.dev, offset);
|
|
} else {
|
|
for (unsigned plane = 0; plane < image->plane_count; plane++) {
|
|
panvk_image_plane_bind(&image->planes[plane], image->bo,
|
|
mem->addr.dev, offset);
|
|
offset += image->planes[plane].layout.data_size;
|
|
}
|
|
}
|
|
}
|
|
|
|
pan_kmod_bo_put(old_bo);
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|