pvr: preliminary EXT_image_drm_format_modifier support
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

Adds a trivial EXT_image_drm_format_modifier support that only handles
LINEAR modifier.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Acked-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38991>
This commit is contained in:
Icenowy Zheng 2025-12-20 00:05:21 +08:00 committed by Marge Bot
parent cf68dc570b
commit bed1576b14
6 changed files with 169 additions and 9 deletions

View file

@ -639,7 +639,7 @@ Khronos extensions that are not part of any Vulkan version:
VK_EXT_headless_surface DONE (anv, dzn, hasvk, hk, lvp, nvk, panvk, pvr, radv, tu, v3dv, vn)
VK_EXT_image_2d_view_of_3d DONE (anv, hasvk, hk, lvp, nvk, panvk, pvr, radv, tu, vn)
VK_EXT_image_compression_control DONE (anv/gfx12-, radv)
VK_EXT_image_drm_format_modifier DONE (anv, hasvk, hk, lvp, nvk, panvk, radv/gfx9+, tu, v3dv, vn)
VK_EXT_image_drm_format_modifier DONE (anv, hasvk, hk, lvp, nvk, panvk, pvr, radv/gfx9+, tu, v3dv, vn)
VK_EXT_image_sliced_view_of_3d DONE (anv, hk, lvp, nvk, radv/gfx10+, vn)
VK_EXT_image_view_min_lod DONE (anv, hasvk, hk, nvk, radv, tu, vn)
VK_EXT_index_type_uint8 DONE (anv, hasvk, hk, nvk, lvp, panvk, pvr, radv/gfx8+, tu, v3dv, vn)

View file

@ -1,3 +1,4 @@
VK_QCOM_image_processing on Turnip
VK_EXT_present_timing on RADV, NVK, Turnip, ANV, Honeykrisp, panvk
VK_KHR_sampler_ycbcr_conversion on pvr
VK_EXT_image_drm_format_modifier on pvr

View file

