blob: 3a6abfd12ce2ac18396fad31d4fd3581682fdf1d [file] [log] [blame]
/*
* Copyright © 2019 Google, LLC
*
* 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 "anv_private.h"
#include "anv_magma.h"
#include "drm-uapi/drm_fourcc.h"
#include "magma/magma_sysmem.h"
#include "vk_util.h"
#include "isl/isl.h"
#if VK_USE_PLATFORM_FUCHSIA
#define MAX_FORMAT_INDICES 128
static const uint32_t kMaxFormatIndices = MAX_FORMAT_INDICES;
struct anv_buffer_collection {
struct vk_object_base base;
magma_buffer_collection_t buffer_collection;
magma_sysmem_buffer_constraints_t constraints;
uint32_t format_index_input_index_map[MAX_FORMAT_INDICES];
};
VK_DEFINE_HANDLE_CASTS(anv_buffer_collection, base, VkBufferCollectionFUCHSIA, VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA)
VkResult anv_CreateBufferCollectionFUCHSIA(VkDevice vk_device,
const VkBufferCollectionCreateInfoFUCHSIA* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkBufferCollectionFUCHSIA* pCollection)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
magma_buffer_collection_t magma_buffer_collection;
status = magma_sysmem_connection_import_buffer_collection(
sysmem_connection, pCreateInfo->collectionToken, &magma_buffer_collection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_INVALID_EXTERNAL_HANDLE);
struct anv_buffer_collection* buffer_collection =
vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*buffer_collection), 8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
vk_object_base_init(&device->vk, &buffer_collection->base, VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA);
buffer_collection->buffer_collection = magma_buffer_collection;
buffer_collection->constraints = 0;
*pCollection = anv_buffer_collection_to_handle(buffer_collection);
return VK_SUCCESS;
}
void anv_DestroyBufferCollectionFUCHSIA(VkDevice vk_device, VkBufferCollectionFUCHSIA vk_collection,
const VkAllocationCallbacks* pAllocator)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return;
if (buffer_collection->constraints) {
magma_buffer_constraints_release2(buffer_collection->constraints);
}
magma_buffer_collection_release2(buffer_collection->buffer_collection);
vk_free2(&device->vk.alloc, pAllocator, buffer_collection);
}
static VkResult get_image_format_constraints(
VkDevice vk_device, VkFormat format, const VkImageCreateInfo* pImageInfo,
magma_image_format_constraints_t* image_constraints_out, isl_tiling_flags_t isl_tiling_flags,
bool aux_buffer, const VkImageFormatConstraintsInfoFUCHSIA* format_constraints)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
const uint32_t kPlane = 0;
const struct anv_format_plane plane_format =
anv_get_format_plane(&device->info, format, kPlane, pImageInfo->tiling);
const isl_surf_usage_flags_t isl_surf_usage =
choose_isl_surf_usage(pImageInfo->flags, // vk_create_flags
pImageInfo->usage, // vk_usage
0, // isl_extra_usage
VK_IMAGE_ASPECT_COLOR_BIT);
enum isl_surf_dim dim;
switch (pImageInfo->imageType) {
case VK_IMAGE_TYPE_1D:
dim = ISL_SURF_DIM_1D;
break;
case VK_IMAGE_TYPE_2D:
dim = ISL_SURF_DIM_2D;
break;
default:
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
struct isl_surf_init_info isl_surf_init_info = {
.dim = dim,
.format = plane_format.isl_format,
.width = pImageInfo->extent.width / plane_format.denominator_scales[0],
.height = pImageInfo->extent.height / plane_format.denominator_scales[1],
.depth = pImageInfo->extent.depth,
.levels = pImageInfo->mipLevels,
.array_len = pImageInfo->arrayLayers,
.samples = pImageInfo->samples,
.min_alignment_B = 0,
.row_pitch_B = 0,
.usage = isl_surf_usage,
.tiling_flags = isl_tiling_flags};
struct isl_surf isl_surf;
if (!isl_surf_init_s(&device->isl_dev, &isl_surf, &isl_surf_init_info)) {
mesa_loge("get_image_format_constraints: isl_surf_init_s failed");
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
assert(pImageInfo->extent.width);
magma_image_format_constraints_t image_constraints = {.width = pImageInfo->extent.width,
.height = pImageInfo->extent.height,
.layers = 1,
.bytes_per_row_divisor = 1,
.min_bytes_per_row = isl_surf.row_pitch_B};
bool is_yuv_format = false;
switch (format) {
case VK_FORMAT_B8G8R8A8_SINT:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_B8G8R8A8_SNORM:
case VK_FORMAT_B8G8R8A8_SSCALED:
case VK_FORMAT_B8G8R8A8_USCALED:
image_constraints.image_format = MAGMA_FORMAT_BGRA32;
break;
case VK_FORMAT_R8G8B8A8_SINT:
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SRGB:
case VK_FORMAT_R8G8B8A8_SNORM:
case VK_FORMAT_R8G8B8A8_SSCALED:
case VK_FORMAT_R8G8B8A8_USCALED:
image_constraints.image_format = MAGMA_FORMAT_R8G8B8A8;
break;
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
image_constraints.image_format = MAGMA_FORMAT_NV12;
is_yuv_format = true;
break;
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
image_constraints.image_format = MAGMA_FORMAT_I420;
is_yuv_format = true;
break;
case VK_FORMAT_R8_UNORM:
image_constraints.image_format = MAGMA_FORMAT_R8;
if (format_constraints && format_constraints->sysmemPixelFormat) {
if (format_constraints->sysmemPixelFormat == MAGMA_FORMAT_L8) {
image_constraints.image_format = MAGMA_FORMAT_L8;
} else if (format_constraints->sysmemPixelFormat != MAGMA_FORMAT_R8) {
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
}
break;
case VK_FORMAT_R8G8_UNORM:
image_constraints.image_format = MAGMA_FORMAT_R8G8;
break;
default:
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
switch (isl_surf.tiling) {
case ISL_TILING_LINEAR:
image_constraints.has_format_modifier = false;
assert(!aux_buffer);
break;
case ISL_TILING_X:
image_constraints.has_format_modifier = true;
image_constraints.format_modifier = MAGMA_FORMAT_MODIFIER_INTEL_X_TILED;
assert(!aux_buffer);
break;
case ISL_TILING_Y0:
image_constraints.has_format_modifier = true;
if (aux_buffer) {
if (isl_drm_modifier_get_score(&device->info, I915_FORMAT_MOD_Y_TILED_CCS) == 0)
return VK_ERROR_FORMAT_NOT_SUPPORTED;
image_constraints.format_modifier = MAGMA_FORMAT_MODIFIER_INTEL_Y_TILED_CCS;
} else {
image_constraints.format_modifier = MAGMA_FORMAT_MODIFIER_INTEL_Y_TILED;
}
if (device->info.ver >= 12 && !is_yuv_format) {
// On Gen12, images need to be a multiple of 4 tiles wide to be usable
// with RC CCS. Only do this size increase on non-YUV images, since YUV
// images won't take advantage of RC CCS.
image_constraints.bytes_per_row_divisor = 512;
}
break;
case ISL_TILING_Yf:
// According to isl_gfx6_filter_tiling, anvil doesn't support YF tiling.
assert(false);
return VK_ERROR_FORMAT_NOT_SUPPORTED;
default:
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
*image_constraints_out = image_constraints;
return VK_SUCCESS;
}
VkResult
anv_SetBufferCollectionBufferConstraintsFUCHSIA(VkDevice vk_device,
VkBufferCollectionFUCHSIA vk_collection,
const VkBufferConstraintsInfoFUCHSIA* pConstraints)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
magma_buffer_format_constraints_t format_constraints = {
.count = pConstraints->bufferCollectionConstraints.minBufferCount,
.usage = 0,
.secure_permitted = false,
.secure_required = false,
.ram_domain_supported = true,
.cpu_domain_supported = true,
.min_size_bytes = pConstraints->createInfo.size,
.options = MAGMA_BUFFER_FORMAT_CONSTRAINT_OPTIONS_EXTRA_COUNTS,
.min_buffer_count_for_camping =
pConstraints->bufferCollectionConstraints.minBufferCountForCamping,
.min_buffer_count_for_shared_slack =
pConstraints->bufferCollectionConstraints.minBufferCountForSharedSlack,
.min_buffer_count_for_dedicated_slack =
pConstraints->bufferCollectionConstraints.minBufferCountForDedicatedSlack,
.max_buffer_count = pConstraints->bufferCollectionConstraints.maxBufferCount};
magma_sysmem_buffer_constraints_t constraints;
status = magma_sysmem_connection_create_buffer_constraints(sysmem_connection,
&format_constraints, &constraints);
if (status != MAGMA_STATUS_OK)
return VK_ERROR_OUT_OF_HOST_MEMORY;
status =
magma_buffer_collection_set_constraints2(buffer_collection->buffer_collection, constraints);
magma_buffer_constraints_release2(constraints);
if (status != MAGMA_STATUS_OK)
return VK_ERROR_FORMAT_NOT_SUPPORTED;
return VK_SUCCESS;
}
static VkFormat sysmem_to_vk_format(uint32_t sysmem_format)
{
switch (sysmem_format) {
case MAGMA_FORMAT_BGRA32:
return VK_FORMAT_B8G8R8A8_UNORM;
case MAGMA_FORMAT_R8G8B8A8:
return VK_FORMAT_R8G8B8A8_UNORM;
case MAGMA_FORMAT_NV12:
return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
case MAGMA_FORMAT_I420:
return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
case MAGMA_FORMAT_L8:
case MAGMA_FORMAT_R8:
return VK_FORMAT_R8_UNORM;
case MAGMA_FORMAT_R8G8:
return VK_FORMAT_R8G8_UNORM;
default:
return VK_FORMAT_UNDEFINED;
}
}
static VkFormatFeatureFlags
get_image_format_features(const struct intel_device_info *devinfo,
VkFormat vk_format,
const struct anv_format *anv_format,
VkImageTiling vk_tiling,
const struct isl_drm_modifier_info *isl_mod_info) {
VkFormatFeatureFlags2KHR flags = anv_get_image_format_features2(devinfo,
vk_format, anv_format, vk_tiling, isl_mod_info);
// Drops any of the higher feature flag bits.
return (VkFormatFeatureFlags) flags;
}
VkResult anv_GetBufferCollectionPropertiesFUCHSIA(VkDevice vk_device,
VkBufferCollectionFUCHSIA vk_collection,
VkBufferCollectionPropertiesFUCHSIA* pProperties)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
magma_collection_info_t collection_info;
status = magma_buffer_collection_get_collection_info(buffer_collection->buffer_collection,
&collection_info);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
uint32_t count;
status = magma_collection_info_get_buffer_count(collection_info, &count);
if (status != MAGMA_STATUS_OK) {
magma_collection_info_release(collection_info);
return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
}
uint32_t sysmem_format;
status = magma_collection_info_get_format(collection_info, &sysmem_format);
if (status != MAGMA_STATUS_OK) {
magma_collection_info_release(collection_info);
return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
}
pProperties->sysmemPixelFormat = sysmem_format;
magma_bool_t has_format_modifier;
uint64_t format_modifier = 0;
status = magma_collection_info_get_format_modifier(collection_info, &has_format_modifier,
&format_modifier);
if (status != MAGMA_STATUS_OK) {
magma_collection_info_release(collection_info);
return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
}
uint32_t color_space = MAGMA_COLORSPACE_INVALID;
magma_collection_info_get_color_space(collection_info, &color_space);
// Colorspace may be invalid for non-images, so ignore error.
pProperties->sysmemColorSpaceIndex.colorSpace = color_space;
pProperties->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_IDENTITY;
pProperties->samplerYcbcrConversionComponents.g = VK_COMPONENT_SWIZZLE_IDENTITY;
pProperties->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY;
pProperties->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY;
pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
pProperties->suggestedXChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
pProperties->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
switch (color_space) {
case MAGMA_COLORSPACE_REC601_NTSC:
case MAGMA_COLORSPACE_REC601_PAL:
pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
break;
case MAGMA_COLORSPACE_REC601_NTSC_FULL_RANGE:
case MAGMA_COLORSPACE_REC601_PAL_FULL_RANGE:
pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
break;
case MAGMA_COLORSPACE_REC709:
pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
break;
case MAGMA_COLORSPACE_REC2020:
pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
break;
case MAGMA_COLORSPACE_SRGB:
pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
break;
default:
pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
break;
}
pProperties->createInfoIndex = 0;
if (buffer_collection->constraints) {
magma_bool_t format_valid[kMaxFormatIndices];
status = magma_collection_info_get_format_index(
collection_info, buffer_collection->constraints, format_valid, kMaxFormatIndices);
if (status != MAGMA_STATUS_OK) {
magma_collection_info_release(collection_info);
return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
}
// Choose the first valid format for now.
for (uint32_t i = 0; i < kMaxFormatIndices; i++) {
if (format_valid[i]) {
pProperties->createInfoIndex = buffer_collection->format_index_input_index_map[i];
break;
}
}
}
if (!has_format_modifier) {
format_modifier = MAGMA_FORMAT_MODIFIER_LINEAR;
}
{
VkFormat format = sysmem_to_vk_format(sysmem_format);
const struct anv_physical_device* physical_device = device->physical;
const struct intel_device_info* devinfo = &physical_device->info;
const struct anv_format* anv_format = anv_get_format(format);
if (has_format_modifier) {
pProperties->formatFeatures = get_image_format_features(devinfo, format, anv_format,
VK_IMAGE_TILING_OPTIMAL, NULL);
} else {
pProperties->formatFeatures = get_image_format_features(devinfo, format, anv_format,
VK_IMAGE_TILING_LINEAR, NULL);
}
}
magma_collection_info_release(collection_info);
pProperties->bufferCount = count;
if (pProperties->bufferCount < 1) {
pProperties->memoryTypeBits = 0u;
} else {
struct anv_physical_device* pdevice = device->physical;
// All memory types supported.
pProperties->memoryTypeBits = (1ull << pdevice->memory.type_count) - 1;
}
return VK_SUCCESS;
}
VkResult anv_SetBufferCollectionImageConstraintsFUCHSIA(
VkDevice vk_device, VkBufferCollectionFUCHSIA vk_collection,
const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_buffer_collection, collection, vk_collection);
// Can't set constraints twice.
if (collection->constraints)
return ANV_MAGMA_DRET(VK_ERROR_INITIALIZATION_FAILED);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
if (pImageConstraintsInfo->formatConstraintsCount < 1) {
assert(!(pImageConstraintsInfo->formatConstraintsCount < 1));
return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
}
const bool have_format_constraints = (pImageConstraintsInfo->pFormatConstraints != NULL);
// Secure formats not supported.
for (uint32_t i = 0; i < pImageConstraintsInfo->formatConstraintsCount; ++i) {
bool secure_required =
(pImageConstraintsInfo->pFormatConstraints[i].imageCreateInfo.flags &
VK_IMAGE_CREATE_PROTECTED_BIT);
if (secure_required) {
assert(!secure_required);
return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
}
}
magma_sysmem_buffer_constraints_t constraints;
// Create the buffer constraints.
{
magma_buffer_format_constraints_t format_constraints = {
.count = pImageConstraintsInfo->bufferCollectionConstraints.minBufferCount,
.usage = 0,
.secure_permitted = false,
.secure_required = false,
.ram_domain_supported = true,
.cpu_domain_supported = true,
.min_size_bytes = 0,
.options = MAGMA_BUFFER_FORMAT_CONSTRAINT_OPTIONS_EXTRA_COUNTS,
.min_buffer_count_for_camping =
pImageConstraintsInfo->bufferCollectionConstraints.minBufferCountForCamping,
.min_buffer_count_for_shared_slack =
pImageConstraintsInfo->bufferCollectionConstraints.minBufferCountForSharedSlack,
.min_buffer_count_for_dedicated_slack =
pImageConstraintsInfo->bufferCollectionConstraints.minBufferCountForDedicatedSlack,
.max_buffer_count = pImageConstraintsInfo->bufferCollectionConstraints.maxBufferCount};
status = magma_sysmem_connection_create_buffer_constraints(sysmem_connection,
&format_constraints, &constraints);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
}
uint32_t format_index = 0;
// Set format slots for each image info.
for (uint32_t i = 0; i < pImageConstraintsInfo->formatConstraintsCount; ++i) {
const VkImageCreateInfo* pCreateInfo =
&pImageConstraintsInfo->pFormatConstraints[i].imageCreateInfo;
VkFormat format = pCreateInfo->format;
const struct anv_physical_device* physical_device = device->physical;
const struct intel_device_info* devinfo = &physical_device->info;
const struct anv_format* anv_format = anv_get_format(format);
const VkFormatFeatureFlags linear_flags =
get_image_format_features(devinfo, format, anv_format, VK_IMAGE_TILING_LINEAR, NULL);
const VkFormatFeatureFlags optimal_flags =
get_image_format_features(devinfo, format, anv_format, VK_IMAGE_TILING_OPTIMAL, NULL);
const VkImageFormatConstraintsInfoFUCHSIA* format_constraints =
have_format_constraints ? &pImageConstraintsInfo->pFormatConstraints[i] : NULL;
const uint32_t colorSpaceCount = format_constraints ? format_constraints->colorSpaceCount : 0;
uint32_t color_spaces[colorSpaceCount];
for (uint32_t j = 0; j < colorSpaceCount; ++j) {
color_spaces[j] = format_constraints->pColorSpaces[j].colorSpace;
}
enum { SLOT0_LINEAR, SLOT1_X_TILED, SLOT2_TILED, SLOT3_TILED };
const uint32_t kSlotCount = 4;
magma_image_format_constraints_t image_constraints[kSlotCount];
bool image_constraints_valid[kSlotCount];
status = get_image_format_constraints(vk_device, format, pCreateInfo,
&image_constraints[SLOT0_LINEAR], ISL_TILING_LINEAR_BIT,
/*aux_buffer*/ false, format_constraints);
if (status != VK_SUCCESS)
continue;
// Sysmem can't handle certain formats tiled, so don't attempt it.
bool skip_optimal = (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) ||
(image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_NV12) ||
(image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_I420) ||
(image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_L8) ||
(image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_R8) ||
(image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_R8G8);
image_constraints_valid[SLOT0_LINEAR] =
!format_constraints || !(~linear_flags & format_constraints->requiredFormatFeatures);
if (skip_optimal) {
image_constraints_valid[SLOT1_X_TILED] = false;
} else {
image_constraints_valid[SLOT1_X_TILED] =
!format_constraints || !(~optimal_flags & format_constraints->requiredFormatFeatures);
}
image_constraints_valid[SLOT2_TILED] = image_constraints_valid[SLOT1_X_TILED];
image_constraints_valid[SLOT3_TILED] = image_constraints_valid[SLOT1_X_TILED];
for (uint32_t slot = 0; slot < kSlotCount; slot++) {
if (!image_constraints_valid[slot])
continue;
switch (slot) {
case SLOT0_LINEAR:
// Image constraints already initialized.
break;
case SLOT1_X_TILED:
status = get_image_format_constraints(
vk_device, format, pCreateInfo, &image_constraints[SLOT1_X_TILED], ISL_TILING_X_BIT,
/*aux_buffer*/ false, format_constraints);
break;
case SLOT2_TILED:
status = get_image_format_constraints(
vk_device, format, pCreateInfo, &image_constraints[SLOT2_TILED],
ISL_TILING_ANY_MASK, /*aux_buffer*/ false, format_constraints);
break;
case SLOT3_TILED: {
const VkImageFormatListCreateInfoKHR* fmt_list =
vk_find_struct_const(pCreateInfo->pNext, IMAGE_FORMAT_LIST_CREATE_INFO_KHR);
if ((pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT) ||
!anv_formats_ccs_e_compatible(&device->info, pCreateInfo->flags,
pCreateInfo->format, pCreateInfo->usage, pCreateInfo->tiling, fmt_list)) {
continue;
}
status = get_image_format_constraints(
vk_device, format, pCreateInfo, &image_constraints[SLOT3_TILED],
ISL_TILING_ANY_MASK, /*aux_buffer*/ true, format_constraints);
break;
}
default:
assert(false);
}
if (status != VK_SUCCESS)
continue;
// Currently every vulkan format maps to only 1 sysmem format, so ensure the client is
// using the same format.
if (format_constraints && format_constraints->sysmemPixelFormat &&
(format_constraints->sysmemPixelFormat != image_constraints[slot].image_format)) {
continue;
}
collection->format_index_input_index_map[format_index] = i;
status = magma_buffer_constraints_set_format2(constraints, format_index,
&image_constraints[slot]);
if (status != MAGMA_STATUS_OK) {
magma_buffer_constraints_release2(constraints);
return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
}
if (colorSpaceCount) {
magma_buffer_constraints_set_colorspaces2(constraints, format_index, colorSpaceCount,
color_spaces);
}
format_index += 1;
if (format_index >= kMaxFormatIndices) {
assert(!(format_index >= kMaxFormatIndices));
magma_buffer_constraints_release2(constraints);
return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
}
}
}
if (format_index == 0) {
magma_buffer_constraints_release2(constraints);
return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
}
status = magma_buffer_collection_set_constraints2(collection->buffer_collection, constraints);
if (status != MAGMA_STATUS_OK) {
magma_buffer_constraints_release2(constraints);
return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
}
collection->constraints = constraints;
return VK_SUCCESS;
}
// Takes ownership of the buffer format collection_info.
static VkResult anv_image_params_from_collection_info(
magma_collection_info_t collection_info, uint32_t width, uint32_t height,
VkImageDrmFormatModifierExplicitCreateInfoEXT* modifier_info_out,
VkSubresourceLayout* subresource_layout_out)
{
magma_bool_t has_format_modifier;
uint64_t format_modifier;
magma_status_t status = MAGMA_STATUS_OK;
magma_image_plane_t magma_planes[MAGMA_MAX_IMAGE_PLANES];
status =
magma_collection_info_get_plane_info_with_size(collection_info, width, height, magma_planes);
if (status == MAGMA_STATUS_OK) {
status = magma_collection_info_get_format_modifier(collection_info, &has_format_modifier,
&format_modifier);
}
uint32_t magma_format;
if (status == MAGMA_STATUS_OK) {
status = magma_collection_info_get_format(collection_info, &magma_format);
}
magma_collection_info_release(collection_info);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
uint64_t drm_format_modifier = DRM_FORMAT_MOD_LINEAR;
bool has_aux = false;
if (has_format_modifier) {
switch (format_modifier) {
case MAGMA_FORMAT_MODIFIER_INTEL_X_TILED:
drm_format_modifier = I915_FORMAT_MOD_X_TILED;
break;
case MAGMA_FORMAT_MODIFIER_INTEL_Y_TILED:
drm_format_modifier = I915_FORMAT_MOD_Y_TILED;
break;
case MAGMA_FORMAT_MODIFIER_INTEL_YF_TILED:
drm_format_modifier = I915_FORMAT_MOD_Yf_TILED;
break;
case MAGMA_FORMAT_MODIFIER_INTEL_Y_TILED_CCS:
drm_format_modifier = I915_FORMAT_MOD_Y_TILED_CCS;
has_aux = true;
break;
case MAGMA_FORMAT_MODIFIER_INTEL_YF_TILED_CCS:
drm_format_modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
has_aux = true;
break;
case MAGMA_FORMAT_MODIFIER_LINEAR:
break;
default:
assert(false);
}
}
uint32_t planes = has_aux ? 2 : 1;
switch (magma_format) {
case MAGMA_FORMAT_I420:
planes = 3;
break;
case MAGMA_FORMAT_NV12:
planes = 2;
break;
default:
break;
}
for (uint32_t i = 0; i < MAGMA_MAX_IMAGE_PLANES; i++) {
subresource_layout_out[i].rowPitch = magma_planes[i].bytes_per_row;
subresource_layout_out[i].offset = magma_planes[i].byte_offset;
subresource_layout_out[i].size = magma_planes[i].bytes_per_row * height;
}
if (has_aux) {
// magma always puts the CCS surface in plane 3, while the rest of the Intel code expects it
// in plane 1.
memcpy(&subresource_layout_out[1], &subresource_layout_out[3],
sizeof(subresource_layout_out[1]));
}
modifier_info_out->sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
modifier_info_out->pNext = NULL;
modifier_info_out->drmFormatModifier = drm_format_modifier;
modifier_info_out->drmFormatModifierPlaneCount = planes;
modifier_info_out->pPlaneLayouts = subresource_layout_out;
return VK_SUCCESS;
}
VkResult anv_image_params_from_buffer_collection(
struct anv_device* device, VkBufferCollectionFUCHSIA vk_collection, const VkExtent3D* extent,
VkImageDrmFormatModifierExplicitCreateInfoEXT* modifier_info_out,
VkSubresourceLayout* subresource_layout_out)
{
ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
magma_collection_info_t collection_info;
status = magma_buffer_collection_get_collection_info(buffer_collection->buffer_collection,
&collection_info);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
uint32_t width = extent ? extent->width : 0u;
uint32_t height = extent ? extent->height : 0;
return anv_image_params_from_collection_info(collection_info, width, height, modifier_info_out,
subresource_layout_out);
}
VkResult anv_memory_params_from_buffer_collection(VkDevice vk_device,
VkBufferCollectionFUCHSIA vk_collection,
bool* is_cache_coherent_out)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
magma_collection_info_t collection_info;
status = magma_buffer_collection_get_collection_info(buffer_collection->buffer_collection,
&collection_info);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
uint32_t coherency_domain;
if (status == MAGMA_STATUS_OK) {
status = magma_collection_info_get_coherency_domain(collection_info, &coherency_domain);
}
magma_collection_info_release(collection_info);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
*is_cache_coherent_out = coherency_domain == MAGMA_COHERENCY_DOMAIN_CPU;
return VK_SUCCESS;
}
VkResult anv_get_buffer_collection_handle(struct anv_device* device,
VkBufferCollectionFUCHSIA vk_collection, uint32_t index,
uint32_t* handle_out, uint32_t* offset_out)
{
ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
magma_sysmem_connection_t sysmem_connection;
magma_status_t status = AnvMagmaGetSysmemConnection(
get_anv_connection(device->vk.magma_connection), &sysmem_connection);
if (status != MAGMA_STATUS_OK)
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
if (magma_buffer_collection_get_buffer_handle(buffer_collection->buffer_collection, index,
handle_out, offset_out) != MAGMA_STATUS_OK) {
return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
}
return VK_SUCCESS;
}
#endif // VK_USE_PLATFORM_FUCHSIA