Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2019-2021 Valve Corporation |
| 3 | * Copyright (c) 2019-2021 LunarG, Inc. |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | * |
| 17 | * Author: John Zulauf <jzulauf@lunarg.com> |
| 18 | * Author: Locke Lin <locke@lunarg.com> |
| 19 | * Author: Jeremy Gebben <jeremyg@lunarg.com> |
| 20 | */ |
| 21 | #include "sync_utils.h" |
| 22 | #include "state_tracker.h" |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 23 | #include "synchronization_validation_types.h" |
| 24 | |
| 25 | namespace sync_utils { |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 26 | static constexpr uint32_t kNumPipelineStageBits = sizeof(VkPipelineStageFlags2KHR) * 8; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 27 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 28 | VkPipelineStageFlags2KHR DisabledPipelineStages(const DeviceFeatures &features) { |
| 29 | VkPipelineStageFlags2KHR result = 0; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 30 | if (!features.core.geometryShader) { |
| 31 | result |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; |
| 32 | } |
| 33 | if (!features.core.tessellationShader) { |
| 34 | result |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; |
| 35 | } |
sfricke-samsung | 828e59d | 2021-08-22 23:20:49 -0700 | [diff] [blame] | 36 | if (!features.conditional_rendering_features.conditionalRendering) { |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 37 | result |= VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT; |
| 38 | } |
| 39 | if (!features.fragment_density_map_features.fragmentDensityMap) { |
| 40 | result |= VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT; |
| 41 | } |
| 42 | if (!features.transform_feedback_features.transformFeedback) { |
| 43 | result |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; |
| 44 | } |
sfricke-samsung | 828e59d | 2021-08-22 23:20:49 -0700 | [diff] [blame] | 45 | if (!features.mesh_shader_features.meshShader) { |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 46 | result |= VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV; |
| 47 | } |
sfricke-samsung | 828e59d | 2021-08-22 23:20:49 -0700 | [diff] [blame] | 48 | if (!features.mesh_shader_features.taskShader) { |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 49 | result |= VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV; |
| 50 | } |
sfricke-samsung | 828e59d | 2021-08-22 23:20:49 -0700 | [diff] [blame] | 51 | if (!features.fragment_shading_rate_features.pipelineFragmentShadingRate && |
| 52 | !features.shading_rate_image_features.shadingRateImage) { |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 53 | result |= VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; |
| 54 | } |
| 55 | // TODO: VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR |
| 56 | // TODO: VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR |
| 57 | return result; |
| 58 | } |
| 59 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 60 | VkPipelineStageFlags2KHR ExpandPipelineStages(VkPipelineStageFlags2KHR stage_mask, VkQueueFlags queue_flags, |
| 61 | const VkPipelineStageFlags2KHR disabled_feature_mask) { |
| 62 | VkPipelineStageFlags2KHR expanded = stage_mask; |
| 63 | |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 64 | if (VK_PIPELINE_STAGE_ALL_COMMANDS_BIT & stage_mask) { |
| 65 | expanded &= ~VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; |
| 66 | for (const auto &all_commands : syncAllCommandStagesByQueueFlags) { |
| 67 | if (all_commands.first & queue_flags) { |
| 68 | expanded |= all_commands.second & ~disabled_feature_mask; |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | if (VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT & stage_mask) { |
| 73 | expanded &= ~VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 74 | // Make sure we don't pull in the HOST stage from expansion, but keep it if set by the caller. |
| 75 | // The syncAllCommandStagesByQueueFlags table includes HOST for all queue types since it is |
| 76 | // allowed but it shouldn't be part of ALL_GRAPHICS |
| 77 | expanded |= |
| 78 | syncAllCommandStagesByQueueFlags.at(VK_QUEUE_GRAPHICS_BIT) & ~disabled_feature_mask & ~VK_PIPELINE_STAGE_HOST_BIT; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 79 | } |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 80 | if (VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR & stage_mask) { |
| 81 | expanded &= ~VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR; |
| 82 | expanded |= VK_PIPELINE_STAGE_2_COPY_BIT_KHR | VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR | VK_PIPELINE_STAGE_2_BLIT_BIT_KHR | |
| 83 | VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR; |
| 84 | } |
| 85 | if (VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR & stage_mask) { |
| 86 | expanded &= ~VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; |
| 87 | expanded |= VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR | VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR; |
| 88 | } |
| 89 | if (VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR & stage_mask) { |
| 90 | expanded &= ~VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR; |
| 91 | expanded |= VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR | VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR | |
| 92 | VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR | VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR; |
| 93 | } |
| 94 | |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 95 | return expanded; |
| 96 | } |
| 97 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 98 | static const auto kShaderReadExpandBits = |
| 99 | VK_ACCESS_2_UNIFORM_READ_BIT_KHR | VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR | VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR; |
| 100 | static const auto kShaderWriteExpandBits = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR; |
| 101 | |
| 102 | VkAccessFlags2KHR ExpandAccessFlags(VkAccessFlags2KHR access_mask) { |
| 103 | VkAccessFlags2KHR expanded = access_mask; |
| 104 | |
| 105 | if (VK_ACCESS_2_SHADER_READ_BIT_KHR & access_mask) { |
| 106 | expanded = expanded & ~VK_ACCESS_2_SHADER_READ_BIT_KHR; |
| 107 | expanded |= kShaderReadExpandBits; |
| 108 | } |
| 109 | |
| 110 | if (VK_ACCESS_2_SHADER_WRITE_BIT_KHR & access_mask) { |
| 111 | expanded = expanded & ~VK_ACCESS_2_SHADER_WRITE_BIT_KHR; |
| 112 | expanded |= kShaderWriteExpandBits; |
| 113 | } |
| 114 | |
| 115 | return expanded; |
| 116 | } |
| 117 | |
| 118 | VkAccessFlags2KHR CompatibleAccessMask(VkPipelineStageFlags2KHR stage_mask) { |
| 119 | VkAccessFlags2KHR result = 0; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 120 | stage_mask = ExpandPipelineStages(stage_mask); |
| 121 | for (size_t i = 0; i < kNumPipelineStageBits; i++) { |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 122 | VkPipelineStageFlags2KHR bit = 1ULL << i; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 123 | if (stage_mask & bit) { |
| 124 | auto access_rec = syncDirectStageToAccessMask.find(bit); |
| 125 | if (access_rec != syncDirectStageToAccessMask.end()) { |
| 126 | result |= access_rec->second; |
| 127 | continue; |
| 128 | } |
| 129 | } |
| 130 | } |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 131 | |
| 132 | // put the meta-access bits back on |
| 133 | if (result & kShaderReadExpandBits) { |
| 134 | result |= VK_ACCESS_2_SHADER_READ_BIT_KHR; |
| 135 | } |
| 136 | |
| 137 | if (result & kShaderWriteExpandBits) { |
| 138 | result |= VK_ACCESS_2_SHADER_WRITE_BIT_KHR; |
| 139 | } |
| 140 | |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 141 | return result; |
| 142 | } |
| 143 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 144 | VkPipelineStageFlags2KHR RelatedPipelineStages(VkPipelineStageFlags2KHR stage_mask, |
| 145 | const std::map<VkPipelineStageFlags2KHR, VkPipelineStageFlags2KHR> &map) { |
| 146 | VkPipelineStageFlags2KHR unscanned = stage_mask; |
| 147 | VkPipelineStageFlags2KHR related = 0; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 148 | for (const auto &entry : map) { |
| 149 | const auto &stage = entry.first; |
| 150 | if (stage & unscanned) { |
| 151 | related = related | entry.second; |
| 152 | unscanned = unscanned & ~stage; |
| 153 | if (!unscanned) break; |
| 154 | } |
| 155 | } |
| 156 | return related; |
| 157 | } |
| 158 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 159 | VkPipelineStageFlags2KHR WithEarlierPipelineStages(VkPipelineStageFlags2KHR stage_mask) { |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 160 | return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyEarlierStages); |
| 161 | } |
| 162 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 163 | VkPipelineStageFlags2KHR WithLaterPipelineStages(VkPipelineStageFlags2KHR stage_mask) { |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 164 | return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyLaterStages); |
| 165 | } |
| 166 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 167 | int GetGraphicsPipelineStageLogicalOrdinal(VkPipelineStageFlags2KHR flag) { |
| 168 | const auto &rec = syncStageOrder.find(flag); |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 169 | if (rec == syncStageOrder.end()) { |
| 170 | return -1; |
| 171 | } |
| 172 | return rec->second; |
| 173 | } |
| 174 | |
| 175 | // The following two functions technically have O(N^2) complexity, but it's for a value of O that's largely |
| 176 | // stable and also rather tiny - this could definitely be rejigged to work more efficiently, but the impact |
| 177 | // on runtime is currently negligible, so it wouldn't gain very much. |
| 178 | // If we add a lot more graphics pipeline stages, this set of functions should be rewritten to accomodate. |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 179 | VkPipelineStageFlags2KHR GetLogicallyEarliestGraphicsPipelineStage(VkPipelineStageFlags2KHR inflags) { |
| 180 | VkPipelineStageFlags2KHR earliest_bit = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 181 | int earliest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(earliest_bit); |
| 182 | |
| 183 | inflags = ExpandPipelineStages(inflags); |
| 184 | for (std::size_t i = 0; i < kNumPipelineStageBits; ++i) { |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 185 | VkPipelineStageFlags2KHR current_flag = (inflags & 0x1ull) << i; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 186 | if (current_flag) { |
| 187 | int new_order = GetGraphicsPipelineStageLogicalOrdinal(current_flag); |
| 188 | if (new_order != -1 && new_order < earliest_bit_order) { |
| 189 | earliest_bit_order = new_order; |
| 190 | earliest_bit = current_flag; |
| 191 | } |
| 192 | } |
| 193 | inflags = inflags >> 1; |
| 194 | } |
| 195 | return earliest_bit; |
| 196 | } |
| 197 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 198 | VkPipelineStageFlags2KHR GetLogicallyLatestGraphicsPipelineStage(VkPipelineStageFlags2KHR inflags) { |
| 199 | VkPipelineStageFlags2KHR latest_bit = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 200 | int latest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(latest_bit); |
| 201 | |
| 202 | inflags = ExpandPipelineStages(inflags); |
| 203 | for (std::size_t i = 0; i < kNumPipelineStageBits; ++i) { |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 204 | VkPipelineStageFlags2KHR current_flag = (inflags & 0x1ull) << i; |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 205 | if (current_flag) { |
| 206 | int new_order = GetGraphicsPipelineStageLogicalOrdinal(current_flag); |
| 207 | if (new_order != -1 && new_order > latest_bit_order) { |
| 208 | latest_bit_order = new_order; |
| 209 | latest_bit = current_flag; |
| 210 | } |
| 211 | } |
| 212 | inflags = inflags >> 1; |
| 213 | } |
| 214 | return latest_bit; |
| 215 | } |
| 216 | |
Jeremy Gebben | 74aa762 | 2020-12-15 11:18:00 -0700 | [diff] [blame] | 217 | // helper to extract the union of the stage masks in all of the barriers |
| 218 | ExecScopes GetGlobalStageMasks(const VkDependencyInfoKHR &dep_info) { |
| 219 | ExecScopes result{}; |
| 220 | for (uint32_t i = 0; i < dep_info.memoryBarrierCount; i++) { |
| 221 | result.src |= dep_info.pMemoryBarriers[i].srcStageMask; |
| 222 | result.dst |= dep_info.pMemoryBarriers[i].dstStageMask; |
| 223 | } |
| 224 | for (uint32_t i = 0; i < dep_info.bufferMemoryBarrierCount; i++) { |
| 225 | result.src |= dep_info.pBufferMemoryBarriers[i].srcStageMask; |
| 226 | result.dst |= dep_info.pBufferMemoryBarriers[i].dstStageMask; |
| 227 | } |
| 228 | for (uint32_t i = 0; i < dep_info.imageMemoryBarrierCount; i++) { |
| 229 | result.src |= dep_info.pImageMemoryBarriers[i].srcStageMask; |
| 230 | result.dst |= dep_info.pImageMemoryBarriers[i].dstStageMask; |
| 231 | } |
| 232 | return result; |
| 233 | } |
| 234 | |
Jeremy Gebben | 40a2294 | 2020-12-22 14:22:06 -0700 | [diff] [blame] | 235 | // Helpers to try to print the shortest string description of masks. |
| 236 | // If the bitmask doesn't use a synchronization2 specific flag, we'll |
| 237 | // print the old strings. There are common code paths where we need |
| 238 | // to print masks as strings and this makes the output less confusing |
| 239 | // for people not using synchronization2. |
| 240 | std::string StringPipelineStageFlags(VkPipelineStageFlags2KHR mask) { |
| 241 | if (mask <= UINT32_MAX) { |
| 242 | return string_VkPipelineStageFlags(mask & UINT32_MAX); |
| 243 | } |
| 244 | return string_VkPipelineStageFlags2KHR(mask); |
| 245 | } |
| 246 | |
| 247 | std::string StringAccessFlags(VkAccessFlags2KHR mask) { |
| 248 | if (mask <= UINT32_MAX) { |
| 249 | return string_VkAccessFlags(mask & UINT32_MAX); |
| 250 | } |
| 251 | return string_VkAccessFlags2KHR(mask); |
| 252 | } |
| 253 | |
Jeremy Gebben | 5f585ae | 2021-02-02 09:03:06 -0700 | [diff] [blame] | 254 | } // namespace sync_utils |