blob: f73676f7b3d52b828eb50990a24ee15c23d1011d [file] [log] [blame]
#!/usr/bin/python3 -i
#
# Copyright (c) 2023-2025 The Khronos Group Inc.
# Copyright (c) 2023-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.
import sys
import os
from vulkan_object import Flag
from base_generator import BaseGenerator
separator = ' |\n '
def BitSuffixed(name):
alt_bit = ('_ANDROID', '_EXT', '_IMG', '_KHR', '_NV', '_NVX', '_SYNCVAL')
bit_suf = name + '_BIT'
# Since almost every bit ends with _KHR, just ignore it.
# Otherwise some generated names end up with every other word being KHR.
if name.endswith('_KHR') :
bit_suf = name.replace('_KHR', '_BIT')
else:
for alt in alt_bit:
if name.endswith(alt) :
bit_suf = name.replace(alt, '_BIT' + alt)
break
return bit_suf
def SortSetBasedOnOrder(stage_set, stage_order):
return [ stage for stage in stage_order if stage in stage_set]
class SyncValidationOutputGenerator(BaseGenerator):
def __init__(self):
BaseGenerator.__init__(self)
# List of all stages sorted according to enum numeric value.
# This does not include stages similar to ALL_GRAPHICS that represent multiple stages
self.stages = []
# List of stages obtained from merge-sorting ordered stages from each pipeline type.
# This defines how the stages are are ordered in the ealiest/latest stage bitmask
self.logicallyOrderedStages = []
# pipeline names from <syncpipeline>
self.pipelineNames = []
# < pipeline_name, [pipeline stages in logical order (exactly as defined in XML)] >
self.pipelineStages = dict()
# < pipeline_name, [{ stage : 'stage', ordered: True/False, after : [stages], before : [stages] }] >
# Each stage includes ordering info but also the stages itself are ordered according to
# order/before/after directives. So, if you need iterate over stages from specific pipeline type
# according to all ordering constrains just iterate over the list as asual.
self.pipelineStagesOrdered = dict()
# < queue type, [stages] >
self.queueToStages = dict()
self.stageAccessCombo = []
# fake stages and accesses for acquire present support
self.pipelineStagePresentEngine = Flag('VK_PIPELINE_STAGE_2_PRESENT_ENGINE_BIT_SYNCVAL', [], 0, False, False, None, None, [])
self.accessAcquireRead = Flag('VK_ACCESS_2_PRESENT_ACQUIRE_READ_BIT_SYNCVAL', [], 0, False, False, None, None, [])
self.accessPresented = Flag('VK_ACCESS_2_PRESENT_PRESENTED_BIT_SYNCVAL', [], 0, False, False, None, None, [])
def generate(self):
self.write(f'''// *** THIS FILE IS GENERATED - DO NOT EDIT ***
// See {os.path.basename(__file__)} for modifications
/***************************************************************************
*
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-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
# Set value to be at end of bitmask
self.pipelineStagePresentEngine.value = max([x.value for x in self.vk.bitmasks['VkPipelineStageFlagBits2'].flags]) << 1
self.accessAcquireRead.value = max([x.value for x in self.vk.bitmasks['VkAccessFlagBits2'].flags]) << 1
self.accessPresented.value = max([x.value for x in self.vk.bitmasks['VkAccessFlagBits2'].flags]) << 2
# Add into the VulkanObject so logic works as if they were in the XML
self.vk.bitmasks['VkPipelineStageFlagBits2'].flags.append(self.pipelineStagePresentEngine)
self.vk.bitmasks['VkAccessFlagBits2'].flags.append(self.accessAcquireRead)
self.vk.bitmasks['VkAccessFlagBits2'].flags.append(self.accessPresented)
present_stage = 'VK_PIPELINE_STAGE_2_PRESENT_ENGINE_BIT_SYNCVAL'
# Get stages in logical order
self.logicallyOrderedStages = ['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT']
for pipeline_name in self.pipelineNames:
for index, stage_info in enumerate(self.pipelineStagesOrdered[pipeline_name]):
stage = stage_info['stage']
if stage not in self.logicallyOrderedStages:
later_stages =[s['stage'] for s in self.pipelineStagesOrdered[pipeline_name][index+1:]]
insert_loc = len(self.logicallyOrderedStages)
while insert_loc > 0:
if any(s in self.logicallyOrderedStages[:insert_loc] for s in later_stages):
insert_loc -= 1
else:
break
self.logicallyOrderedStages.insert(insert_loc, stage)
self.logicallyOrderedStages.append('VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT')
self.stages = [x.flag.name for x in self.vk.syncStage if x.equivalent.max]
self.stages.append(present_stage)
# sort self.stages based on VkPipelineStageFlagBits2 bit order
sort_order = {y.name : y.value for y in sorted([x for x in self.vk.bitmasks['VkPipelineStageFlagBits2'].flags], key=lambda x: x.value)}
sort_order['VK_PIPELINE_STAGE_2_NONE'] = -1
self.stages.sort(key=lambda stage: sort_order[stage])
self.stageAccessCombo = self.createStageAccessCombinations()
if self.filename == 'sync_validation_types.h':
self.generateHeader()
elif self.filename == 'sync_validation_types.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 <array>
#include <map>
#include <stdint.h>
#include <vulkan/vulkan.h>
#include "containers/custom_containers.h"
#include "sync/sync_access_flags.h"
''')
out.append('// clang-format off\n')
shader_read_access = next((a for a in self.vk.syncAccess if a.flag.name == 'VK_ACCESS_2_SHADER_READ_BIT'), None)
shader_read_expansion = [e.name for e in shader_read_access.equivalent.accesses]
out.append(f'static constexpr VkAccessFlags2 kShaderReadExpandBits = {"|".join(shader_read_expansion)};\n')
shader_write_access = next((a for a in self.vk.syncAccess if a.flag.name == 'VK_ACCESS_2_SHADER_WRITE_BIT'), None)
shader_write_expansion = [e.name for e in shader_write_access.equivalent.accesses]
out.append(f'static constexpr VkAccessFlags2 kShaderWriteExpandBits = {"|".join(shader_write_expansion)};\n')
all_transfer_stage = next((s for s in self.vk.syncStage if s.flag.name == 'VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT'), None)
all_transfer_expansion = [e.name for e in all_transfer_stage.equivalent.stages]
out.append(f'static constexpr VkPipelineStageFlags2 kAllTransferExpandBits = {"|".join(all_transfer_expansion)};\n')
out.append(f'''
// Fake stages and accesses for acquire present support
static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRESENT_ENGINE_BIT_SYNCVAL = 0x{(self.pipelineStagePresentEngine.value):016X}ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_PRESENT_ACQUIRE_READ_BIT_SYNCVAL = 0x{(self.accessAcquireRead.value):016X}ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_PRESENT_PRESENTED_BIT_SYNCVAL = 0x{(self.accessPresented.value):016X}ULL;
''')
out.append('// Unique number for each stage/access combination\n')
out.append('enum SyncAccessIndex {\n')
for access in self.stageAccessCombo:
out.append(f' {access["stage_access"]} = {access["index"]},\n')
out.append('};\n')
out.append('\n')
out.append('using syncval::SyncAccessFlags;\n');
syncStageAccessFlagsSize = 192
out.append('// Unique bit for each stage/access combination\n')
for access in [x for x in self.stageAccessCombo if x['access_bit'] is not None]:
out.append(f'static const SyncAccessFlags {access["access_bit"]} = (SyncAccessFlags(1) << {access["stage_access"]});\n')
if len(self.stageAccessCombo) > syncStageAccessFlagsSize:
print("The bitset is too small, errors will occur, need to increase syncStageAccessFlagsSize\n")
sys.exit(1)
out.append(f'''
struct SyncAccessInfo {{
const char *name;
VkPipelineStageFlagBits2 stage_mask;
VkAccessFlagBits2 access_mask;
SyncAccessIndex access_index;
SyncAccessFlags access_bit;
}};
// Array of text names and component masks for each stage/access index
const std::array<SyncAccessInfo, {len(self.stageAccessCombo)}>& GetSyncAccessInfos();
''')
out.append('// Constants defining the mask of all read and write access states\n')
out.append('static const SyncAccessFlags syncAccessReadMask = ( // Mask of all read accesses\n')
read_list = [x['access_bit'] for x in self.stageAccessCombo if x['is_read'] is not None and x['is_read'] == 'true']
out.append(' ')
out.append(' |\n '.join(read_list))
out.append('\n);')
out.append('\n\n')
out.append('static const SyncAccessFlags syncAccessWriteMask = ( // Mask of all write accesses\n')
write_list = [x['access_bit'] for x in self.stageAccessCombo if x['is_read'] is not None and x['is_read'] != 'true']
out.append(' ')
out.append(' |\n '.join(write_list))
out.append('\n);\n')
out.append('''
// Bit order mask of accesses for each stage. Order matters, don't try to use vvl::unordered_map
const std::map<VkPipelineStageFlagBits2, SyncAccessFlags>& syncAccessMaskByStageBit();
// Bit order mask of accesses for each VkAccess. Order matters, don't try to use vvl::unordered_map
const std::map<VkAccessFlagBits2, SyncAccessFlags>& syncAccessMaskByAccessBit();
// Direct VkPipelineStageFlags to valid VkAccessFlags lookup table
const vvl::unordered_map<VkPipelineStageFlagBits2, VkAccessFlags2>& syncDirectStageToAccessMask();
// Pipeline stages corresponding to VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT for each VkQueueFlagBits
const vvl::unordered_map<VkQueueFlagBits, VkPipelineStageFlags2>& syncAllCommandStagesByQueueFlags();
// Masks of logically earlier stage flags for a given stage flag
const vvl::unordered_map<VkPipelineStageFlagBits2, VkPipelineStageFlags2>& syncLogicallyEarlierStages();
// Masks of logically later stage flags for a given stage flag
const vvl::unordered_map<VkPipelineStageFlagBits2, VkPipelineStageFlags2>& syncLogicallyLaterStages();
''')
out.append('// clang-format on\n')
self.write("".join(out))
def generateSource(self):
out = []
out.append('''
#include "sync_validation_types.h"
''')
# GetSyncAccessInfos
out.append('// clang-format off\n')
out.append(f'const std::array<SyncAccessInfo, {len(self.stageAccessCombo)}>& GetSyncAccessInfos() {{\n')
out.append(f'static const std::array<SyncAccessInfo, {len(self.stageAccessCombo)}> variable = {{ {{\n')
for stageAccess in self.stageAccessCombo:
out.append(f''' {{
{stageAccess["stage_access_string"]},
{stageAccess["stage"]},
{stageAccess["access"]},
{stageAccess["stage_access"]},
{stageAccess["access_bit"] if stageAccess["access_bit"] is not None else "SyncAccessFlags(0)"}
}},
''')
out.append('}};\n')
out.append('return variable;\n')
out.append('}\n')
# syncAccessMaskByStageBit
out.append('const std::map<VkPipelineStageFlagBits2, SyncAccessFlags>& syncAccessMaskByStageBit() {\n')
out.append(' static const std::map<VkPipelineStageFlagBits2, SyncAccessFlags> variable = {\n')
stage_to_stageAccess = {}
for stageAccess_info in self.stageAccessCombo:
stage = stageAccess_info['stage']
if stage == 'VK_PIPELINE_STAGE_2_NONE':
continue
stageAccess_bit = stageAccess_info['access_bit']
stage_to_stageAccess[stage] = stage_to_stageAccess.get(stage, []) + [stageAccess_bit]
stages_in_bit_order = sorted([x for x in self.vk.bitmasks['VkPipelineStageFlagBits2'].flags], key=lambda x: x.value)
for flag in [x for x in stages_in_bit_order if x.name in stage_to_stageAccess]:
out.append(f' {{ {flag.name}, (\n {separator.join(stage_to_stageAccess[flag.name])}\n )}},\n')
out.append(' };\n')
out.append(' return variable;\n')
out.append('}\n\n')
# syncAccessMaskByAccessBit
out.append('const std::map<VkAccessFlagBits2, SyncAccessFlags>& syncAccessMaskByAccessBit() {\n')
out.append(' static const std::map<VkAccessFlagBits2, SyncAccessFlags> variable = {\n')
access_to_stageAccess = {}
for stageAccess_info in self.stageAccessCombo:
access = stageAccess_info['access']
if access == 'VK_ACCESS_2_NONE':
continue
stageAccess_bit = stageAccess_info['access_bit']
access_to_stageAccess[access] = access_to_stageAccess.get(access, []) + [stageAccess_bit]
accesses_in_bit_order = sorted([x for x in self.vk.bitmasks['VkAccessFlagBits2'].flags], key=lambda x: x.value)
for flag in [x for x in accesses_in_bit_order if x.name in access_to_stageAccess]:
out.append(f' {{ {flag.name}, (\n {separator.join(access_to_stageAccess[flag.name])}\n )}},\n')
out.append(' { VK_ACCESS_2_MEMORY_READ_BIT, (\n syncAccessReadMask\n )},\n')
out.append(' { VK_ACCESS_2_MEMORY_WRITE_BIT, (\n syncAccessWriteMask\n )},\n')
out.append(' };\n')
out.append(' return variable;\n')
out.append('}\n\n')
# syncDirectStageToAccessMask
out.append('const vvl::unordered_map<VkPipelineStageFlagBits2, VkAccessFlags2>& syncDirectStageToAccessMask() {\n')
out.append(' static const vvl::unordered_map<VkPipelineStageFlagBits2, VkAccessFlags2> variable = {\n')
stage_to_access = {}
for stageAccess_info in self.stageAccessCombo:
stage = stageAccess_info['stage']
if stage == 'VK_PIPELINE_STAGE_2_NONE':
continue
stage_to_access[stage] = stage_to_access.get(stage, []) + [stageAccess_info['access']]
stages_in_bit_order = sorted([x for x in self.vk.bitmasks['VkPipelineStageFlagBits2'].flags], key=lambda x: x.value)
for flag in [x for x in stages_in_bit_order if x.name in stage_to_access]:
out.append(f' {{ {flag.name}, (\n {separator.join(stage_to_access[flag.name])}\n )}},\n')
out.append(' };\n')
out.append(' return variable;\n')
out.append('}\n\n')
# syncAllCommandStagesByQueueFlags
out.append('const vvl::unordered_map<VkQueueFlagBits, VkPipelineStageFlags2>& syncAllCommandStagesByQueueFlags() {\n')
out.append(' static const vvl::unordered_map<VkQueueFlagBits, VkPipelineStageFlags2> variable = {\n')
ignoreQueueFlag = [
'VK_PIPELINE_STAGE_2_NONE',
'VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT',
'VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT',
'VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT',
'VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT',
]
for queue in [x.name for x in self.vk.bitmasks['VkQueueFlagBits'].flags]:
stages = [x.flag.name for x in self.vk.syncStage if x.support.queues is not None and (queue in x.support.queues) and x.flag.name not in ignoreQueueFlag and x.equivalent.max]
# These are possible for every queue
for s in ['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT', 'VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT']:
if s not in stages:
stages.append(s)
out.append(f' {{ {queue}, (\n {separator.join(stages)}\n )}},\n')
out.append(' };\n')
out.append(' return variable;\n')
out.append('}\n\n')
# syncLogicallyEarlierStages
out.append('const vvl::unordered_map<VkPipelineStageFlagBits2, VkPipelineStageFlags2>& syncLogicallyEarlierStages() {\n')
out.append(' static const vvl::unordered_map<VkPipelineStageFlagBits2, VkPipelineStageFlags2> variable = {\n')
earlier_stages = {}
earlier_stages['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT'] = set(['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT'])
earlier_stages['VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'] = set(['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT', 'VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'])
for stages in self.pipelineStagesOrdered.values():
for i in range(len(stages)):
stage_order = stages[i]
stage = stage_order['stage']
if stage == 'VK_PIPELINE_STAGE_2_HOST_BIT':
continue
if stage not in earlier_stages:
earlier_stages[stage] = set(['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT'])
earlier_stages['VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'].update([stage])
if not stage_order['ordered']:
earlier_stages[stage] = set(['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT'])
else:
earlier_stages[stage].update([s['stage'] for s in stages[:i]])
earlier_stages = { key:SortSetBasedOnOrder(values, self.logicallyOrderedStages) for key, values in earlier_stages.items() }
for stage in self.stages:
if stage in earlier_stages and len(earlier_stages[stage]) > 0:
out.append(f' {{ {stage}, (\n {separator.join(earlier_stages[stage])}\n )}},\n')
out.append(' };\n')
out.append(' return variable;\n')
out.append('}\n\n')
# syncLogicallyLaterStages
out.append('const vvl::unordered_map<VkPipelineStageFlagBits2, VkPipelineStageFlags2>& syncLogicallyLaterStages() {\n')
out.append(' static const vvl::unordered_map<VkPipelineStageFlagBits2, VkPipelineStageFlags2> variable = {\n')
later_stages = {}
later_stages['VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'] = set(['VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'])
later_stages['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT'] = set(['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT', 'VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'])
for stages in self.pipelineStagesOrdered.values():
for i in range(len(stages)):
stage_order = stages[i]
stage = stage_order['stage']
if stage == 'VK_PIPELINE_STAGE_2_HOST_BIT':
continue
if stage not in later_stages:
later_stages[stage] = set(['VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'])
later_stages['VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT'].update([stage])
if not stage_order['ordered']:
later_stages[stage] = set(['VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT'])
else:
later_stages[stage].update([s['stage'] for s in stages[i+1:] if s['ordered']])
later_stages = { key:SortSetBasedOnOrder(values, self.logicallyOrderedStages) for key, values in later_stages.items() }
for stage in self.stages:
if stage in later_stages and len(later_stages[stage]) > 0:
out.append(f' {{ {stage}, (\n {separator.join(later_stages[stage])}\n )}},\n')
out.append(' };\n')
out.append(' return variable;\n')
out.append('}\n\n')
out.append('// clang-format on\n')
self.write("".join(out))
# Gets all <syncpipeline>
# TODO - Use the BaseGenerator's VulkanObject
def genSyncPipeline(self, sync):
BaseGenerator.genSyncPipeline(self, sync)
name = sync.elem.get('name').replace(' ', '_')
# special case for trasfer stage: expand it to primitive transfer operations
if name == 'transfer':
transferExpansion = [
('transfer copy', 'VK_PIPELINE_STAGE_2_COPY_BIT'),
('transfer_resolve', 'VK_PIPELINE_STAGE_2_RESOLVE_BIT'),
('transfer_blit', 'VK_PIPELINE_STAGE_2_BLIT_BIT'),
('transfer_clear', 'VK_PIPELINE_STAGE_2_CLEAR_BIT'),
('transfer_acceleration_structure_copy', 'VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR'),
]
for transfer_pipeline_name, transfer_stage in transferExpansion:
self.pipelineNames.append(transfer_pipeline_name)
self.pipelineStages[transfer_pipeline_name] = []
self.pipelineStagesOrdered[transfer_pipeline_name] = []
for elem in sync.elem.findall('syncpipelinestage'):
stage = elem.text
if stage == 'VK_PIPELINE_STAGE_2_TRANSFER_BIT':
stage = transfer_stage
self.pipelineStages[transfer_pipeline_name].append(stage)
self.pipelineStagesOrdered[transfer_pipeline_name].append({'stage' : stage, 'ordered' : True, 'before' : None, 'after' : None })
# regular case (non-expandable stages)
else:
self.pipelineNames.append(name)
self.pipelineStages[name] = []
self.pipelineStagesOrdered[name] = []
before_list = []
after_list = []
unordered_list = []
for elem in sync.elem.findall('syncpipelinestage'):
stage = elem.text
self.pipelineStages[name].append(stage)
order = elem.get('order')
before = elem.get('before')
after = elem.get('after')
stage_order = {'stage' : stage, 'ordered' : order != 'None', 'before' : None, 'after' : None }
if before is not None:
stage_order['before'] = before
before_list.append(stage_order)
elif after is not None:
stage_order['after'] = after
after_list.append(stage_order)
elif order == 'None':
unordered_list.append(stage_order)
else:
self.pipelineStagesOrdered[name].append(stage_order)
# process ordering directives
for stage_order in before_list:
before_stage = stage_order['before']
before_index = next((i for i, s in enumerate(self.pipelineStagesOrdered[name]) if s['stage'] == before_stage))
self.pipelineStagesOrdered[name].insert(before_index, stage_order)
for stage_order in after_list:
after_stage = stage_order['after']
after_index = next((i for i, s in enumerate(self.pipelineStagesOrdered[name]) if s['stage'] == after_stage))
self.pipelineStagesOrdered[name].insert(after_index + 1, stage_order)
for stage_order in unordered_list:
self.pipelineStagesOrdered[name].append(stage_order)
# Create the stage/access combination from the legal uses of access with stages
def createStageAccessCombinations(self):
index = 1
enum_prefix = 'SYNC_'
stage_accesses = []
none_stage_access = enum_prefix + 'ACCESS_INDEX_NONE'
stage_accesses.append({
'stage_access': none_stage_access,
'stage_access_string' : '"' + none_stage_access + '"',
'access_bit': None,
'index': 0,
'stage': 'VK_PIPELINE_STAGE_2_NONE',
'access': 'VK_ACCESS_2_NONE',
'is_read': None}) #tri-state logic hack...
# < stage, [accesses] >
stageToAccessMap = dict()
stageToAccessMap['VK_PIPELINE_STAGE_2_PRESENT_ENGINE_BIT_SYNCVAL'] = ['VK_ACCESS_2_PRESENT_ACQUIRE_READ_BIT_SYNCVAL', 'VK_ACCESS_2_PRESENT_PRESENTED_BIT_SYNCVAL']
# In general, syncval algorithms work only with 'base' accesses
# and skip aliases/multi-accesses, or expands multi-accesses when necessary
# Create a subset
for access in [x for x in self.vk.syncAccess if x.equivalent.max and not x.support.max]:
for flag in access.support.stages:
if flag.name not in stageToAccessMap:
stageToAccessMap[flag.name] = []
stageToAccessMap[flag.name].append(access.flag.name)
# A special case where compound access should be registered instead of its expansion.
# AS build and micromap build stages use SHADER_READ access directly.
stageToAccessMap['VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR'].append('VK_ACCESS_2_SHADER_READ_BIT')
if 'VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT' in stageToAccessMap:
stageToAccessMap['VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT'].append('VK_ACCESS_2_SHADER_READ_BIT')
for stage in [x for x in self.stages if x in stageToAccessMap]:
mini_stage = stage.lstrip()
if mini_stage.startswith(enum_prefix):
mini_stage = mini_stage.replace(enum_prefix,'')
else:
mini_stage = mini_stage.replace('VK_PIPELINE_STAGE_2_', '')
mini_stage = mini_stage.replace('_BIT_KHR', '')
mini_stage = mini_stage.replace('_BIT', '')
# Because access_stage_table's elements order might be different sometimes.
# It causes the generator creates different code. It needs to be sorted.
stageToAccessMap[stage].sort()
for access in stageToAccessMap[stage]:
mini_access = access.replace('VK_ACCESS_2_', '').replace('_BIT_KHR', '')
mini_access = mini_access.replace('_BIT', '')
stage_access = '_'.join((mini_stage,mini_access))
stage_access = enum_prefix + stage_access
access_bit = BitSuffixed(stage_access)
is_read = stage_access.endswith('_READ') or ( '_READ_' in stage_access)
stage_accesses.append({
'stage_access': stage_access,
'stage_access_string' : '"' + stage_access + '"',
'access_bit': access_bit,
'index': index,
'stage': stage,
'access': access,
'is_read': 'true' if is_read else 'false' })
index += 1
# Add synthetic stage/access
synth_stage_access = [ 'IMAGE_LAYOUT_TRANSITION', 'QUEUE_FAMILY_OWNERSHIP_TRANSFER']
stage = 'VK_PIPELINE_STAGE_2_NONE'
access = 'VK_ACCESS_2_NONE'
for synth in synth_stage_access :
stage_access = enum_prefix + synth
access_bit = BitSuffixed(stage_access)
is_read = False # both ILT and QFO are R/W operations
stage_accesses.append({
'stage_access': stage_access,
'stage_access_string' : '"' + stage_access + '"',
'access_bit': access_bit,
'index': index,
'stage': stage,
'access': access,
'is_read': 'true' if is_read else 'false' })
index += 1
return stage_accesses