| #!/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 |