blob: 7bdff13bf9890edc6b1f30fe526255038dac6e0d [file]
/* Copyright (c) 2015-2026 The Khronos Group Inc.
* Copyright (c) 2015-2026 Valve Corporation
* Copyright (c) 2015-2026 LunarG, Inc.
* Copyright (C) 2015-2025 Google Inc.
* Modifications Copyright (C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
*
* 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/vulkan_core.h>
#include <vulkan/utility/vk_format_utils.h>
#include "containers/span.h"
#include "error_message/error_location.h"
#include "stateless/stateless_validation.h"
#include "utils/math_utils.h"
namespace stateless {
bool Device::ValidateMicromapBuildInfo(const Context& context, const VkMicromapBuildInfoEXT& build_info,
const Location& build_info_loc) const {
bool skip = false;
if (build_info.pUsageCounts && build_info.ppUsageCounts) {
skip |= LogError("VUID-VkMicromapBuildInfoEXT-pUsageCounts-07516", device, build_info_loc,
"both pUsageCounts and ppUsageCounts are not NULL.");
}
if (build_info.type == VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT && (build_info.pUsageCounts || build_info.ppUsageCounts)) {
const Field usage_field = build_info.pUsageCounts ? Field::pUsageCounts : Field::ppUsageCounts;
for (uint32_t usage_i = 0; usage_i < build_info.usageCountsCount; ++usage_i) {
const VkMicromapUsageEXT& usage =
build_info.pUsageCounts ? build_info.pUsageCounts[usage_i] : *build_info.ppUsageCounts[usage_i];
skip |= context.ValidateRangedEnum(
build_info_loc.dot(usage_field, usage_i).dot(Field::format), vvl::Enum::VkOpacityMicromapFormatKHR,
static_cast<VkOpacityMicromapFormatKHR>(usage.format), "VUID-VkMicromapBuildInfoEXT-format-11652");
}
}
return skip;
}
bool Device::manual_PreCallValidateCreateMicromapEXT(VkDevice device, const VkMicromapCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator, VkMicromapEXT* pMicromap,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapEXT) {
skip |= LogError("VUID-vkCreateMicromapEXT-micromap-11615", device, error_obj.location,
"The VkPhysicalDeviceOpacityMicromapFeaturesEXT::micromap feature was not enabled.");
}
if ((pCreateInfo->createFlags & VK_MICROMAP_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT) &&
!enabled_features.micromapCaptureReplayEXT) {
skip |= LogError("VUID-VkMicromapCreateInfoEXT-micromapCaptureReplay-11616", device, error_obj.location,
"micromapCaptureReplay feature was not enabled.");
}
return skip;
}
bool Device::manual_PreCallValidateDestroyMicromapEXT(VkDevice device, VkMicromapEXT micromap,
const VkAllocationCallbacks* pAllocator, const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapEXT) {
skip |= LogError("VUID-vkDestroyMicromapEXT-micromap-11619", device, error_obj.location,
"The VkPhysicalDeviceOpacityMicromapFeaturesEXT::micromap feature was not enabled.");
}
return skip;
}
bool Device::manual_PreCallValidateCmdBuildMicromapsEXT(VkCommandBuffer commandBuffer, uint32_t infoCount,
const VkMicromapBuildInfoEXT* pInfos, const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapEXT) {
skip |= LogError("VUID-vkCmdBuildMicromapsEXT-micromap-11648", device, error_obj.location,
"The VkPhysicalDeviceOpacityMicromapFeaturesEXT::micromap feature was not enabled.");
}
for (const auto [info_i, info] : vvl::enumerate(pInfos, infoCount)) {
const Location info_loc = error_obj.location.dot(Field::pInfos, info_i);
if (!IsPointerAligned(info.scratchData.deviceAddress,
phys_dev_ext_props.acc_structure_props.minAccelerationStructureScratchOffsetAlignment)) {
skip |= LogError("VUID-vkCmdBuildMicromapsEXT-pInfos-07514", commandBuffer,
info_loc.dot(Field::scratchData).dot(Field::deviceAddress),
"(0x%" PRIx64 ") must be aligned to minAccelerationStructureScratchOffsetAlignment (%" PRIu32 ").",
info.scratchData.deviceAddress,
phys_dev_ext_props.acc_structure_props.minAccelerationStructureScratchOffsetAlignment);
}
if (info.triangleArray.deviceAddress == 0) {
// TODO - This needs to be in CoreChecks and use cc_buffer_address.cpp
skip |= LogError("VUID-vkCmdBuildMicromapsEXT-pInfos-10897", device,
info_loc.dot(Field::triangleArray).dot(Field::deviceAddress), "is NULL.");
} else if (!IsPointerAligned(info.triangleArray.deviceAddress, 256)) {
skip |= LogError("VUID-vkCmdBuildMicromapsEXT-pInfos-07515", commandBuffer,
info_loc.dot(Field::triangleArray).dot(Field::deviceAddress),
"(0x%" PRIx64 ") must be aligned to 256.", info.triangleArray.deviceAddress);
}
if (info.data.deviceAddress == 0) {
// TODO - This needs to be in CoreChecks and use cc_buffer_address.cpp
skip |= LogError("VUID-vkCmdBuildMicromapsEXT-pInfos-10896", device,
info_loc.dot(Field::data).dot(Field::deviceAddress), "is NULL.");
} else if (!IsPointerAligned(info.data.deviceAddress, 256)) {
skip |= LogError("VUID-vkCmdBuildMicromapsEXT-pInfos-07515", commandBuffer,
info_loc.dot(Field::data).dot(Field::deviceAddress), "(0x%" PRIx64 ") must be aligned to 256.",
info.data.deviceAddress);
}
skip |= ValidateMicromapBuildInfo(context, info, info_loc);
}
return skip;
}
bool Device::manual_PreCallValidateBuildMicromapsEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount,
const VkMicromapBuildInfoEXT* pInfos, const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapHostCommandsEXT) {
skip |= LogError("VUID-vkBuildMicromapsEXT-micromapHostCommands-07555", device, error_obj.location,
"micromapHostCommands feature was not enabled.");
}
for (const auto [info_i, info] : vvl::enumerate(pInfos, infoCount)) {
const Location info_loc = error_obj.location.dot(Field::pInfos, info_i);
if (!info.data.hostAddress) {
skip |= LogError("VUID-vkBuildMicromapsEXT-pInfos-07553", device, info_loc.dot(Field::data).dot(Field::hostAddress),
"is zero.");
}
if (!info.triangleArray.hostAddress) {
skip |= LogError("VUID-vkBuildMicromapsEXT-pInfos-07554", device,
info_loc.dot(Field::triangleArray).dot(Field::hostAddress), "is zero.");
}
skip |= ValidateMicromapBuildInfo(context, info, info_loc);
}
return skip;
}
bool Device::manual_PreCallValidateCopyMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation,
const VkCopyMicromapInfoEXT* pInfo, const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapHostCommandsEXT) {
skip |= LogError("VUID-vkCopyMicromapEXT-micromapHostCommands-07560", device, error_obj.location,
"micromapHostCommands feature was not enabled.");
}
const Location info_loc = error_obj.location.dot(Field::pInfo);
if (pInfo->mode != VK_COPY_MICROMAP_MODE_COMPACT_EXT && pInfo->mode != VK_COPY_MICROMAP_MODE_CLONE_EXT) {
skip |= LogError("VUID-VkCopyMicromapInfoEXT-mode-07531", device, info_loc.dot(Field::mode), "is %s.",
string_VkCopyMicromapModeEXT(pInfo->mode));
}
return skip;
}
bool Device::manual_PreCallValidateCopyMicromapToMemoryEXT(VkDevice device, VkDeferredOperationKHR deferredOperation,
const VkCopyMicromapToMemoryInfoEXT* pInfo,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapHostCommandsEXT) {
skip |= LogError("VUID-vkCopyMicromapToMemoryEXT-micromapHostCommands-07571", device, error_obj.location,
"micromapHostCommands feature was not enabled.");
}
const Location info_loc = error_obj.location.dot(Field::pInfo);
if (pInfo->mode != VK_COPY_MICROMAP_MODE_SERIALIZE_EXT) {
skip |= LogError("VUID-VkCopyMicromapToMemoryInfoEXT-mode-07542", device, info_loc.dot(Field::mode), "is %s.",
string_VkCopyMicromapModeEXT(pInfo->mode));
}
if (!pInfo->dst.hostAddress) {
skip |= LogError("VUID-vkCopyMicromapToMemoryEXT-pInfo-07569", device, info_loc.dot(Field::dst).dot(Field::hostAddress),
"is zero.");
} else if (!IsPointerAligned(pInfo->dst.hostAddress, 16)) {
skip |= LogError("VUID-vkCopyMicromapToMemoryEXT-pInfo-07570", device, info_loc.dot(Field::dst).dot(Field::hostAddress),
"(%p) must be aligned to 16 bytes.", pInfo->dst.hostAddress);
}
return skip;
}
bool Device::manual_PreCallValidateCopyMemoryToMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation,
const VkCopyMemoryToMicromapInfoEXT* pInfo,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapHostCommandsEXT) {
skip |= LogError("VUID-vkCopyMemoryToMicromapEXT-micromapHostCommands-07566", device, error_obj.location,
"micromapHostCommands feature was not enabled.");
}
const Location info_loc = error_obj.location.dot(Field::pInfo);
if (pInfo->mode != VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT) {
skip |= LogError("VUID-VkCopyMemoryToMicromapInfoEXT-mode-07548", device, info_loc.dot(Field::mode), "is %s.",
string_VkCopyMicromapModeEXT(pInfo->mode));
}
if (!pInfo->src.hostAddress) {
skip |= LogError("VUID-vkCopyMemoryToMicromapEXT-pInfo-07563", device, info_loc.dot(Field::src).dot(Field::hostAddress),
"is zero.");
} else if (!IsPointerAligned(pInfo->src.hostAddress, 16)) {
skip |= LogError("VUID-vkCopyMemoryToMicromapEXT-pInfo-07564", device, info_loc.dot(Field::src).dot(Field::hostAddress),
"(%p) must be aligned to 16 bytes.", pInfo->src.hostAddress);
}
return skip;
}
bool Device::manual_PreCallValidateWriteMicromapsPropertiesEXT(VkDevice device, uint32_t micromapCount,
const VkMicromapEXT* pMicromaps, VkQueryType queryType,
size_t dataSize, void* pData, size_t stride,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (queryType != VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT && queryType != VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT) {
skip |= LogError("VUID-vkWriteMicromapsPropertiesEXT-queryType-07503", device, error_obj.location, "is %s.",
string_VkQueryType(queryType));
}
return skip;
}
bool Device::manual_PreCallValidateCmdCopyMicromapEXT(VkCommandBuffer commandBuffer, const VkCopyMicromapInfoEXT* pInfo,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
const Location info_loc = error_obj.location.dot(Field::pInfo);
if (pInfo->mode != VK_COPY_MICROMAP_MODE_COMPACT_EXT && pInfo->mode != VK_COPY_MICROMAP_MODE_CLONE_EXT) {
skip |= LogError("VUID-VkCopyMicromapInfoEXT-mode-07531", commandBuffer, info_loc.dot(Field::mode), "is %s.",
string_VkCopyMicromapModeEXT(pInfo->mode));
}
return skip;
}
bool Device::manual_PreCallValidateCmdCopyMicromapToMemoryEXT(VkCommandBuffer commandBuffer,
const VkCopyMicromapToMemoryInfoEXT* pInfo,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
const Location info_loc = error_obj.location.dot(Field::pInfo);
if (pInfo->mode != VK_COPY_MICROMAP_MODE_SERIALIZE_EXT) {
skip |= LogError("VUID-VkCopyMicromapToMemoryInfoEXT-mode-07542", commandBuffer, info_loc.dot(Field::mode), "is %s.",
string_VkCopyMicromapModeEXT(pInfo->mode));
}
if (pInfo->dst.deviceAddress == 0) {
skip |= LogError("VUID-vkCmdCopyMicromapToMemoryEXT-pInfo-07536", device,
info_loc.dot(Field::dst).dot(Field::deviceAddress), "is NULL.");
} else if (!IsPointerAligned(pInfo->dst.deviceAddress, 256)) {
skip |=
LogError("VUID-vkCmdCopyMicromapToMemoryEXT-pInfo-07537", device, info_loc.dot(Field::dst).dot(Field::deviceAddress),
"(0x%" PRIx64 ") must be aligned to 256 bytes.", pInfo->dst.deviceAddress);
}
return skip;
}
bool Device::manual_PreCallValidateCmdCopyMemoryToMicromapEXT(VkCommandBuffer commandBuffer,
const VkCopyMemoryToMicromapInfoEXT* pInfo,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
const Location info_loc = error_obj.location.dot(Field::pInfo);
if (pInfo->mode != VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT) {
skip |= LogError("VUID-VkCopyMemoryToMicromapInfoEXT-mode-07548", commandBuffer, info_loc.dot(Field::mode), "is %s.",
string_VkCopyMicromapModeEXT(pInfo->mode));
}
if (pInfo->src.deviceAddress == 0) {
skip |= LogError("VUID-vkCmdCopyMemoryToMicromapEXT-pInfo-07543", device,
info_loc.dot(Field::src).dot(Field::deviceAddress), "is NULL.");
} else if (!IsPointerAligned(pInfo->src.deviceAddress, 256)) {
skip |=
LogError("VUID-vkCmdCopyMemoryToMicromapEXT-pInfo-07544", device, info_loc.dot(Field::src).dot(Field::deviceAddress),
"(0x%" PRIx64 ") must be aligned to 256 bytes.", pInfo->src.deviceAddress);
}
return skip;
}
bool Device::manual_PreCallValidateCmdWriteMicromapsPropertiesEXT(VkCommandBuffer commandBuffer, uint32_t micromapCount,
const VkMicromapEXT* pMicromaps, VkQueryType queryType,
VkQueryPool queryPool, uint32_t firstQuery,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (queryType != VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT && queryType != VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT) {
skip |= LogError("VUID-vkCmdWriteMicromapsPropertiesEXT-queryType-07503", commandBuffer, error_obj.location, "is %s.",
string_VkQueryType(queryType));
}
return skip;
}
bool Device::manual_PreCallValidateGetDeviceMicromapCompatibilityEXT(VkDevice device, const VkMicromapVersionInfoEXT* pVersionInfo,
VkAccelerationStructureCompatibilityKHR* pCompatibility,
const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapEXT) {
skip |= LogError("VUID-vkGetDeviceMicromapCompatibilityEXT-micromap-11666", device, error_obj.location,
"The VkPhysicalDeviceOpacityMicromapFeaturesEXT::micromap feature was not enabled.");
}
return skip;
}
bool Device::manual_PreCallValidateGetMicromapBuildSizesEXT(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType,
const VkMicromapBuildInfoEXT* pBuildInfo,
VkMicromapBuildSizesInfoEXT* pSizeInfo, const Context& context) const {
bool skip = false;
const auto& error_obj = context.error_obj;
if (!enabled_features.micromapEXT) {
skip |= LogError("VUID-vkGetMicromapBuildSizesEXT-micromap-11618", device, error_obj.location,
"The VkPhysicalDeviceOpacityMicromapFeaturesEXT::micromap feature was not enabled.");
}
skip |= ValidateMicromapBuildInfo(context, *pBuildInfo, error_obj.location.dot(Field::pBuildInfo));
return skip;
}
} // namespace stateless