blob: d706ba5921df173dc9d6da1744ec6301ecd9ca46 [file] [log] [blame]
/* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (C) 2015-2025 Google Inc.
* Modifications Copyright (C) 2020 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 "spirv_tools_utils.h"
#include "generated/device_features.h"
#include "generated/vk_api_version.h"
#include "generated/vk_extension_helper.h"
#include "utils/hash_util.h"
#include <sstream>
spv_target_env PickSpirvEnv(const APIVersion &api_version, bool spirv_1_4) {
if (api_version >= VK_API_VERSION_1_4) {
return SPV_ENV_VULKAN_1_4;
} else if (api_version >= VK_API_VERSION_1_3) {
return SPV_ENV_VULKAN_1_3;
} else if (api_version >= VK_API_VERSION_1_2) {
return SPV_ENV_VULKAN_1_2;
} else if (api_version >= VK_API_VERSION_1_1) {
if (spirv_1_4) {
return SPV_ENV_VULKAN_1_1_SPIRV_1_4;
} else {
return SPV_ENV_VULKAN_1_1;
}
}
return SPV_ENV_VULKAN_1_0;
}
// Some Vulkan extensions/features are just all done in spirv-val behind optional settings
void AdjustValidatorOptions(const DeviceExtensions &device_extensions, const DeviceFeatures &enabled_features,
spv_target_env spirv_environment, spvtools::ValidatorOptions &out_options, uint32_t *out_hash,
std::string &out_command) {
struct Settings {
bool relax_block_layout;
bool uniform_buffer_standard_layout;
bool scalar_block_layout;
bool workgroup_scalar_block_layout;
bool allow_local_size_id;
bool allow_offset_texture_operand;
bool allow_vulkan_32_bit_bitwise;
} settings;
// VK_KHR_relaxed_block_layout never had a feature bit so just enabling the extension allows relaxed layout
// Was promotoed in Vulkan 1.1 so anyone using Vulkan 1.1 also gets this for free
settings.relax_block_layout = IsExtEnabled(device_extensions.vk_khr_relaxed_block_layout);
// The rest of the settings are controlled from a feature bit, which are set correctly in the state tracking. Regardless of
// Vulkan version used, the feature bit is needed (also described in the spec).
settings.uniform_buffer_standard_layout = enabled_features.uniformBufferStandardLayout == VK_TRUE;
settings.scalar_block_layout = enabled_features.scalarBlockLayout == VK_TRUE;
settings.workgroup_scalar_block_layout = enabled_features.workgroupMemoryExplicitLayoutScalarBlockLayout == VK_TRUE;
settings.allow_local_size_id = enabled_features.maintenance4 == VK_TRUE;
settings.allow_offset_texture_operand = enabled_features.maintenance8 == VK_TRUE;
settings.allow_vulkan_32_bit_bitwise = enabled_features.maintenance9 == VK_TRUE;
std::ostringstream ss;
ss << "spirv-val <input.spv>";
if (settings.relax_block_layout) {
ss << " --relax-block-layout";
out_options.SetRelaxBlockLayout(true);
}
if (settings.uniform_buffer_standard_layout) {
ss << " --uniform-buffer-standard-layout";
out_options.SetUniformBufferStandardLayout(true);
}
if (settings.scalar_block_layout) {
ss << " --scalar-block-layout";
out_options.SetScalarBlockLayout(true);
}
if (settings.workgroup_scalar_block_layout) {
ss << " --workgroup-scalar-block-layout";
out_options.SetWorkgroupScalarBlockLayout(true);
}
if (settings.allow_local_size_id) {
ss << " --allow-localsizeid";
out_options.SetAllowLocalSizeId(true);
}
if (settings.allow_offset_texture_operand) {
ss << " --allow-offset-texture-operand";
out_options.SetAllowOffsetTextureOperand(true);
}
if (settings.allow_vulkan_32_bit_bitwise) {
ss << " --allow-vulkan-32-bit-bitwise";
out_options.SetAllowVulkan32BitBitwise(true);
}
switch (spirv_environment) {
case SPV_ENV_VULKAN_1_4:
ss << " --target-env vulkan1.4";
break;
case SPV_ENV_VULKAN_1_3:
ss << " --target-env vulkan1.3";
break;
case SPV_ENV_VULKAN_1_2:
ss << " --target-env vulkan1.2";
break;
case SPV_ENV_VULKAN_1_1:
ss << " --target-env vulkan1.1";
break;
case SPV_ENV_VULKAN_1_0:
ss << " --target-env vulkan1.0";
break;
default:
break;
}
// Faster validation without friendly names.
out_options.SetFriendlyNames(false);
// The spv_validator_options_t in libspirv.h is hidden so we can't just hash that struct, so instead need to create our own.
if (out_hash) {
*out_hash = hash_util::Hash32(&settings, sizeof(Settings));
}
ss << "\n";
out_command = ss.str();
}