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"
23 #include "synchronization_validation_types.h"
24 
25 namespace sync_utils {
26 static constexpr uint32_t kNumPipelineStageBits = sizeof(VkPipelineStageFlags2KHR) * 8;
27 
DisabledPipelineStages(const DeviceFeatures & features)28 VkPipelineStageFlags2KHR DisabledPipelineStages(const DeviceFeatures &features) {
29     VkPipelineStageFlags2KHR result = 0;
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     }
36     if (!features.conditional_rendering_features.conditionalRendering) {
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     }
45     if (!features.mesh_shader_features.meshShader) {
46         result |= VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV;
47     }
48     if (!features.mesh_shader_features.taskShader) {
49         result |= VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV;
50     }
51     if (!features.fragment_shading_rate_features.pipelineFragmentShadingRate &&
52         !features.shading_rate_image_features.shadingRateImage) {
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 
ExpandPipelineStages(VkPipelineStageFlags2KHR stage_mask,VkQueueFlags queue_flags,const VkPipelineStageFlags2KHR disabled_feature_mask)60 VkPipelineStageFlags2KHR ExpandPipelineStages(VkPipelineStageFlags2KHR stage_mask, VkQueueFlags queue_flags,
61                                               const VkPipelineStageFlags2KHR disabled_feature_mask) {
62     VkPipelineStageFlags2KHR expanded = stage_mask;
63 
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;
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;
79     }
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 
95     return expanded;
96 }
97 
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 
ExpandAccessFlags(VkAccessFlags2KHR access_mask)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 
CompatibleAccessMask(VkPipelineStageFlags2KHR stage_mask)118 VkAccessFlags2KHR CompatibleAccessMask(VkPipelineStageFlags2KHR stage_mask) {
119     VkAccessFlags2KHR result = 0;
120     stage_mask = ExpandPipelineStages(stage_mask);
121     for (size_t i = 0; i < kNumPipelineStageBits; i++) {
122         VkPipelineStageFlags2KHR bit = 1ULL << i;
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     }
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 
141     return result;
142 }
143 
RelatedPipelineStages(VkPipelineStageFlags2KHR stage_mask,const std::map<VkPipelineStageFlags2KHR,VkPipelineStageFlags2KHR> & map)144 VkPipelineStageFlags2KHR RelatedPipelineStages(VkPipelineStageFlags2KHR stage_mask,
145                                                const std::map<VkPipelineStageFlags2KHR, VkPipelineStageFlags2KHR> &map) {
146     VkPipelineStageFlags2KHR unscanned = stage_mask;
147     VkPipelineStageFlags2KHR related = 0;
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 
WithEarlierPipelineStages(VkPipelineStageFlags2KHR stage_mask)159 VkPipelineStageFlags2KHR WithEarlierPipelineStages(VkPipelineStageFlags2KHR stage_mask) {
160     return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyEarlierStages);
161 }
162 
WithLaterPipelineStages(VkPipelineStageFlags2KHR stage_mask)163 VkPipelineStageFlags2KHR WithLaterPipelineStages(VkPipelineStageFlags2KHR stage_mask) {
164     return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyLaterStages);
165 }
166 
GetGraphicsPipelineStageLogicalOrdinal(VkPipelineStageFlags2KHR flag)167 int GetGraphicsPipelineStageLogicalOrdinal(VkPipelineStageFlags2KHR flag) {
168     const auto &rec = syncStageOrder.find(flag);
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.
GetLogicallyEarliestGraphicsPipelineStage(VkPipelineStageFlags2KHR inflags)179 VkPipelineStageFlags2KHR GetLogicallyEarliestGraphicsPipelineStage(VkPipelineStageFlags2KHR inflags) {
180     VkPipelineStageFlags2KHR earliest_bit = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
181     int earliest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(earliest_bit);
182 
183     inflags = ExpandPipelineStages(inflags);
184     for (std::size_t i = 0; i < kNumPipelineStageBits; ++i) {
185         VkPipelineStageFlags2KHR current_flag = (inflags & 0x1ull) << i;
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 
GetLogicallyLatestGraphicsPipelineStage(VkPipelineStageFlags2KHR inflags)198 VkPipelineStageFlags2KHR GetLogicallyLatestGraphicsPipelineStage(VkPipelineStageFlags2KHR inflags) {
199     VkPipelineStageFlags2KHR latest_bit = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
200     int latest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(latest_bit);
201 
202     inflags = ExpandPipelineStages(inflags);
203     for (std::size_t i = 0; i < kNumPipelineStageBits; ++i) {
204         VkPipelineStageFlags2KHR current_flag = (inflags & 0x1ull) << i;
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 
217 // helper to extract the union of the stage masks in all of the barriers
GetGlobalStageMasks(const VkDependencyInfoKHR & dep_info)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 
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.
StringPipelineStageFlags(VkPipelineStageFlags2KHR mask)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 
StringAccessFlags(VkAccessFlags2KHR mask)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 
254 }  // namespace sync_utils
255