1 /* Copyright (c) 2015-2021 The Khronos Group Inc.
2 * Copyright (c) 2015-2021 Valve Corporation
3 * Copyright (c) 2015-2021 LunarG, Inc.
4 * Copyright (C) 2015-2021 Google Inc.
5 * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * Author: Courtney Goeltzenleuchter <courtneygo@google.com>
20 * Author: Tobin Ehlis <tobine@google.com>
21 * Author: Chris Forbes <chrisf@ijw.co.nz>
22 * Author: Mark Lobodzinski <mark@lunarg.com>
23 * Author: Dave Houlton <daveh@lunarg.com>
24 * Author: John Zulauf <jzulauf@lunarg.com>
25 * Author: Tobias Hector <tobias.hector@amd.com>
26 * Author: Jeremy Gebben <jeremyg@lunarg.com>
27 */
28 #pragma once
29 #include "hash_vk_types.h"
30 #include "base_node.h"
31 #include "sampler_state.h"
32 #include "ray_tracing_state.h"
33 #include "render_pass_state.h"
34 #include "shader_module.h"
35
36 // Fwd declarations -- including descriptor_set.h creates an ugly include loop
37 namespace cvdescriptorset {
38 class DescriptorSetLayoutDef;
39 class DescriptorSetLayout;
40 class DescriptorSet;
41 class Descriptor;
42
43 } // namespace cvdescriptorset
44
45 class ValidationStateTracker;
46 class CMD_BUFFER_STATE;
47 class RENDER_PASS_STATE;
48 struct SHADER_MODULE_STATE;
49 class PIPELINE_STATE;
50
51 // Flags describing requirements imposed by the pipeline on a descriptor. These
52 // can't be checked at pipeline creation time as they depend on the Image or
53 // ImageView bound.
54 enum DescriptorReqBits {
55 DESCRIPTOR_REQ_VIEW_TYPE_1D = 1 << VK_IMAGE_VIEW_TYPE_1D,
56 DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY = 1 << VK_IMAGE_VIEW_TYPE_1D_ARRAY,
57 DESCRIPTOR_REQ_VIEW_TYPE_2D = 1 << VK_IMAGE_VIEW_TYPE_2D,
58 DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY = 1 << VK_IMAGE_VIEW_TYPE_2D_ARRAY,
59 DESCRIPTOR_REQ_VIEW_TYPE_3D = 1 << VK_IMAGE_VIEW_TYPE_3D,
60 DESCRIPTOR_REQ_VIEW_TYPE_CUBE = 1 << VK_IMAGE_VIEW_TYPE_CUBE,
61 DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY = 1 << VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
62
63 DESCRIPTOR_REQ_ALL_VIEW_TYPE_BITS = (1 << (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY + 1)) - 1,
64
65 DESCRIPTOR_REQ_SINGLE_SAMPLE = 2 << VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
66 DESCRIPTOR_REQ_MULTI_SAMPLE = DESCRIPTOR_REQ_SINGLE_SAMPLE << 1,
67
68 DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT = DESCRIPTOR_REQ_MULTI_SAMPLE << 1,
69 DESCRIPTOR_REQ_COMPONENT_TYPE_SINT = DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT << 1,
70 DESCRIPTOR_REQ_COMPONENT_TYPE_UINT = DESCRIPTOR_REQ_COMPONENT_TYPE_SINT << 1,
71
72 DESCRIPTOR_REQ_VIEW_ATOMIC_OPERATION = DESCRIPTOR_REQ_COMPONENT_TYPE_UINT << 1,
73 DESCRIPTOR_REQ_SAMPLER_IMPLICITLOD_DREF_PROJ = DESCRIPTOR_REQ_VIEW_ATOMIC_OPERATION << 1,
74 DESCRIPTOR_REQ_SAMPLER_BIAS_OFFSET = DESCRIPTOR_REQ_SAMPLER_IMPLICITLOD_DREF_PROJ << 1,
75
76 };
77 typedef uint32_t DescriptorReqFlags;
78
79 extern DescriptorReqFlags DescriptorRequirementsBitsFromFormat(VkFormat fmt);
80
81 struct DescriptorRequirement {
82 DescriptorReqFlags reqs;
83 bool is_writable;
84 // Copy from StageState.interface_var. It combines from plural shader stages. The index of array is index of image.
85 std::vector<layer_data::unordered_set<SamplerUsedByImage>> samplers_used_by_image;
DescriptorRequirementDescriptorRequirement86 DescriptorRequirement() : reqs(0), is_writable(false) {}
87 };
88
89 inline bool operator==(const DescriptorRequirement &a, const DescriptorRequirement &b) NOEXCEPT { return a.reqs == b.reqs; }
90
91 inline bool operator<(const DescriptorRequirement &a, const DescriptorRequirement &b) NOEXCEPT { return a.reqs < b.reqs; }
92
93 typedef std::map<uint32_t, DescriptorRequirement> BindingReqMap;
94
95 // Canonical dictionary for the pipeline layout's layout of descriptorsetlayouts
96 using DescriptorSetLayoutDef = cvdescriptorset::DescriptorSetLayoutDef;
97 using DescriptorSetLayoutId = std::shared_ptr<const DescriptorSetLayoutDef>;
98 using PipelineLayoutSetLayoutsDef = std::vector<DescriptorSetLayoutId>;
99 using PipelineLayoutSetLayoutsDict =
100 hash_util::Dictionary<PipelineLayoutSetLayoutsDef, hash_util::IsOrderedContainer<PipelineLayoutSetLayoutsDef>>;
101 using PipelineLayoutSetLayoutsId = PipelineLayoutSetLayoutsDict::Id;
102
103 // Canonical dictionary for PushConstantRanges
104 using PushConstantRangesDict = hash_util::Dictionary<PushConstantRanges>;
105 using PushConstantRangesId = PushConstantRangesDict::Id;
106
107 // Defines/stores a compatibility defintion for set N
108 // The "layout layout" must store at least set+1 entries, but only the first set+1 are considered for hash and equality testing
109 // Note: the "cannonical" data are referenced by Id, not including handle or device specific state
110 // Note: hash and equality only consider layout_id entries [0, set] for determining uniqueness
111 struct PipelineLayoutCompatDef {
112 uint32_t set;
113 PushConstantRangesId push_constant_ranges;
114 PipelineLayoutSetLayoutsId set_layouts_id;
PipelineLayoutCompatDefPipelineLayoutCompatDef115 PipelineLayoutCompatDef(const uint32_t set_index, const PushConstantRangesId pcr_id, const PipelineLayoutSetLayoutsId sl_id)
116 : set(set_index), push_constant_ranges(pcr_id), set_layouts_id(sl_id) {}
117 size_t hash() const;
118 bool operator==(const PipelineLayoutCompatDef &other) const;
119 };
120
121 // Canonical dictionary for PipelineLayoutCompat records
122 using PipelineLayoutCompatDict = hash_util::Dictionary<PipelineLayoutCompatDef, hash_util::HasHashMember<PipelineLayoutCompatDef>>;
123 using PipelineLayoutCompatId = PipelineLayoutCompatDict::Id;
124
125 // Store layouts and pushconstants for PipelineLayout
126 class PIPELINE_LAYOUT_STATE : public BASE_NODE {
127 public:
128 using SetLayoutVector = std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>>;
129 const SetLayoutVector set_layouts;
130 // canonical form IDs for the "compatible for set" contents
131 const PushConstantRangesId push_constant_ranges;
132 // table of "compatible for set N" cannonical forms for trivial accept validation
133 const std::vector<PipelineLayoutCompatId> compat_for_set;
134
135 PIPELINE_LAYOUT_STATE(ValidationStateTracker *dev_data, VkPipelineLayout l, const VkPipelineLayoutCreateInfo *pCreateInfo);
136
layout()137 VkPipelineLayout layout() const { return handle_.Cast<VkPipelineLayout>(); }
138
GetDsl(uint32_t set)139 std::shared_ptr<cvdescriptorset::DescriptorSetLayout const> GetDsl(uint32_t set) const {
140 std::shared_ptr<cvdescriptorset::DescriptorSetLayout const> dsl = nullptr;
141 if (set < set_layouts.size()) {
142 dsl = set_layouts[set];
143 }
144 return dsl;
145 }
146 };
147
148 struct PipelineStageState {
149 std::shared_ptr<const SHADER_MODULE_STATE> module;
150 const VkPipelineShaderStageCreateInfo *create_info;
151 VkShaderStageFlagBits stage_flag;
152 spirv_inst_iter entrypoint;
153 layer_data::unordered_set<uint32_t> accessible_ids;
154 using DescriptorUse = std::pair<DescriptorSlot, interface_var>;
155 std::vector<DescriptorUse> descriptor_uses;
156 bool has_writable_descriptor;
157 bool has_atomic_descriptor;
158 bool wrote_primitive_shading_rate;
159
160 PipelineStageState(const VkPipelineShaderStageCreateInfo *stage, std::shared_ptr<const SHADER_MODULE_STATE> &module);
161 };
162
163 class PIPELINE_STATE : public BASE_NODE {
164 public:
165 union CreateInfo {
CreateInfo(const VkGraphicsPipelineCreateInfo * ci,std::shared_ptr<const RENDER_PASS_STATE> rpstate)166 CreateInfo(const VkGraphicsPipelineCreateInfo *ci, std::shared_ptr<const RENDER_PASS_STATE> rpstate) {
167 bool use_color = false;
168 bool use_depth = false;
169
170 if (ci->renderPass == VK_NULL_HANDLE) {
171 auto dynamic_rendering = LvlFindInChain<VkPipelineRenderingCreateInfoKHR>(ci->pNext);
172 if (dynamic_rendering) {
173 use_color = (dynamic_rendering->colorAttachmentCount > 0);
174 use_depth = (dynamic_rendering->depthAttachmentFormat != VK_FORMAT_UNDEFINED);
175 }
176 } else {
177 use_color = rpstate->UsesColorAttachment(ci->subpass);
178 use_depth = rpstate->UsesDepthStencilAttachment(ci->subpass);
179 }
180
181 graphics.initialize(ci, use_color, use_depth);
182 }
CreateInfo(const VkComputePipelineCreateInfo * ci)183 CreateInfo(const VkComputePipelineCreateInfo *ci) : compute(ci) {}
CreateInfo(const VkRayTracingPipelineCreateInfoKHR * ci)184 CreateInfo(const VkRayTracingPipelineCreateInfoKHR *ci) : raytracing(ci) {}
CreateInfo(const VkRayTracingPipelineCreateInfoNV * ci)185 CreateInfo(const VkRayTracingPipelineCreateInfoNV *ci) : raytracing(ci) {}
186
~CreateInfo()187 ~CreateInfo() {
188 switch (graphics.sType) {
189 case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO:
190 graphics.~safe_VkGraphicsPipelineCreateInfo();
191 break;
192 case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO:
193 compute.~safe_VkComputePipelineCreateInfo();
194 break;
195 case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV:
196 case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR:
197 raytracing.~safe_VkRayTracingPipelineCreateInfoCommon();
198 break;
199 default:
200 assert(false);
201 break;
202 }
203 }
204
205 safe_VkGraphicsPipelineCreateInfo graphics;
206 safe_VkComputePipelineCreateInfo compute;
207 safe_VkRayTracingPipelineCreateInfoCommon raytracing;
208 };
209 const CreateInfo create_info;
210 std::shared_ptr<const PIPELINE_LAYOUT_STATE> pipeline_layout;
211 std::shared_ptr<const RENDER_PASS_STATE> rp_state;
212 // Additional metadata needed by pipeline_state initialization and validation
213 using StageStateVec = std::vector<PipelineStageState>;
214 const StageStateVec stage_state;
215
216 // Capture which slots (set#->bindings) are actually used by the shaders of this pipeline
217 using ActiveSlotMap = layer_data::unordered_map<uint32_t, BindingReqMap>;
218 // NOTE: this map is 'almost' const and used in performance critical code paths.
219 // The values of existing entries in the DescriptorRequirement::samplers_used_by_image map
220 // are updated at various times. Locking requirements are TBD.
221 const ActiveSlotMap active_slots;
222 const uint32_t max_active_slot = 0; // the highest set number in active_slots for pipeline layout compatibility checks
223
224 const layer_data::unordered_set<uint32_t> fragmentShader_writable_output_location_list;
225 // Vtx input info (if any)
226 using VertexBindingVector = std::vector<VkVertexInputBindingDescription>;
227 const VertexBindingVector vertex_binding_descriptions_;
228
229 using VertexAttrVector = std::vector<VkVertexInputAttributeDescription>;
230 const VertexAttrVector vertex_attribute_descriptions_;
231
232 using VertexAttrAlignmentVector = std::vector<VkDeviceSize>;
233 const VertexAttrAlignmentVector vertex_attribute_alignments_;
234
235 using VertexBindingIndexMap = layer_data::unordered_map<uint32_t, uint32_t>;
236 const VertexBindingIndexMap vertex_binding_to_index_map_;
237
238 using AttachmentVector = std::vector<VkPipelineColorBlendAttachmentState>;
239 const AttachmentVector attachments;
240
241 const bool blend_constants_enabled; // Blend constants enabled for any attachments
242 const bool sample_location_enabled;
243 // Flag of which shader stages are active for this pipeline
244 const uint32_t active_shaders = 0;
245 const VkPrimitiveTopology topology_at_rasterizer;
246
247 PIPELINE_STATE(const ValidationStateTracker *state_data, const VkGraphicsPipelineCreateInfo *pCreateInfo,
248 std::shared_ptr<const RENDER_PASS_STATE> &&rpstate, std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout);
249
250 PIPELINE_STATE(const ValidationStateTracker *state_data, const VkComputePipelineCreateInfo *pCreateInfo,
251 std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout);
252
253 template <typename CreateInfoStruct>
254 PIPELINE_STATE(const ValidationStateTracker *state_data, const CreateInfoStruct *pCreateInfo,
255 std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout);
256
pipeline()257 VkPipeline pipeline() const { return handle_.Cast<VkPipeline>(); }
258
SetHandle(VkPipeline p)259 void SetHandle(VkPipeline p) { handle_.handle = CastToUint64(p); }
260
GetPipelineType()261 inline VkPipelineBindPoint GetPipelineType() const {
262 switch (create_info.graphics.sType) {
263 case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO:
264 return VK_PIPELINE_BIND_POINT_GRAPHICS;
265 case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO:
266 return VK_PIPELINE_BIND_POINT_COMPUTE;
267 case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV:
268 return VK_PIPELINE_BIND_POINT_RAY_TRACING_NV;
269 case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR:
270 return VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
271 default:
272 assert(false);
273 return VK_PIPELINE_BIND_POINT_MAX_ENUM;
274 }
275 }
276
GetPipelineCreateFlags()277 inline VkPipelineCreateFlags GetPipelineCreateFlags() const {
278 switch (create_info.graphics.sType) {
279 case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO:
280 return create_info.graphics.flags;
281 case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO:
282 return create_info.compute.flags;
283 case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV:
284 case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR:
285 return create_info.raytracing.flags;
286 default:
287 assert(false);
288 return 0;
289 }
290 }
291 };
292
293 // Track last states that are bound per pipeline bind point (Gfx & Compute)
294 struct LAST_BOUND_STATE {
LAST_BOUND_STATELAST_BOUND_STATE295 LAST_BOUND_STATE() { Reset(); } // must define default constructor for portability reasons
296 PIPELINE_STATE *pipeline_state;
297 VkPipelineLayout pipeline_layout;
298 std::unique_ptr<cvdescriptorset::DescriptorSet> push_descriptor_set;
299
300 // Ordered bound set tracking where index is set# that given set is bound to
301 struct PER_SET {
PER_SETLAST_BOUND_STATE::PER_SET302 PER_SET()
303 : bound_descriptor_set(nullptr),
304 compat_id_for_set(0),
305 validated_set(nullptr),
306 validated_set_change_count(~0ULL),
307 validated_set_image_layout_change_count(~0ULL),
308 validated_set_binding_req_map() {}
309
310 cvdescriptorset::DescriptorSet *bound_descriptor_set;
311 // one dynamic offset per dynamic descriptor bound to this CB
312 std::vector<uint32_t> dynamicOffsets;
313 PipelineLayoutCompatId compat_id_for_set;
314
315 // Cache most recently validated descriptor state for ValidateCmdBufDrawState/UpdateDrawState
316 const cvdescriptorset::DescriptorSet *validated_set;
317 uint64_t validated_set_change_count;
318 uint64_t validated_set_image_layout_change_count;
319 BindingReqMap validated_set_binding_req_map;
320 };
321
322 std::vector<PER_SET> per_set;
323
324 void Reset();
325
326 void UnbindAndResetPushDescriptorSet(CMD_BUFFER_STATE *cb_state, cvdescriptorset::DescriptorSet *ds);
327
IsUsingLAST_BOUND_STATE328 inline bool IsUsing() const { return pipeline_state ? true : false; }
329 };
330
CompatForSet(uint32_t set,const LAST_BOUND_STATE & a,const std::vector<PipelineLayoutCompatId> & b)331 static inline bool CompatForSet(uint32_t set, const LAST_BOUND_STATE &a, const std::vector<PipelineLayoutCompatId> &b) {
332 bool result = (set < a.per_set.size()) && (set < b.size()) && (a.per_set[set].compat_id_for_set == b[set]);
333 return result;
334 }
335
CompatForSet(uint32_t set,const PIPELINE_LAYOUT_STATE * a,const PIPELINE_LAYOUT_STATE * b)336 static inline bool CompatForSet(uint32_t set, const PIPELINE_LAYOUT_STATE *a, const PIPELINE_LAYOUT_STATE *b) {
337 // Intentionally have a result variable to simplify debugging
338 bool result = a && b && (set < a->compat_for_set.size()) && (set < b->compat_for_set.size()) &&
339 (a->compat_for_set[set] == b->compat_for_set[set]);
340 return result;
341 }
342
343 enum LvlBindPoint {
344 BindPoint_Graphics = VK_PIPELINE_BIND_POINT_GRAPHICS,
345 BindPoint_Compute = VK_PIPELINE_BIND_POINT_COMPUTE,
346 BindPoint_Ray_Tracing = 2,
347 BindPoint_Count = 3,
348 };
349
ConvertToPipelineBindPoint(LvlBindPoint bind_point)350 static VkPipelineBindPoint inline ConvertToPipelineBindPoint(LvlBindPoint bind_point) {
351 switch (bind_point) {
352 case BindPoint_Ray_Tracing:
353 return VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
354 default:
355 return static_cast<VkPipelineBindPoint>(bind_point);
356 }
357 return VK_PIPELINE_BIND_POINT_MAX_ENUM;
358 }
359
ConvertToLvlBindPoint(VkPipelineBindPoint bind_point)360 static LvlBindPoint inline ConvertToLvlBindPoint(VkPipelineBindPoint bind_point) {
361 switch (bind_point) {
362 case VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR:
363 return BindPoint_Ray_Tracing;
364 default:
365 return static_cast<LvlBindPoint>(bind_point);
366 }
367 return BindPoint_Count;
368 }
369