blob: ed13fa55ffb68a82d2794ae0470555b029763fd4 [file] [log] [blame]
/* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (C) 2015-2023 Google Inc.
* Modifications Copyright (C) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
* Modifications Copyright (C) 2022 RasterGrid Kft.
*
* 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/vk_enum_string_helper.h>
#include "generated/chassis.h"
#include "core_validation.h"
bool CoreChecks::ValidateRayTracingPipeline(const PIPELINE_STATE &pipeline,
const safe_VkRayTracingPipelineCreateInfoCommon &create_info,
VkPipelineCreateFlags flags, const Location &create_info_loc) const {
bool skip = false;
bool isKHR = create_info_loc.function == Func::vkCreateRayTracingPipelinesKHR;
if (isKHR) {
if (create_info.maxPipelineRayRecursionDepth > phys_dev_ext_props.ray_tracing_props_khr.maxRayRecursionDepth) {
skip |=
LogError("VUID-VkRayTracingPipelineCreateInfoKHR-maxPipelineRayRecursionDepth-03589", device,
create_info_loc.dot(Field::maxPipelineRayRecursionDepth),
"(%" PRIu32
") must be less than or equal to "
"maxRayRecursionDepth (%" PRIu32 ").",
create_info.maxPipelineRayRecursionDepth, phys_dev_ext_props.ray_tracing_props_khr.maxRayRecursionDepth);
}
if (create_info.pLibraryInfo) {
for (uint32_t i = 0; i < create_info.pLibraryInfo->libraryCount; ++i) {
const Location library_info_loc = create_info_loc.dot(Field::pLibraryInfo);
const Location library_loc = library_info_loc.dot(Field::pLibraries, i);
const auto library_pipelinestate = Get<PIPELINE_STATE>(create_info.pLibraryInfo->pLibraries[i]);
const auto &library_create_info = library_pipelinestate->GetCreateInfo<VkRayTracingPipelineCreateInfoKHR>();
if (library_create_info.maxPipelineRayRecursionDepth != create_info.maxPipelineRayRecursionDepth) {
skip |= LogError("VUID-VkRayTracingPipelineCreateInfoKHR-pLibraries-03591", device, library_loc,
"was created with maxPipelineRayRecursionDepth (%" PRIu32 ") which is not equal %s (%" PRIu32
") .",
library_create_info.maxPipelineRayRecursionDepth,
create_info_loc.dot(Field::maxPipelineRayRecursionDepth).Fields().c_str(),
create_info.maxPipelineRayRecursionDepth);
}
if (library_create_info.pLibraryInfo && (library_create_info.pLibraryInterface->maxPipelineRayHitAttributeSize !=
create_info.pLibraryInterface->maxPipelineRayHitAttributeSize ||
library_create_info.pLibraryInterface->maxPipelineRayPayloadSize !=
create_info.pLibraryInterface->maxPipelineRayPayloadSize)) {
skip |= LogError("VUID-VkRayTracingPipelineCreateInfoKHR-pLibraryInfo-03593", device, library_loc,
"was created with maxPipelineRayPayloadSize (%" PRIu32
") and "
"maxPipelineRayHitAttributeSize (%" PRIu32 ") which is not equal to %s values of (%" PRIu32
") and (%" PRIu32 ").",
library_create_info.pLibraryInterface->maxPipelineRayPayloadSize,
library_create_info.pLibraryInterface->maxPipelineRayHitAttributeSize,
create_info_loc.dot(Field::pLibraryInterface).Fields().c_str(),
create_info.pLibraryInterface->maxPipelineRayPayloadSize,
create_info.pLibraryInterface->maxPipelineRayHitAttributeSize);
}
if ((flags & VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR) &&
!(library_create_info.flags & VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR)) {
skip |=
LogError("VUID-VkRayTracingPipelineCreateInfoKHR-flags-03594", device, library_loc,
"was created with %s, which is missing "
"VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR included in %s (%s).",
string_VkPipelineCreateFlags(flags).c_str(), create_info_loc.dot(Field::flags).Fields().c_str(),
string_VkPipelineCreateFlags(library_create_info.flags).c_str());
}
}
}
} else {
if (create_info.maxRecursionDepth > phys_dev_ext_props.ray_tracing_props_nv.maxRecursionDepth) {
skip |= LogError("VUID-VkRayTracingPipelineCreateInfoNV-maxRecursionDepth-03457", device,
create_info_loc.dot(Field::maxRecursionDepth),
"(%" PRIu32
") must be less than or equal to "
"maxRecursionDepth (%" PRIu32 ")",
create_info.maxRecursionDepth, phys_dev_ext_props.ray_tracing_props_nv.maxRecursionDepth);
}
}
const auto *groups = create_info.ptr()->pGroups;
for (uint32_t i = 0; i < pipeline.stage_states.size(); i++) {
StageCreateInfo stage_create_info(&pipeline);
skip |= ValidatePipelineShaderStage(stage_create_info, pipeline.stage_states[i], create_info_loc.dot(Field::pStages, i));
}
if (const auto *pipeline_robustness_info = vku::FindStructInPNextChain<VkPipelineRobustnessCreateInfoEXT>(create_info.pNext);
pipeline_robustness_info) {
skip |= ValidatePipelineRobustnessCreateInfo(pipeline, *pipeline_robustness_info, create_info_loc);
}
if ((create_info.flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) == 0) {
const uint32_t raygen_stages_count = CalcShaderStageCount(pipeline, VK_SHADER_STAGE_RAYGEN_BIT_KHR);
if (raygen_stages_count == 0) {
skip |= LogError(
isKHR ? "VUID-VkRayTracingPipelineCreateInfoKHR-stage-03425" : "VUID-VkRayTracingPipelineCreateInfoNV-stage-06232",
device, create_info_loc,
"The stage member of at least one element of pStages must be VK_SHADER_STAGE_RAYGEN_BIT_KHR.");
}
}
if ((flags & VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR) != 0 &&
(flags & VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR) != 0) {
skip |= LogError("VUID-VkRayTracingPipelineCreateInfoKHR-flags-06546", device, create_info_loc.dot(Field::flags),
"is %s (contains both SKIP_TRIANGLES and SKIP_AABBS).", string_VkPipelineCreateFlags(flags).c_str());
}
for (uint32_t group_index = 0; group_index < create_info.groupCount; group_index++) {
const auto &group = groups[group_index];
const Location &group_loc = create_info_loc.dot(Field::pGroups, group_index);
if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV) {
if (!GroupHasValidIndex(
pipeline, group.generalShader,
VK_SHADER_STAGE_RAYGEN_BIT_NV | VK_SHADER_STAGE_MISS_BIT_NV | VK_SHADER_STAGE_CALLABLE_BIT_NV)) {
skip |= LogError(isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03474"
: "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02413",
device, group_loc.dot(Field::generalShader), "is %" PRIu32 ".", group.generalShader);
}
if (group.anyHitShader != VK_SHADER_UNUSED_NV || group.closestHitShader != VK_SHADER_UNUSED_NV ||
group.intersectionShader != VK_SHADER_UNUSED_NV) {
skip |= LogError(isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03475"
: "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02414",
device, group_loc,
"anyHitShader is %" PRIu32 ", closestHitShader is %" PRIu32 ", intersectionShader is %" PRIu32 ".",
group.anyHitShader, group.closestHitShader, group.intersectionShader);
}
} else if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV) {
if (!GroupHasValidIndex(pipeline, group.intersectionShader, VK_SHADER_STAGE_INTERSECTION_BIT_NV)) {
skip |= LogError(isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03476"
: "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02415",
device, group_loc.dot(Field::intersectionShader), "is %" PRIu32 ".", group.intersectionShader);
}
} else if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV) {
if (group.intersectionShader != VK_SHADER_UNUSED_NV) {
skip |= LogError(isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03477"
: "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02416",
device, group_loc.dot(Field::intersectionShader), "is %" PRIu32 ".", group.intersectionShader);
}
}
if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV ||
group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV) {
if (!GroupHasValidIndex(pipeline, group.anyHitShader, VK_SHADER_STAGE_ANY_HIT_BIT_KHR)) {
skip |= LogError(isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-anyHitShader-03479"
: "VUID-VkRayTracingShaderGroupCreateInfoNV-anyHitShader-02418",
device, group_loc.dot(Field::anyHitShader), "is %" PRIu32 ".", group.anyHitShader);
}
if (!GroupHasValidIndex(pipeline, group.closestHitShader, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)) {
skip |= LogError(isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-closestHitShader-03478"
: "VUID-VkRayTracingShaderGroupCreateInfoNV-closestHitShader-02417",
device, group_loc.dot(Field::closestHitShader), "is %" PRIu32 ".", group.closestHitShader);
}
}
}
return skip;
}
bool CoreChecks::PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
const ErrorObject &error_obj, void *crtpl_state_data) const {
bool skip = StateTracker::PreCallValidateCreateRayTracingPipelinesNV(device, pipelineCache, count, pCreateInfos, pAllocator,
pPipelines, error_obj, crtpl_state_data);
auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_api_state *>(crtpl_state_data);
for (uint32_t i = 0; i < count; i++) {
const PIPELINE_STATE *pipeline = crtpl_state->pipe_state[i].get();
if (!pipeline) {
continue;
}
const Location create_info_loc = error_obj.location.dot(Field::pCreateInfos, i);
using CIType = vvl::base_type<decltype(pCreateInfos)>;
if (pipeline->create_flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
std::shared_ptr<const PIPELINE_STATE> base_pipeline;
const auto bpi = pipeline->BasePipelineIndex<CIType>();
const auto bph = pipeline->BasePipeline<CIType>();
if (bpi != -1) {
base_pipeline = crtpl_state->pipe_state[bpi];
} else if (bph != VK_NULL_HANDLE) {
base_pipeline = Get<PIPELINE_STATE>(bph);
}
if (!base_pipeline || !(base_pipeline->create_flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
skip |= LogError(
"VUID-vkCreateRayTracingPipelinesNV-flags-03416", device, create_info_loc,
"If the flags member of any element of pCreateInfos contains the "
"VK_PIPELINE_CREATE_DERIVATIVE_BIT flag,"
"the base pipeline must have been created with the VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT flag set.");
}
}
skip |= ValidateRayTracingPipeline(*pipeline, pipeline->GetCreateInfo<CIType>(), pCreateInfos[i].flags, create_info_loc);
skip |= ValidateShaderModuleId(*pipeline, create_info_loc);
skip |= ValidatePipelineCacheControlFlags(pCreateInfos[i].flags, create_info_loc.dot(Field::flags),
"VUID-VkRayTracingPipelineCreateInfoNV-pipelineCreationCacheControl-02905");
}
return skip;
}
bool CoreChecks::PreCallValidateCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation,
VkPipelineCache pipelineCache, uint32_t count,
const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
const ErrorObject &error_obj, void *crtpl_state_data) const {
bool skip = StateTracker::PreCallValidateCreateRayTracingPipelinesKHR(
device, deferredOperation, pipelineCache, count, pCreateInfos, pAllocator, pPipelines, error_obj, crtpl_state_data);
auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
for (uint32_t i = 0; i < count; i++) {
const PIPELINE_STATE *pipeline = crtpl_state->pipe_state[i].get();
if (!pipeline) {
continue;
}
const Location create_info_loc = error_obj.location.dot(Field::pCreateInfos, i);
using CIType = vvl::base_type<decltype(pCreateInfos)>;
if (pipeline->create_flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
std::shared_ptr<const PIPELINE_STATE> base_pipeline;
const auto bpi = pipeline->BasePipelineIndex<CIType>();
const auto bph = pipeline->BasePipeline<CIType>();
if (bpi != -1) {
base_pipeline = crtpl_state->pipe_state[bpi];
} else if (bph != VK_NULL_HANDLE) {
base_pipeline = Get<PIPELINE_STATE>(bph);
}
if (!base_pipeline || !(base_pipeline->create_flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
skip |= LogError(
"VUID-vkCreateRayTracingPipelinesKHR-flags-03416", device, create_info_loc,
"If the flags member of any element of pCreateInfos contains the "
"VK_PIPELINE_CREATE_DERIVATIVE_BIT flag,"
"the base pipeline must have been created with the VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT flag set.");
}
}
skip |= ValidateRayTracingPipeline(*pipeline, pipeline->GetCreateInfo<CIType>(), pCreateInfos[i].flags, create_info_loc);
skip |= ValidateShaderModuleId(*pipeline, create_info_loc);
skip |= ValidatePipelineCacheControlFlags(pCreateInfos[i].flags, create_info_loc.dot(Field::flags),
"VUID-VkRayTracingPipelineCreateInfoKHR-pipelineCreationCacheControl-02905");
const auto create_info = pipeline->GetCreateInfo<VkRayTracingPipelineCreateInfoKHR>();
if (create_info.pLibraryInfo) {
constexpr std::array<std::pair<const char *, VkPipelineCreateFlags>, 7> vuid_map = {{
{"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04718", VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR},
{"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04719", VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR},
{"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04720",
VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR},
{"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04721",
VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR},
{"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04722",
VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR},
{"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04723", VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR},
{"VUID-VkRayTracingPipelineCreateInfoKHR-flags-07403", VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT},
}};
bool uses_descriptor_buffer = false;
for (uint32_t j = 0; j < create_info.pLibraryInfo->libraryCount; ++j) {
const Location library_info_loc = create_info_loc.dot(Field::pLibraryInfo);
const Location library_loc = library_info_loc.dot(Field::pLibraries, j);
const auto lib = Get<PIPELINE_STATE>(create_info.pLibraryInfo->pLibraries[j]);
if ((lib->create_flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) == 0) {
skip |= LogError("VUID-VkPipelineLibraryCreateInfoKHR-pLibraries-03381", device, library_loc,
"was created with %s.", string_VkPipelineCreateFlags(lib->create_flags).c_str());
}
for (const auto &pair : vuid_map) {
if (pipeline->create_flags & pair.second) {
if ((lib->create_flags & pair.second) == 0) {
skip |= LogError(pair.first, device, library_loc,
"was created with %s, which is missing %s included in %s (%s).",
string_VkPipelineCreateFlags(lib->create_flags).c_str(),
string_VkPipelineCreateFlags(pair.second).c_str(),
create_info_loc.dot(Field::flags).Fields().c_str(),
string_VkPipelineCreateFlags(pipeline->create_flags).c_str());
}
}
}
if (j == 0) {
uses_descriptor_buffer = lib->descriptor_buffer_mode;
} else if (uses_descriptor_buffer != lib->descriptor_buffer_mode) {
skip |= LogError(
"VUID-VkPipelineLibraryCreateInfoKHR-pLibraries-08096", device, library_loc,
"%s created with VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT which is opopposite of pLibraries[0].",
lib->descriptor_buffer_mode ? "was" : "was not");
break; // no point keep checking as might have many of same error
}
}
}
}
return skip;
}