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 #include "pipeline_state.h"
29 #include "descriptor_sets.h"
30 #include "cmd_buffer_state.h"
31 #include "state_tracker.h"
32 #include "shader_module.h"
33 
34 // Dictionary of canonical form of the pipeline set layout of descriptor set layouts
35 static PipelineLayoutSetLayoutsDict pipeline_layout_set_layouts_dict;
36 
37 // Dictionary of canonical form of the "compatible for set" records
38 static PipelineLayoutCompatDict pipeline_layout_compat_dict;
39 
40 static PushConstantRangesDict push_constant_ranges_dict;
41 
hash() const42 size_t PipelineLayoutCompatDef::hash() const {
43     hash_util::HashCombiner hc;
44     // The set number is integral to the CompatDef's distinctiveness
45     hc << set << push_constant_ranges.get();
46     const auto &descriptor_set_layouts = *set_layouts_id.get();
47     for (uint32_t i = 0; i <= set; i++) {
48         hc << descriptor_set_layouts[i].get();
49     }
50     return hc.Value();
51 }
52 
operator ==(const PipelineLayoutCompatDef & other) const53 bool PipelineLayoutCompatDef::operator==(const PipelineLayoutCompatDef &other) const {
54     if ((set != other.set) || (push_constant_ranges != other.push_constant_ranges)) {
55         return false;
56     }
57 
58     if (set_layouts_id == other.set_layouts_id) {
59         // if it's the same set_layouts_id, then *any* subset will match
60         return true;
61     }
62 
63     // They aren't exactly the same PipelineLayoutSetLayouts, so we need to check if the required subsets match
64     const auto &descriptor_set_layouts = *set_layouts_id.get();
65     assert(set < descriptor_set_layouts.size());
66     const auto &other_ds_layouts = *other.set_layouts_id.get();
67     assert(set < other_ds_layouts.size());
68     for (uint32_t i = 0; i <= set; i++) {
69         if (descriptor_set_layouts[i] != other_ds_layouts[i]) {
70             return false;
71         }
72     }
73     return true;
74 }
75 
GetCanonicalId(const uint32_t set_index,const PushConstantRangesId pcr_id,const PipelineLayoutSetLayoutsId set_layouts_id)76 static PipelineLayoutCompatId GetCanonicalId(const uint32_t set_index, const PushConstantRangesId pcr_id,
77                                              const PipelineLayoutSetLayoutsId set_layouts_id) {
78     return pipeline_layout_compat_dict.look_up(PipelineLayoutCompatDef(set_index, pcr_id, set_layouts_id));
79 }
80 
81 // For repeatable sorting, not very useful for "memory in range" search
82 struct PushConstantRangeCompare {
operator ()PushConstantRangeCompare83     bool operator()(const VkPushConstantRange *lhs, const VkPushConstantRange *rhs) const {
84         if (lhs->offset == rhs->offset) {
85             if (lhs->size == rhs->size) {
86                 // The comparison is arbitrary, but avoids false aliasing by comparing all fields.
87                 return lhs->stageFlags < rhs->stageFlags;
88             }
89             // If the offsets are the same then sorting by the end of range is useful for validation
90             return lhs->size < rhs->size;
91         }
92         return lhs->offset < rhs->offset;
93     }
94 };
95 
GetCanonicalId(const VkPipelineLayoutCreateInfo * info)96 static PushConstantRangesId GetCanonicalId(const VkPipelineLayoutCreateInfo *info) {
97     if (!info->pPushConstantRanges) {
98         // Hand back the empty entry (creating as needed)...
99         return push_constant_ranges_dict.look_up(PushConstantRanges());
100     }
101 
102     // Sort the input ranges to ensure equivalent ranges map to the same id
103     std::set<const VkPushConstantRange *, PushConstantRangeCompare> sorted;
104     for (uint32_t i = 0; i < info->pushConstantRangeCount; i++) {
105         sorted.insert(info->pPushConstantRanges + i);
106     }
107 
108     PushConstantRanges ranges;
109     ranges.reserve(sorted.size());
110     for (const auto *range : sorted) {
111         ranges.emplace_back(*range);
112     }
113     return push_constant_ranges_dict.look_up(std::move(ranges));
114 }
115 
GetSetLayouts(ValidationStateTracker * dev_data,const VkPipelineLayoutCreateInfo * pCreateInfo)116 static PIPELINE_LAYOUT_STATE::SetLayoutVector GetSetLayouts(ValidationStateTracker *dev_data,
117                                                             const VkPipelineLayoutCreateInfo *pCreateInfo) {
118     PIPELINE_LAYOUT_STATE::SetLayoutVector set_layouts(pCreateInfo->setLayoutCount);
119 
120     for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; ++i) {
121         set_layouts[i] = dev_data->Get<cvdescriptorset::DescriptorSetLayout>(pCreateInfo->pSetLayouts[i]);
122     }
123     return set_layouts;
124 }
125 
GetCompatForSet(const PIPELINE_LAYOUT_STATE::SetLayoutVector & set_layouts,const PushConstantRangesId & push_constant_ranges)126 static std::vector<PipelineLayoutCompatId> GetCompatForSet(const PIPELINE_LAYOUT_STATE::SetLayoutVector &set_layouts,
127                                                            const PushConstantRangesId &push_constant_ranges) {
128     PipelineLayoutSetLayoutsDef set_layout_ids(set_layouts.size());
129     for (size_t i = 0; i < set_layouts.size(); i++) {
130         set_layout_ids[i] = set_layouts[i]->GetLayoutId();
131     }
132     auto set_layouts_id = pipeline_layout_set_layouts_dict.look_up(set_layout_ids);
133 
134     std::vector<PipelineLayoutCompatId> compat_for_set;
135     compat_for_set.reserve(set_layouts.size());
136 
137     for (uint32_t i = 0; i < set_layouts.size(); i++) {
138         compat_for_set.emplace_back(GetCanonicalId(i, push_constant_ranges, set_layouts_id));
139     }
140     return compat_for_set;
141 }
142 
PIPELINE_LAYOUT_STATE(ValidationStateTracker * dev_data,VkPipelineLayout l,const VkPipelineLayoutCreateInfo * pCreateInfo)143 PIPELINE_LAYOUT_STATE::PIPELINE_LAYOUT_STATE(ValidationStateTracker *dev_data, VkPipelineLayout l,
144                                              const VkPipelineLayoutCreateInfo *pCreateInfo)
145     : BASE_NODE(l, kVulkanObjectTypePipelineLayout),
146       set_layouts(GetSetLayouts(dev_data, pCreateInfo)),
147       push_constant_ranges(GetCanonicalId(pCreateInfo)),
148       compat_for_set(GetCompatForSet(set_layouts, push_constant_ranges)) {}
149 
GetVertexBindingDescriptions(const safe_VkGraphicsPipelineCreateInfo & create_info)150 static PIPELINE_STATE::VertexBindingVector GetVertexBindingDescriptions(const safe_VkGraphicsPipelineCreateInfo &create_info) {
151     PIPELINE_STATE::VertexBindingVector result;
152     if (create_info.pVertexInputState) {
153         const auto vici = create_info.pVertexInputState;
154         if (vici->vertexBindingDescriptionCount) {
155             result.reserve(vici->vertexBindingDescriptionCount);
156             std::copy(vici->pVertexBindingDescriptions, vici->pVertexBindingDescriptions + vici->vertexBindingDescriptionCount,
157                       std::back_inserter(result));
158         }
159     }
160     return result;
161 }
162 
GetVertexBindingMap(const PIPELINE_STATE::VertexBindingVector & bindings)163 static PIPELINE_STATE::VertexBindingIndexMap GetVertexBindingMap(const PIPELINE_STATE::VertexBindingVector &bindings) {
164     PIPELINE_STATE::VertexBindingIndexMap result;
165     for (uint32_t i = 0; i < bindings.size(); i++) {
166         result[bindings[i].binding] = i;
167     }
168     return result;
169 }
170 
GetVertexAttributeDescriptions(const safe_VkGraphicsPipelineCreateInfo & create_info)171 static PIPELINE_STATE::VertexAttrVector GetVertexAttributeDescriptions(const safe_VkGraphicsPipelineCreateInfo &create_info) {
172     PIPELINE_STATE::VertexAttrVector result;
173     if (create_info.pVertexInputState) {
174         const auto vici = create_info.pVertexInputState;
175         if (vici->vertexAttributeDescriptionCount) {
176             result.reserve(vici->vertexAttributeDescriptionCount);
177             std::copy(vici->pVertexAttributeDescriptions,
178                       vici->pVertexAttributeDescriptions + vici->vertexAttributeDescriptionCount, std::back_inserter(result));
179         }
180     }
181     return result;
182 }
183 
GetAttributeAlignments(const PIPELINE_STATE::VertexAttrVector & attributes)184 static PIPELINE_STATE::VertexAttrAlignmentVector GetAttributeAlignments(const PIPELINE_STATE::VertexAttrVector &attributes) {
185     PIPELINE_STATE::VertexAttrAlignmentVector result;
186     result.reserve(attributes.size());
187     for (const auto &attr : attributes) {
188         VkDeviceSize vtx_attrib_req_alignment = FormatElementSize(attr.format);
189         if (FormatElementIsTexel(attr.format)) {
190             vtx_attrib_req_alignment = SafeDivision(vtx_attrib_req_alignment, FormatComponentCount(attr.format));
191         }
192         result.push_back(vtx_attrib_req_alignment);
193     }
194     return result;
195 }
196 
GetAttachments(const safe_VkGraphicsPipelineCreateInfo & create_info)197 static PIPELINE_STATE::AttachmentVector GetAttachments(const safe_VkGraphicsPipelineCreateInfo &create_info) {
198     PIPELINE_STATE::AttachmentVector result;
199     if (create_info.pColorBlendState) {
200         const auto cbci = create_info.pColorBlendState;
201         if (cbci->attachmentCount) {
202             result.reserve(cbci->attachmentCount);
203             std::copy(cbci->pAttachments, cbci->pAttachments + cbci->attachmentCount, std::back_inserter(result));
204         }
205     }
206     return result;
207 }
208 
IsBlendConstantsEnabled(const PIPELINE_STATE::AttachmentVector & attachments)209 static bool IsBlendConstantsEnabled(const PIPELINE_STATE::AttachmentVector &attachments) {
210     bool result = false;
211     for (const auto &attachment : attachments) {
212         if (VK_TRUE == attachment.blendEnable) {
213             if (((attachment.dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
214                  (attachment.dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
215                 ((attachment.dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
216                  (attachment.dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
217                 ((attachment.srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
218                  (attachment.srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
219                 ((attachment.srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
220                  (attachment.srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
221                 result = true;
222                 break;
223             }
224         }
225     }
226     return result;
227 }
228 
IsSampleLocationEnabled(const safe_VkGraphicsPipelineCreateInfo & create_info)229 static bool IsSampleLocationEnabled(const safe_VkGraphicsPipelineCreateInfo &create_info) {
230     bool result = false;
231     if (create_info.pMultisampleState) {
232         const auto *sample_location_state =
233             LvlFindInChain<VkPipelineSampleLocationsStateCreateInfoEXT>(create_info.pMultisampleState->pNext);
234         if (sample_location_state != nullptr) {
235             result = (sample_location_state->sampleLocationsEnable != 0);
236         }
237     }
238     return result;
239 }
240 
HasWriteableDescriptor(const std::vector<PipelineStageState::DescriptorUse> & descriptor_uses)241 static bool HasWriteableDescriptor(const std::vector<PipelineStageState::DescriptorUse> &descriptor_uses) {
242     return std::any_of(descriptor_uses.begin(), descriptor_uses.end(),
243                        [](const PipelineStageState::DescriptorUse &use) { return use.second.is_atomic_operation; });
244 }
245 
HasAtomicDescriptor(const std::vector<PipelineStageState::DescriptorUse> & descriptor_uses)246 static bool HasAtomicDescriptor(const std::vector<PipelineStageState::DescriptorUse> &descriptor_uses) {
247     return std::any_of(descriptor_uses.begin(), descriptor_uses.end(),
248                        [](const PipelineStageState::DescriptorUse &use) { return use.second.is_writable; });
249 }
250 
WrotePrimitiveShadingRate(VkShaderStageFlagBits stage_flag,spirv_inst_iter entrypoint,const SHADER_MODULE_STATE * module)251 static bool WrotePrimitiveShadingRate(VkShaderStageFlagBits stage_flag, spirv_inst_iter entrypoint,
252                                       const SHADER_MODULE_STATE *module) {
253     bool primitiverate_written = false;
254     if (stage_flag == VK_SHADER_STAGE_VERTEX_BIT || stage_flag == VK_SHADER_STAGE_GEOMETRY_BIT ||
255         stage_flag == VK_SHADER_STAGE_MESH_BIT_NV) {
256         for (const auto &set : module->GetBuiltinDecorationList()) {
257             auto insn = module->at(set.offset);
258             if (set.builtin == spv::BuiltInPrimitiveShadingRateKHR) {
259                 primitiverate_written = module->IsBuiltInWritten(insn, entrypoint);
260             }
261             if (primitiverate_written) {
262                 break;
263             }
264         }
265     }
266     return primitiverate_written;
267 }
268 
PipelineStageState(const VkPipelineShaderStageCreateInfo * stage,std::shared_ptr<const SHADER_MODULE_STATE> & module_)269 PipelineStageState::PipelineStageState(const VkPipelineShaderStageCreateInfo *stage,
270                                        std::shared_ptr<const SHADER_MODULE_STATE> &module_)
271     : module(module_),
272       create_info(stage),
273       stage_flag(stage->stage),
274       entrypoint(module->FindEntrypoint(stage->pName, stage->stage)),
275       accessible_ids(module->MarkAccessibleIds(entrypoint)),
276       descriptor_uses(module->CollectInterfaceByDescriptorSlot(accessible_ids)),
277       has_writable_descriptor(HasWriteableDescriptor(descriptor_uses)),
278       has_atomic_descriptor(HasAtomicDescriptor(descriptor_uses)),
279       wrote_primitive_shading_rate(WrotePrimitiveShadingRate(stage_flag, entrypoint, module.get())) {}
280 
GetStageStates(const ValidationStateTracker * state_data,const safe_VkPipelineShaderStageCreateInfo * stages,uint32_t stage_count)281 static PIPELINE_STATE::StageStateVec GetStageStates(const ValidationStateTracker *state_data,
282                                                     const safe_VkPipelineShaderStageCreateInfo *stages, uint32_t stage_count) {
283     PIPELINE_STATE::StageStateVec stage_states;
284     stage_states.reserve(stage_count);
285     // shader stages need to be recorded in pipeline order
286     for (uint32_t stage_idx = 0; stage_idx < 32; ++stage_idx) {
287         for (uint32_t i = 0; i < stage_count; i++) {
288             if (stages[i].stage == (1 << stage_idx)) {
289                 auto module = state_data->Get<SHADER_MODULE_STATE>(stages[i].module);
290                 stage_states.emplace_back(stages[i].ptr(), module);
291             }
292         }
293     }
294     return stage_states;
295 }
296 
GetActiveSlots(const PIPELINE_STATE::StageStateVec & stage_states)297 static PIPELINE_STATE::ActiveSlotMap GetActiveSlots(const PIPELINE_STATE::StageStateVec &stage_states) {
298     PIPELINE_STATE::ActiveSlotMap active_slots;
299     for (const auto &stage : stage_states) {
300         if (stage.entrypoint == stage.module->end()) {
301             continue;
302         }
303         // Capture descriptor uses for the pipeline
304         for (const auto &use : stage.descriptor_uses) {
305             // While validating shaders capture which slots are used by the pipeline
306             auto &entry = active_slots[use.first.set][use.first.binding];
307             entry.is_writable |= use.second.is_writable;
308 
309             auto &reqs = entry.reqs;
310             reqs |= stage.module->DescriptorTypeToReqs(use.second.type_id);
311             if (use.second.is_atomic_operation) reqs |= DESCRIPTOR_REQ_VIEW_ATOMIC_OPERATION;
312             if (use.second.is_sampler_implicitLod_dref_proj) reqs |= DESCRIPTOR_REQ_SAMPLER_IMPLICITLOD_DREF_PROJ;
313             if (use.second.is_sampler_bias_offset) reqs |= DESCRIPTOR_REQ_SAMPLER_BIAS_OFFSET;
314 
315             if (use.second.samplers_used_by_image.size()) {
316                 if (use.second.samplers_used_by_image.size() > entry.samplers_used_by_image.size()) {
317                     entry.samplers_used_by_image.resize(use.second.samplers_used_by_image.size());
318                 }
319                 uint32_t image_index = 0;
320                 for (const auto &samplers : use.second.samplers_used_by_image) {
321                     for (const auto &sampler : samplers) {
322                         entry.samplers_used_by_image[image_index].emplace(sampler);
323                     }
324                     ++image_index;
325                 }
326             }
327         }
328     }
329     return active_slots;
330 }
331 
GetMaxActiveSlot(const PIPELINE_STATE::ActiveSlotMap & active_slots)332 static uint32_t GetMaxActiveSlot(const PIPELINE_STATE::ActiveSlotMap &active_slots) {
333     uint32_t max_active_slot = 0;
334     for (const auto &entry : active_slots) {
335         max_active_slot = std::max(max_active_slot, entry.first);
336     }
337     return max_active_slot;
338 }
339 
GetActiveShaders(const VkPipelineShaderStageCreateInfo * stages,uint32_t stage_count)340 static uint32_t GetActiveShaders(const VkPipelineShaderStageCreateInfo *stages, uint32_t stage_count) {
341     uint32_t result = 0;
342     for (uint32_t i = 0; i < stage_count; i++) {
343         result |= stages[i].stage;
344     }
345     return result;
346 }
347 
GetFSOutputLocations(const PIPELINE_STATE::StageStateVec & stage_states)348 static layer_data::unordered_set<uint32_t> GetFSOutputLocations(const PIPELINE_STATE::StageStateVec &stage_states) {
349     layer_data::unordered_set<uint32_t> result;
350     for (const auto &stage : stage_states) {
351         if (stage.entrypoint == stage.module->end()) {
352             continue;
353         }
354         if (stage.stage_flag == VK_SHADER_STAGE_FRAGMENT_BIT) {
355             result = stage.module->CollectWritableOutputLocationinFS(stage.entrypoint);
356             break;
357         }
358     }
359     return result;
360 }
361 
GetTopologyAtRasterizer(const PIPELINE_STATE::StageStateVec & stage_states,const safe_VkPipelineInputAssemblyStateCreateInfo * assembly_state)362 static VkPrimitiveTopology GetTopologyAtRasterizer(const PIPELINE_STATE::StageStateVec &stage_states,
363                                                    const safe_VkPipelineInputAssemblyStateCreateInfo *assembly_state) {
364     VkPrimitiveTopology result = assembly_state ? assembly_state->topology : static_cast<VkPrimitiveTopology>(0);
365     for (const auto &stage : stage_states) {
366         if (stage.entrypoint == stage.module->end()) {
367             continue;
368         }
369         auto stage_topo = stage.module->GetTopology(stage.entrypoint);
370         if (stage_topo) {
371             result = *stage_topo;
372         }
373     }
374     return result;
375 }
376 
PIPELINE_STATE(const ValidationStateTracker * state_data,const VkGraphicsPipelineCreateInfo * pCreateInfo,std::shared_ptr<const RENDER_PASS_STATE> && rpstate,std::shared_ptr<const PIPELINE_LAYOUT_STATE> && layout)377 PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *state_data, const VkGraphicsPipelineCreateInfo *pCreateInfo,
378                                std::shared_ptr<const RENDER_PASS_STATE> &&rpstate,
379                                std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout)
380     : BASE_NODE(static_cast<VkPipeline>(VK_NULL_HANDLE), kVulkanObjectTypePipeline),
381       create_info(pCreateInfo, rpstate),
382       pipeline_layout(std::move(layout)),
383       rp_state(rpstate),
384       stage_state(GetStageStates(state_data, create_info.graphics.pStages, create_info.graphics.stageCount)),
385       active_slots(GetActiveSlots(stage_state)),
386       max_active_slot(GetMaxActiveSlot(active_slots)),
387       fragmentShader_writable_output_location_list(GetFSOutputLocations(stage_state)),
388       vertex_binding_descriptions_(GetVertexBindingDescriptions(create_info.graphics)),
389       vertex_attribute_descriptions_(GetVertexAttributeDescriptions(create_info.graphics)),
390       vertex_attribute_alignments_(GetAttributeAlignments(vertex_attribute_descriptions_)),
391       vertex_binding_to_index_map_(GetVertexBindingMap(vertex_binding_descriptions_)),
392       attachments(GetAttachments(create_info.graphics)),
393       blend_constants_enabled(IsBlendConstantsEnabled(attachments)),
394       sample_location_enabled(IsSampleLocationEnabled(create_info.graphics)),
395       active_shaders(GetActiveShaders(pCreateInfo->pStages, pCreateInfo->stageCount)),
396       topology_at_rasterizer(GetTopologyAtRasterizer(stage_state, create_info.graphics.pInputAssemblyState)) {}
397 
PIPELINE_STATE(const ValidationStateTracker * state_data,const VkComputePipelineCreateInfo * pCreateInfo,std::shared_ptr<const PIPELINE_LAYOUT_STATE> && layout)398 PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *state_data, const VkComputePipelineCreateInfo *pCreateInfo,
399                                std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout)
400     : BASE_NODE(static_cast<VkPipeline>(VK_NULL_HANDLE), kVulkanObjectTypePipeline),
401       create_info(pCreateInfo),
402       pipeline_layout(std::move(layout)),
403       stage_state(GetStageStates(state_data, &create_info.compute.stage, 1)),
404       active_slots(GetActiveSlots(stage_state)),
405       blend_constants_enabled(false),
406       sample_location_enabled(false),
407       active_shaders(GetActiveShaders(&pCreateInfo->stage, 1)),
408       topology_at_rasterizer{} {
409     assert(active_shaders == VK_SHADER_STAGE_COMPUTE_BIT);
410 }
411 
412 template <typename CreateInfoStruct>
PIPELINE_STATE(const ValidationStateTracker * state_data,const CreateInfoStruct * pCreateInfo,std::shared_ptr<const PIPELINE_LAYOUT_STATE> && layout)413 PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *state_data, const CreateInfoStruct *pCreateInfo,
414                                std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout)
415     : BASE_NODE(static_cast<VkPipeline>(VK_NULL_HANDLE), kVulkanObjectTypePipeline),
416       create_info(pCreateInfo),
417       pipeline_layout(std::move(layout)),
418       stage_state(GetStageStates(state_data, create_info.raytracing.pStages, create_info.raytracing.stageCount)),
419       active_slots(GetActiveSlots(stage_state)),
420       blend_constants_enabled(false),
421       sample_location_enabled(false),
422       active_shaders(GetActiveShaders(pCreateInfo->pStages, pCreateInfo->stageCount)),
423       topology_at_rasterizer{} {
424     assert(0 == (active_shaders &
425                  ~(VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR |
426                    VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR)));
427 }
428 
429 template PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *, const VkRayTracingPipelineCreateInfoNV *,
430                                         std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&);
431 template PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *, const VkRayTracingPipelineCreateInfoKHR *,
432                                         std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&);
433 
UnbindAndResetPushDescriptorSet(CMD_BUFFER_STATE * cb_state,cvdescriptorset::DescriptorSet * ds)434 void LAST_BOUND_STATE::UnbindAndResetPushDescriptorSet(CMD_BUFFER_STATE *cb_state, cvdescriptorset::DescriptorSet *ds) {
435     if (push_descriptor_set) {
436         for (auto &ps : per_set) {
437             if (ps.bound_descriptor_set == push_descriptor_set.get()) {
438                 cb_state->RemoveChild(ps.bound_descriptor_set);
439                 ps.bound_descriptor_set = nullptr;
440             }
441         }
442     }
443     cb_state->AddChild(ds);
444     push_descriptor_set.reset(ds);
445 }
446 
Reset()447 void LAST_BOUND_STATE::Reset() {
448     pipeline_state = nullptr;
449     pipeline_layout = VK_NULL_HANDLE;
450     if (push_descriptor_set) {
451         push_descriptor_set->Reset();
452     }
453     push_descriptor_set = nullptr;
454     per_set.clear();
455 }
456