Merge branch 'pvr-mod-basic' into 'main'

Draft: pvr: preliminary EXT_image_drm_format_modifier support

See merge request mesa/mesa!38991
This commit is contained in:
Icenowy Zheng 2025-12-20 07:58:05 +08:00
commit 28d85aab39
4 changed files with 162 additions and 8 deletions

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"
@ -437,6 +438,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,
@ -466,6 +523,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;
@ -492,6 +553,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) {
@ -504,8 +566,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;
@ -535,7 +611,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;
}
@ -566,7 +642,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;
@ -620,7 +696,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,
@ -686,6 +762,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_PER_ARCH(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"
@ -61,10 +62,16 @@ 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_init_physical_extent(struct pvr_image *image,
const VkImageCreateInfo *pCreateInfo,
unsigned pbe_stride_align)
{
assert(image->memlayout != PVR_MEMLAYOUT_UNDEFINED);
@ -92,6 +99,19 @@ static void pvr_image_init_physical_extent(struct pvr_image *image,
image->physical_extent.width =
align(image->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);
image->physical_extent.width =
explicit_mod->pPlaneLayouts[0].rowPitch / bpp;
}
}
}
}
@ -154,6 +174,47 @@ 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 (!util_is_aligned(explicit_mod->pPlaneLayouts[0].rowPitch,
bpp * pbe_stride_align))
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,
@ -161,6 +222,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,
@ -168,21 +233,32 @@ 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.
*/
image->alignment = 4096U;
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

@ -175,6 +175,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

@ -75,7 +75,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;