@ -27,6 +27,7 @@
#include <stdint.h>
#include <vulkan/vulkan.h>
#include "drm-uapi/drm_fourcc.h"
#include "hwdef/rogue_hw_utils.h"
#include "pvr_common.h"
@ -452,6 +453,62 @@ pvr_get_buffer_format_features2(struct pvr_physical_device *pdevice,
return flags;
}
static void pvr_get_drm_format_modifier_properties_list(
struct pvr_physical_device *pdevice,
VkFormat vk_format,
VkBaseOutStructure *ext)
{
assert(ext->sType == VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT ||
ext->sType == VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT);
/* The two top-level data structures are the same. It's only when
* you get to walking the actual list of modifier properties that
* they differ.
*/
VkDrmFormatModifierPropertiesListEXT *p = (void *)ext;
const VkFormatFeatureFlags2 linear_features =
pvr_get_image_format_features2(pdevice, vk_format, VK_IMAGE_TILING_LINEAR);
/* We support LINEAR only yet */
if (!linear_features) {
p->drmFormatModifierCount = 0;
return;
}
switch (ext->sType) {
case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: {
VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierPropertiesEXT, out,
p->pDrmFormatModifierProperties,
&p->drmFormatModifierCount);
vk_outarray_append_typed(VkDrmFormatModifierPropertiesEXT, &out, mp) {
mp->drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
mp->drmFormatModifierPlaneCount = 1;
mp->drmFormatModifierTilingFeatures =
vk_format_features2_to_features(linear_features);
}
break;
}
case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT: {
VkDrmFormatModifierPropertiesList2EXT *p2 = (void *)p;
VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierProperties2EXT, out,
p2->pDrmFormatModifierProperties,
&p2->drmFormatModifierCount);
vk_outarray_append_typed(VkDrmFormatModifierProperties2EXT, &out, mp) {
mp->drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
mp->drmFormatModifierPlaneCount = 1;
mp->drmFormatModifierTilingFeatures = linear_features;
}
break;
}
default:
UNREACHABLE("Invalid structure type for modifier properties");
}
}
void pvr_GetPhysicalDeviceFormatProperties2(
VkPhysicalDevice physicalDevice,
VkFormat format,
@ -481,6 +538,10 @@ void pvr_GetPhysicalDeviceFormatProperties2(
pFormatProperties3->bufferFeatures = buffer2;
break;
}
case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT:
case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT:
pvr_get_drm_format_modifier_properties_list(pdevice, format, ext);
break;
default:
vk_debug_ignored_stype(ext->sType);
break;
@ -534,6 +595,7 @@ pvr_get_image_format_properties(struct pvr_physical_device *pdevice,
VkFormatFeatureFlags2 tiling_features2;
VkImageUsageFlags usage =
info->usage | (stencil_usage_info ? stencil_usage_info->stencilUsage : 0);
VkImageTiling tiling = info->tiling;
VkResult result;
if (!pvr_format) {
@ -546,8 +608,22 @@ pvr_get_image_format_properties(struct pvr_physical_device *pdevice,
goto err_unsupported_format;
}
if (tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
const VkPhysicalDeviceImageDrmFormatModifierInfoEXT *drm_format_mod_info =
vk_find_struct_const(info->pNext,
PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT);
if (drm_format_mod_info &&
drm_format_mod_info->drmFormatModifier == DRM_FORMAT_MOD_LINEAR) {
tiling = VK_IMAGE_TILING_LINEAR;
} else {
result = vk_error(pdevice, VK_ERROR_FORMAT_NOT_SUPPORTED);
goto err_unsupported_format;
}
}
tiling_features2 =
pvr_get_image_format_features2(pdevice, info->format, info->tiling);
pvr_get_image_format_features2(pdevice, info->format, tiling);
if (tiling_features2 == 0) {
result = vk_error(pdevice, VK_ERROR_FORMAT_NOT_SUPPORTED);
goto err_unsupported_format;
@ -587,7 +663,7 @@ pvr_get_image_format_properties(struct pvr_physical_device *pdevice,
/* Linear tiled 3D images may only be used for transfer or blit
* operations.
*/
if (info->tiling == VK_IMAGE_TILING_LINEAR && usage & ~transfer_usage) {
if (tiling == VK_IMAGE_TILING_LINEAR && usage & ~transfer_usage) {
result = vk_error(pdevice, VK_ERROR_FORMAT_NOT_SUPPORTED);
goto err_unsupported_format;
}
@ -618,7 +694,7 @@ pvr_get_image_format_properties(struct pvr_physical_device *pdevice,
pImageFormatProperties->maxExtent.depth = max_render_size_z;
}
if (info->tiling == VK_IMAGE_TILING_LINEAR) {
if (tiling == VK_IMAGE_TILING_LINEAR) {
pImageFormatProperties->maxExtent.depth = 1;
pImageFormatProperties->maxArrayLayers = 1;
pImageFormatProperties->sampleCounts = VK_SAMPLE_COUNT_1_BIT;
@ -672,7 +748,7 @@ pvr_get_image_format_properties(struct pvr_physical_device *pdevice,
* or VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, so for simplicity don't
* support miplevels for these tilings.
*/
if (info->tiling == VK_IMAGE_TILING_LINEAR) {
if (tiling == VK_IMAGE_TILING_LINEAR) {
pImageFormatProperties->maxMipLevels = 1;
} else {
const uint32_t max_size = MAX3(pImageFormatProperties->maxExtent.width,
@ -738,6 +814,7 @@ VkResult pvr_GetPhysicalDeviceImageFormatProperties2(
case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO:
break;
case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO:
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT:
/* Nothing to do here, it's handled in
* pvr_get_image_format_properties)
*/

View file

@ -28,6 +28,7 @@
#include <stdint.h>
#include <string.h>
#include "drm-uapi/drm_fourcc.h"
#include "pvr_buffer.h"
#include "pvr_device.h"
#include "pvr_device_info.h"
@ -62,11 +63,17 @@ static void pvr_image_init_memlayout(struct pvr_image *image)
case VK_IMAGE_TILING_LINEAR:
image->memlayout = PVR_MEMLAYOUT_LINEAR;
break;
case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT:
/* Support only LINEAR now */
assert(image->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR);
image->memlayout = PVR_MEMLAYOUT_LINEAR;
break;
}
}
static void pvr_image_plane_init_physical_extent(
struct pvr_image *image,
const VkImageCreateInfo *pCreateInfo,
unsigned pbe_stride_align,
const struct vk_format_ycbcr_info *ycbcr_info,
uint8_t i)
@ -95,6 +102,19 @@ static void pvr_image_plane_init_physical_extent(
plane->physical_extent.width =
align(plane->physical_extent.width, pbe_stride_align);
}
if (image->vk.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
const VkImageDrmFormatModifierExplicitCreateInfoEXT *explicit_mod =
vk_find_struct_const(
pCreateInfo->pNext,
IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
if (explicit_mod) {
const uint32_t bpp =
vk_format_get_blocksize(image->vk.format);
plane->physical_extent.width =
explicit_mod->pPlaneLayouts[i].rowPitch / bpp;
}
}
}
if (ycbcr_info) {
@ -106,6 +126,7 @@ static void pvr_image_plane_init_physical_extent(
}
static void pvr_image_init_physical_extent(struct pvr_image *image,
const VkImageCreateInfo *pCreateInfo,
unsigned pbe_stride_align)
{
assert(image->memlayout != PVR_MEMLAYOUT_UNDEFINED);
@ -115,6 +136,7 @@ static void pvr_image_init_physical_extent(struct pvr_image *image,
for (uint8_t plane = 0; plane < image->plane_count; plane++) {
pvr_image_plane_init_physical_extent(image,
pCreateInfo,
pbe_stride_align,
ycbcr_info,
plane);
@ -197,6 +219,50 @@ static void pvr_image_setup_mip_levels(struct pvr_image *image)
static unsigned get_pbe_stride_align(const struct pvr_device_info *dev_info);
static VkResult pvr_pick_modifier(const VkImageCreateInfo *pCreateInfo,
unsigned pbe_stride_align,
uint64_t *modifier)
{
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);
/* Only support LINEAR now */
*modifier = DRM_FORMAT_MOD_INVALID;
if (mod_list)
for (unsigned i = 0; i < mod_list->drmFormatModifierCount; i++)
if (mod_list->pDrmFormatModifiers[i] == DRM_FORMAT_MOD_LINEAR)
*modifier = DRM_FORMAT_MOD_LINEAR;
if (explicit_mod) {
const uint32_t bpp = vk_format_get_blocksize(pCreateInfo->format);
assert(explicit_mod->drmFormatModifier == DRM_FORMAT_MOD_LINEAR &&
explicit_mod->drmFormatModifierPlaneCount == 1);
*modifier = explicit_mod->drmFormatModifier;
if (explicit_mod->pPlaneLayouts[0].offset != 0)
return VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT;
if (explicit_mod->pPlaneLayouts[0].rowPitch %
(bpp * pbe_stride_align) != 0) {
return VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT;
}
if (explicit_mod->pPlaneLayouts[0].rowPitch <
pCreateInfo->extent.width * bpp) {
return VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT;
}
}
return VK_SUCCESS;
}
VkResult pvr_CreateImage(VkDevice _device,
const VkImageCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
@ -204,6 +270,10 @@ VkResult pvr_CreateImage(VkDevice _device,
{
VK_FROM_HANDLE(pvr_device, device, _device);
struct pvr_image *image;
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
VkResult res;
unsigned pbe_stride_align = get_pbe_stride_align(&device->pdevice->dev_info);
if (wsi_common_is_swapchain_image(pCreateInfo)) {
return wsi_common_create_swapchain_image(&device->pdevice->wsi_device,
@ -211,11 +281,24 @@ VkResult pvr_CreateImage(VkDevice _device,
pImage);
}
if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
res = pvr_pick_modifier(pCreateInfo, pbe_stride_align,
&modifier);
if (res != VK_SUCCESS)
return vk_error(device, res);
assert(modifier == DRM_FORMAT_MOD_LINEAR);
}
image =
vk_image_create(&device->vk, pCreateInfo, pAllocator, sizeof(*image));
if (!image)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
if (image->vk.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
image->vk.drm_format_mod = modifier;
}
/* All images aligned to 4k, in case of arrays/CEM.
* Refer: pvr_GetImageMemoryRequirements for further details.
*/
@ -223,11 +306,9 @@ VkResult pvr_CreateImage(VkDevice _device,
image->plane_count = vk_format_get_plane_count(image->vk.format);
unsigned pbe_stride_align = get_pbe_stride_align(&device->pdevice->dev_info);
/* Initialize the image using the saved information from pCreateInfo */
pvr_image_init_memlayout(image);
pvr_image_init_physical_extent(image, pbe_stride_align);
pvr_image_init_physical_extent(image, pCreateInfo, pbe_stride_align);
pvr_image_setup_mip_levels(image);
*pImage = pvr_image_to_handle(image);

View file

@ -177,6 +177,7 @@ static void pvr_physical_device_get_supported_extensions(
.EXT_custom_border_color = true,
.EXT_depth_clamp_zero_one = true,
.EXT_depth_clip_enable = true,
.EXT_image_drm_format_modifier = true,
.EXT_extended_dynamic_state = true,
.EXT_extended_dynamic_state2 = true,
.EXT_extended_dynamic_state3 = true,

View file

@ -79,7 +79,7 @@ VkResult pvr_wsi_init(struct pvr_physical_device *pdevice)
if (result != VK_SUCCESS)
return result;
pdevice->wsi_device.supports_modifiers = false;
pdevice->wsi_device.supports_modifiers = true;
pdevice->wsi_device.can_present_on_device = pvr_can_present_on_device;
pdevice->vk.wsi_device = &pdevice->wsi_device;