blob: 0e11119648fcc444ce1fde2743302852f3581a5f [file] [log] [blame]
/* Copyright (c) 2015-2024 The Khronos Group Inc.
* Copyright (C) 2025 Arm Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vulkan/utility/vk_format_utils.h>
#include "stateless/stateless_validation.h"
#include "utils/math_utils.h"
#include <cstdint>
namespace stateless {
bool Device::ValidateTensorDescriptionARM(const VkTensorDescriptionARM &description, const Location &description_loc) const {
bool skip = false;
if (description.format == VK_FORMAT_UNDEFINED) {
skip |= LogError("VUID-VkTensorDescriptionARM-format-09735", device, description_loc.dot(Field::format),
"is VK_FORMAT_UNDEFINED");
return skip;
} else {
const uint32_t component_count = vkuFormatComponentCount(description.format);
if (component_count != 1) {
skip |= LogError("VUID-VkTensorDescriptionARM-format-09735", device, description_loc.dot(Field::format),
"(%s) has (%" PRIu32 ") components.", string_VkFormat(description.format), component_count);
}
}
// pStrides can be null
if (const auto *strides = description.pStrides) {
if (description.tiling == VK_TENSOR_TILING_OPTIMAL_ARM) {
skip |= LogError("VUID-VkTensorCreateInfoARM-pDescription-09720", device, description_loc.dot(Field::tiling),
"is VK_TENSOR_TILING_OPTIMAL_ARM, but pDescription::pStrides (%p) is not null", description.pStrides);
}
const uint32_t texel_block_size = vkuFormatTexelBlockSize(description.format);
if (strides[description.dimensionCount - 1] != texel_block_size) {
skip |= LogError("VUID-VkTensorDescriptionARM-pStrides-09736", device,
description_loc.dot(Field::pStrides, description.dimensionCount - 1),
"(%" PRIi64 ") must equal the size in bytes of a tensor element (%" PRIu32 ")",
strides[description.dimensionCount - 1], texel_block_size);
}
if (static_cast<uint64_t>(strides[0]) * static_cast<uint64_t>(description.pDimensions[0]) >
phys_dev_ext_props.tensor_properties.maxTensorSize) {
skip |= LogError("VUID-VkTensorDescriptionARM-pStrides-09884", device, description_loc.dot(Field::pStrides, 0),
"(%" PRId64 ") x pDimensions[0] (%" PRId64
") is greater than VkPhysicalDeviceTensorPropertiesARM::maxTensorSize (%" PRIu64 ").",
strides[0], description.pDimensions[0], phys_dev_ext_props.tensor_properties.maxTensorSize);
}
for (uint32_t i = 0; i < description.dimensionCount; i++) {
if (!IsIntegerMultipleOf(strides[i], texel_block_size)) {
skip |=
LogError("VUID-VkTensorDescriptionARM-pStrides-09737", device, description_loc.dot(Field::pStrides, i),
"(%" PRIi64 ") must be a multiple of the element size (%" PRIu32 ")", strides[i], texel_block_size);
}
if (strides[i] <= 0 || strides[i] > phys_dev_ext_props.tensor_properties.maxTensorStride) {
skip |= LogError("VUID-VkTensorDescriptionARM-pStrides-09738", device, description_loc.dot(Field::pStrides, i),
"(%" PRIi64 ") is <= 0 or > maxTensorStride (%" PRIu64 ")", strides[i],
phys_dev_ext_props.tensor_properties.maxTensorStride);
}
if (i > 0) {
if (strides[i - 1] < static_cast<int64_t>(strides[i] * description.pDimensions[i])) {
skip |=
LogError("VUID-VkTensorDescriptionARM-pStrides-09739", device, description_loc.dot(Field::pStrides, i - 1),
"(%" PRIi64 ") < pStrides[%" PRIu32 "] (%" PRIi64 ") * pDimensions[%" PRIu32 "] (%" PRIu64 ")",
strides[i - 1], i, strides[i], i, description.pDimensions[i]);
}
}
}
if (!enabled_features.tensorNonPacked) {
int64_t i = description.dimensionCount - 1;
bool is_packed = strides[i] == vkuFormatTexelBlockSize(description.format);
while (is_packed && i > 0) {
if (strides[i - 1] != static_cast<int64_t>(strides[i] * description.pDimensions[i])) {
is_packed = false;
break;
}
i--;
}
// if other errors above occured, i might be zero, but another error will be reported already
if (!is_packed && i > 0) {
skip |= LogError("VUID-VkTensorDescriptionARM-None-09740", device, description_loc,
"does not define a packed tensor: pStrides[%" PRIi64 "] (%" PRIi64 ") != pStrides[%" PRIi64
"] (%" PRIi64 ") * pDimensions[%" PRIi64 "] (%" PRIi64 ")",
i - 1, strides[i - 1], i, strides[i], i, description.pDimensions[i]);
}
}
}
if (description.dimensionCount > phys_dev_ext_props.tensor_properties.maxTensorDimensionCount) {
skip |= LogError("VUID-VkTensorDescriptionARM-dimensionCount-09733", device, description_loc.dot(Field::dimensionCount),
"(%" PRIu32
") must be less than or equal to "
"VkPhysicalDeviceTensorPropertiesARM::maxTensorDimensionCount (%" PRIu32 ")",
description.dimensionCount, phys_dev_ext_props.tensor_properties.maxTensorDimensionCount);
}
{
int64_t total_elements = 1;
auto *dims = description.pDimensions;
auto would_overflow = false;
for (uint32_t i = 0; i < description.dimensionCount; i++) {
if (INT64_MAX / total_elements >= dims[i]) {
total_elements *= dims[i];
} else {
would_overflow = true;
}
if (dims[i] <= 0) {
skip |= LogError("VUID-VkTensorDescriptionARM-pDimensions-09734", device,
description_loc.dot(Field::pDimensions, i), "(%" PRIi64 ") must be greater than 0.", dims[i]);
} else if (static_cast<uint64_t>(dims[i]) > phys_dev_ext_props.tensor_properties.maxPerDimensionTensorElements) {
skip |=
LogError("VUID-VkTensorDescriptionARM-pDimensions-09883", device, description_loc.dot(Field::pDimensions, i),
"(%" PRIi64 ") is greater than maxPerDimensionTensorElements (%" PRIu64 ")", dims[i],
phys_dev_ext_props.tensor_properties.maxPerDimensionTensorElements);
}
}
if (static_cast<uint64_t>(total_elements) > phys_dev_ext_props.tensor_properties.maxTensorElements || would_overflow) {
skip |= LogError("VUID-VkTensorCreateInfoARM-tensorElements-09721", device, description_loc.dot(Field::pDimensions),
"the total number of elements (%" PRIi64 ") is greater than maxTensorElements (%" PRIu64 ")", total_elements,
phys_dev_ext_props.tensor_properties.maxTensorElements);
}
}
bool image_aliasing = (description.usage & VK_TENSOR_USAGE_IMAGE_ALIASING_BIT_ARM) != 0;
if (description.tiling == VK_TENSOR_TILING_OPTIMAL_ARM && image_aliasing) {
if (description.pDimensions[description.dimensionCount - 1] > 4) {
skip |= LogError("VUID-VkTensorDescriptionARM-tiling-09741", device, description_loc.dot(Field::tiling),
"is VK_TENSOR_TILING_OPTIMAL_ARM and usage (%s) includes VK_TENSOR_USAGE_IMAGE_ALIASING_BIT_ARM "
"but pDimensions[%" PRIu32 "] (%" PRIu64 ") > 4",
string_VkTensorUsageFlagsARM(description.usage).c_str(), (description.dimensionCount - 1),
description.pDimensions[description.dimensionCount - 1]);
}
}
if (description.tiling == VK_TENSOR_TILING_LINEAR_ARM && image_aliasing) {
skip |= LogError("VUID-VkTensorDescriptionARM-tiling-09742", device, description_loc.dot(Field::tiling),
"is VK_TENSOR_TILING_LINEAR_ARM but usage (%s) includes VK_TENSOR_USAGE_IMAGE_ALIASING_BIT_ARM",
string_VkTensorUsageFlagsARM(description.usage).c_str());
}
return skip;
}
bool Device::manual_PreCallValidateCreateTensorARM(VkDevice device, const VkTensorCreateInfoARM *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkTensorARM *pTensor,
const Context &context) const {
bool skip = false;
if (!enabled_features.tensors) {
skip |=
LogError("VUID-vkCreateTensorARM-tensors-09832", device, context.error_obj.location, "tensors feature is not enabled");
}
const Location create_info_loc = context.error_obj.location.dot(Field::pCreateInfo);
ASSERT_AND_RETURN_SKIP(pCreateInfo->pDescription);
auto description = *pCreateInfo->pDescription;
skip |= ValidateTensorDescriptionARM(description, create_info_loc.dot(Field::pDescription));
if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) {
if (pCreateInfo->queueFamilyIndexCount <= 1) {
skip |= LogError("VUID-VkTensorCreateInfoARM-sharingMode-09723", device, create_info_loc.dot(Field::sharingMode),
"is VK_SHARING_MODE_CONCURRENT, but queueFamilyIndexCount is %" PRIu32 ".",
pCreateInfo->queueFamilyIndexCount);
}
if (!pCreateInfo->pQueueFamilyIndices) {
skip |= LogError("VUID-VkTensorCreateInfoARM-sharingMode-09722", device, create_info_loc.dot(Field::sharingMode),
"is VK_SHARING_MODE_CONCURRENT, but pQueueFamilyIndices is NULL.");
}
}
if (vku::FindStructInPNextChain<VkOpaqueCaptureDescriptorDataCreateInfoEXT>(pCreateInfo->pNext)) {
if (!(pCreateInfo->flags & VK_TENSOR_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_ARM)) {
skip |= LogError("VUID-VkTensorCreateInfoARM-pNext-09727", device, create_info_loc.dot(Field::pNext),
"includes a VkOpaqueCaptureDescriptorDataCreateInfoEXT structure, but flags (%s) is "
"missing VK_TENSOR_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_ARM",
string_VkTensorCreateFlagsARM(pCreateInfo->flags).c_str());
}
}
if ((pCreateInfo->flags & VK_TENSOR_CREATE_PROTECTED_BIT_ARM) != 0) {
if (!enabled_features.protectedMemory) {
skip |= LogError("VUID-VkTensorCreateInfoARM-protectedMemory-09729", device, create_info_loc.dot(Field::flags),
"%s has the (%s) bit set but the protectedMemory device feature is not enabled.",
string_VkTensorCreateFlagsARM(pCreateInfo->flags).c_str(),
string_VkTensorCreateFlagsARM(VK_TENSOR_CREATE_PROTECTED_BIT_ARM).c_str());
}
}
if ((pCreateInfo->flags & VK_TENSOR_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_ARM) != 0) {
if (!enabled_features.descriptorBufferCaptureReplay) {
skip |= LogError("VUID-VkTensorCreateInfoARM-flags-09726", device, create_info_loc.dot(Field::flags),
"(%s) includes (%s), but the descriptorBufferCaptureReplay feature is not enabled.",
string_VkTensorCreateFlagsARM(pCreateInfo->flags).c_str(),
string_VkTensorCreateFlagsARM(VK_TENSOR_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_ARM).c_str());
}
}
if (auto external_memory_info = vku::FindStructInPNextChain<VkExternalMemoryTensorCreateInfoARM>(pCreateInfo->pNext)) {
VkPhysicalDeviceExternalTensorInfoARM tensor_info = vku::InitStructHelper();
tensor_info.pDescription = pCreateInfo->pDescription;
tensor_info.handleType = static_cast<VkExternalMemoryHandleTypeFlagBits>(external_memory_info->handleTypes);
VkExternalTensorPropertiesARM properties = vku::InitStructHelper();
dispatch_instance_->GetPhysicalDeviceExternalTensorPropertiesARM(physical_device, &tensor_info, &properties);
const auto compatible_types = properties.externalMemoryProperties.compatibleHandleTypes;
if ((external_memory_info->handleTypes & compatible_types) != external_memory_info->handleTypes) {
skip |= LogError(
"VUID-VkTensorCreateInfoARM-pNext-09864", device,
create_info_loc.pNext(Struct::VkExternalMemoryTensorCreateInfoARM, Field::handleTypes),
"(%s) is not reported as compatible by vkGetPhysicalDeviceExternalTensorPropertiesARM. Compatible types are: %s",
string_VkExternalMemoryHandleTypeFlags(external_memory_info->handleTypes).c_str(),
string_VkExternalMemoryHandleTypeFlags(compatible_types).c_str());
}
}
return skip;
}
} // namespace stateless