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