blob: d42ef50dd6a348f0c3721fd0e02c8cf15c50a123 [file] [log] [blame]
#!/usr/bin/python3 -i
#
# Copyright (c) 2021-2025 The Khronos Group Inc.
#
# 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.
import os
import sys
from generators.generator_utils import buildListVUID, getVUID
from vulkan_object import CommandScope
from base_generator import BaseGenerator
#
# CommandValidationOutputGenerator - Generate implicit vkCmd validation for CoreChecks
class CommandValidationOutputGenerator(BaseGenerator):
def __init__(self,
valid_usage_file):
BaseGenerator.__init__(self)
self.valid_vuids = buildListVUID(valid_usage_file)
#
# Called at beginning of processing as file is opened
def generate(self):
self.write(f'''// *** THIS FILE IS GENERATED - DO NOT EDIT ***
// See {os.path.basename(__file__)} for modifications
/***************************************************************************
*
* Copyright (c) 2021-2025 Valve Corporation
* Copyright (c) 2021-2025 LunarG, Inc.
*
* 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.
****************************************************************************/\n''')
self.write('// NOLINTBEGIN') # Wrap for clang-tidy to ignore
if self.filename == 'command_validation.h':
self.generateHeader()
elif self.filename == 'command_validation.cpp':
self.generateSource()
else:
self.write(f'\nFile name {self.filename} has no code to generate\n')
self.write('// NOLINTEND') # Wrap for clang-tidy to ignore
def generateHeader(self):
out = []
out.append('''
#pragma once
#include "generated/error_location_helper.h"
enum class CommandScope { Inside, Outside, Both };
struct CommandValidationInfo {
const char* recording_vuid;
const char* buffer_level_vuid;
VkQueueFlags queue_flags;
const char* queue_vuid;
CommandScope render_pass_scope;
const char* render_pass_vuid;
CommandScope video_coding_scope;
const char* video_coding_vuid;
const char* suspended_vuid;
bool state;
bool action;
bool synchronization;
};
const CommandValidationInfo& GetCommandValidationInfo(vvl::Func command);
''')
self.write("".join(out))
def generateSource(self):
out = []
out.append('''
#include "command_validation.h"
#include "containers/custom_containers.h"
extern const char *kVUIDUndefined;
using Func = vvl::Func;
''')
out.append('// clang-format off\n')
out.append('static const auto &GetCommandValidationTable() {\n')
out.append('static const vvl::unordered_map<Func, CommandValidationInfo> kCommandValidationTable {\n')
for command in [x for x in self.vk.commands.values() if x.name.startswith('vkCmd')]:
out.append(f'{{Func::{command.name}, {{\n')
# recording_vuid
alias_name = command.name if command.alias is None else command.alias
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-commandBuffer-recording')
out.append(f' {vuid},\n')
# buffer_level_vuid
if command.primary and command.secondary:
out.append(' nullptr,\n')
elif command.primary:
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-bufferlevel')
out.append(f' {vuid},\n')
else:
# Currently there is only "primary" or "primary,secondary" in XML
# Hard to predict what might change, so will error out instead if assumption breaks
print('cmdbufferlevel attribute was and not known, need to update generation code')
sys.exit(1)
queue_flags = ' | '.join(command.queues)
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-commandBuffer-cmdpool')
out.append(f' {queue_flags}, {vuid},\n')
# render_pass / render_pass_vuid
renderPassType = 'CommandScope::Both'
vuid = 'kVUIDUndefined' # Only will be a VUID if not BOTH
if command.renderPass is CommandScope.INSIDE:
renderPassType = 'CommandScope::Inside'
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-renderpass')
elif command.renderPass is CommandScope.OUTSIDE:
renderPassType = 'CommandScope::Outside'
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-renderpass')
out.append(f' {renderPassType}, {vuid},\n')
# video_coding / video_coding_vuid
videoCodingType = 'CommandScope::Both'
vuid = 'kVUIDUndefined' # Only will be a VUID if not BOTH
if command.videoCoding is CommandScope.INSIDE:
videoCodingType = 'CommandScope::Inside'
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-videocoding')
elif command.videoCoding is CommandScope.OUTSIDE or command.videoCoding is CommandScope.NONE:
videoCodingType = 'CommandScope::Outside'
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-videocoding')
out.append(f' {videoCodingType}, {vuid},\n')
# command type
is_state = 'true' if 'state' in command.tasks else 'false'
is_action = 'true' if 'action' in command.tasks else 'false'
is_synchronization = 'true' if 'synchronization' in command.tasks else 'false'
vuid = 'kVUIDUndefined'
if is_action == 'true' or is_synchronization == 'true':
vuid = getVUID(self.valid_vuids, f'VUID-{alias_name}-suspended')
out.append(f' {vuid},\n')
out.append(f' {is_state}, {is_action}, {is_synchronization},\n')
out.append('}},\n')
out.append('};\n')
out.append('return kCommandValidationTable;\n')
out.append('}\n')
out.append('// clang-format on\n')
out.append('''
const CommandValidationInfo& GetCommandValidationInfo(vvl::Func command) {
auto info_it = GetCommandValidationTable().find(command);
assert(info_it != GetCommandValidationTable().end());
return info_it->second;
}
''')
self.write("".join(out))