diff --git a/src/imagination/vulkan/pvr_formats.c b/src/imagination/vulkan/pvr_formats.c index 074a148f0b0..392c707d21a 100644 --- a/src/imagination/vulkan/pvr_formats.c +++ b/src/imagination/vulkan/pvr_formats.c @@ -27,6 +27,7 @@ #include #include +#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) */ diff --git a/src/imagination/vulkan/pvr_image.c b/src/imagination/vulkan/pvr_image.c index 09458aad3f6..7bdcebd1d3c 100644 --- a/src/imagination/vulkan/pvr_image.c +++ b/src/imagination/vulkan/pvr_image.c @@ -28,6 +28,7 @@ #include #include +#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); diff --git a/src/imagination/vulkan/pvr_physical_device.c b/src/imagination/vulkan/pvr_physical_device.c index 5e2286707b8..7256b4be7ef 100644 --- a/src/imagination/vulkan/pvr_physical_device.c +++ b/src/imagination/vulkan/pvr_physical_device.c @@ -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, diff --git a/src/imagination/vulkan/pvr_wsi.c b/src/imagination/vulkan/pvr_wsi.c index 4177b6284a1..3e00f4f874c 100644 --- a/src/imagination/vulkan/pvr_wsi.c +++ b/src/imagination/vulkan/pvr_wsi.c @@ -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;