blob: 7f792c07d53f8820b8a3fd66e75d75c535ba6926 [file] [log] [blame]
/* Copyright (c) 2015-2022 The Khronos Group Inc.
* Copyright (c) 2015-2022 Valve Corporation
* Copyright (c) 2015-2022 LunarG, Inc.
* Copyright (C) 2015-2022 Google Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Courtney Goeltzenleuchter <courtneygo@google.com>
* Author: Tobin Ehlis <tobine@google.com>
* Author: Chris Forbes <chrisf@ijw.co.nz>
* Author: Mark Lobodzinski <mark@lunarg.com>
* Author: Dave Houlton <daveh@lunarg.com>
* Author: John Zulauf <jzulauf@lunarg.com>
* Author: Tobias Hector <tobias.hector@amd.com>
* Author: Jeremy Gebben <jeremyg@lunarg.com>
*/
#include "pipeline_state.h"
#include "descriptor_sets.h"
#include "cmd_buffer_state.h"
#include "state_tracker.h"
#include "shader_module.h"
static bool HasWriteableDescriptor(const std::vector<PipelineStageState::DescriptorUse> &descriptor_uses) {
return std::any_of(descriptor_uses.begin(), descriptor_uses.end(),
[](const PipelineStageState::DescriptorUse &use) { return use.second.is_writable; });
}
static bool HasAtomicDescriptor(const std::vector<PipelineStageState::DescriptorUse> &descriptor_uses) {
return std::any_of(descriptor_uses.begin(), descriptor_uses.end(),
[](const PipelineStageState::DescriptorUse &use) { return use.second.is_atomic_operation; });
}
static bool WrotePrimitiveShadingRate(VkShaderStageFlagBits stage_flag, layer_data::optional<Instruction> entrypoint,
const SHADER_MODULE_STATE *module_state) {
bool primitiverate_written = false;
if (entrypoint && (stage_flag == VK_SHADER_STAGE_VERTEX_BIT || stage_flag == VK_SHADER_STAGE_GEOMETRY_BIT ||
stage_flag == VK_SHADER_STAGE_MESH_BIT_NV)) {
for (const Instruction *inst : module_state->GetBuiltinDecorationList()) {
if (inst->GetBuiltIn() == spv::BuiltInPrimitiveShadingRateKHR) {
primitiverate_written = module_state->IsBuiltInWritten(inst, *entrypoint);
}
if (primitiverate_written) {
break;
}
}
}
return primitiverate_written;
}
PipelineStageState::PipelineStageState(const safe_VkPipelineShaderStageCreateInfo *stage,
std::shared_ptr<const SHADER_MODULE_STATE> &module_state)
: module_state(module_state),
create_info(stage),
stage_flag(stage->stage),
entrypoint(module_state->FindEntrypoint(stage->pName, stage->stage)),
accessible_ids(module_state->MarkAccessibleIds(entrypoint)),
descriptor_uses(module_state->CollectInterfaceByDescriptorSlot(accessible_ids)),
has_writable_descriptor(HasWriteableDescriptor(descriptor_uses)),
has_atomic_descriptor(HasAtomicDescriptor(descriptor_uses)),
wrote_primitive_shading_rate(WrotePrimitiveShadingRate(stage_flag, entrypoint, module_state.get())),
writes_to_gl_layer(module_state->WritesToGlLayer()),
has_input_attachment_capability(module_state->HasInputAttachmentCapability()) {}
// static
PIPELINE_STATE::StageStateVec PIPELINE_STATE::GetStageStates(const ValidationStateTracker &state_data,
const PIPELINE_STATE &pipe_state) {
PIPELINE_STATE::StageStateVec stage_states;
// shader stages need to be recorded in pipeline order
const auto stages = pipe_state.GetShaderStages();
for (uint32_t stage_idx = 0; stage_idx < 32; ++stage_idx) {
bool stage_found = false;
// Only cast to a VkShaderStageFlagBits if the result could fit in that enum; otherwise
// that's undefined behavior. See
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4689
if (!((1 << stage_idx) & VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM)) {
continue;
}
const auto stage = static_cast<VkShaderStageFlagBits>(1 << stage_idx);
for (const auto &shader_stage : stages) {
if (shader_stage.stage == stage) {
auto module = state_data.Get<SHADER_MODULE_STATE>(shader_stage.module);
if (!module) {
// If module is null and there is a VkShaderModuleCreateInfo in the pNext chain of the stage info, then this
// module is part of a library and the state must be created
const auto shader_ci = LvlFindInChain<VkShaderModuleCreateInfo>(shader_stage.pNext);
const uint32_t unique_shader_id = 0;
if (shader_ci) {
// TODO GPU-AV rework required to get this value properly
module = state_data.CreateShaderModuleState(*shader_ci, unique_shader_id);
} else {
// shader_module_identifier could legally provide a null module handle
VkShaderModuleCreateInfo dummy_module_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
dummy_module_ci.pCode = &unique_shader_id; // Ensure tripping invalid spirv
module = state_data.CreateShaderModuleState(dummy_module_ci, unique_shader_id);
}
}
stage_states.emplace_back(&shader_stage, module);
stage_found = true;
}
}
if (!stage_found) {
// Check if stage has been supplied by a library
switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT:
if (pipe_state.pre_raster_state && pipe_state.pre_raster_state->vertex_shader) {
stage_states.emplace_back(pipe_state.pre_raster_state->vertex_shader_ci,
pipe_state.pre_raster_state->vertex_shader);
}
break;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
if (pipe_state.pre_raster_state && pipe_state.pre_raster_state->tessc_shader) {
stage_states.emplace_back(pipe_state.pre_raster_state->tessc_shader_ci,
pipe_state.pre_raster_state->tessc_shader);
}
break;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
if (pipe_state.pre_raster_state && pipe_state.pre_raster_state->tesse_shader) {
stage_states.emplace_back(pipe_state.pre_raster_state->tesse_shader_ci,
pipe_state.pre_raster_state->tesse_shader);
}
break;
case VK_SHADER_STAGE_GEOMETRY_BIT:
if (pipe_state.pre_raster_state && pipe_state.pre_raster_state->geometry_shader) {
stage_states.emplace_back(pipe_state.pre_raster_state->geometry_shader_ci,
pipe_state.pre_raster_state->geometry_shader);
}
break;
case VK_SHADER_STAGE_FRAGMENT_BIT:
if (pipe_state.fragment_shader_state && pipe_state.fragment_shader_state->fragment_shader) {
stage_states.emplace_back(pipe_state.fragment_shader_state->fragment_shader_ci.get(),
pipe_state.fragment_shader_state->fragment_shader);
}
break;
default:
// no-op
break;
}
}
}
return stage_states;
}
// static
PIPELINE_STATE::ActiveSlotMap PIPELINE_STATE::GetActiveSlots(const StageStateVec &stage_states) {
PIPELINE_STATE::ActiveSlotMap active_slots;
for (const auto &stage : stage_states) {
if (!stage.entrypoint) {
continue;
}
// Capture descriptor uses for the pipeline
for (const auto &use : stage.descriptor_uses) {
// While validating shaders capture which slots are used by the pipeline
auto &entry = active_slots[use.first.set][use.first.binding];
entry.is_writable |= use.second.is_writable;
auto &reqs = entry.reqs;
reqs |= stage.module_state->DescriptorTypeToReqs(use.second.type_id);
if (use.second.is_atomic_operation) reqs |= DESCRIPTOR_REQ_VIEW_ATOMIC_OPERATION;
if (use.second.is_sampler_sampled) reqs |= DESCRIPTOR_REQ_SAMPLER_SAMPLED;
if (use.second.is_sampler_implicitLod_dref_proj) reqs |= DESCRIPTOR_REQ_SAMPLER_IMPLICITLOD_DREF_PROJ;
if (use.second.is_sampler_bias_offset) reqs |= DESCRIPTOR_REQ_SAMPLER_BIAS_OFFSET;
if (use.second.is_read_without_format) reqs |= DESCRIPTOR_REQ_IMAGE_READ_WITHOUT_FORMAT;
if (use.second.is_write_without_format) reqs |= DESCRIPTOR_REQ_IMAGE_WRITE_WITHOUT_FORMAT;
if (use.second.is_dref_operation) reqs |= DESCRIPTOR_REQ_IMAGE_DREF;
if (use.second.samplers_used_by_image.size()) {
if (use.second.samplers_used_by_image.size() > entry.samplers_used_by_image.size()) {
entry.samplers_used_by_image.resize(use.second.samplers_used_by_image.size());
}
uint32_t image_index = 0;
for (const auto &samplers : use.second.samplers_used_by_image) {
for (const auto &sampler : samplers) {
entry.samplers_used_by_image[image_index].emplace(sampler);
}
++image_index;
}
}
}
}
return active_slots;
}
static uint32_t GetMaxActiveSlot(const PIPELINE_STATE::ActiveSlotMap &active_slots) {
uint32_t max_active_slot = 0;
for (const auto &entry : active_slots) {
max_active_slot = std::max(max_active_slot, entry.first);
}
return max_active_slot;
}
static uint32_t GetActiveShaders(const PIPELINE_STATE::StageStateVec &stages) {
uint32_t result = 0;
for (const auto &stage : stages) {
result |= stage.stage_flag;
}
return result;
}
static bool UsesShaderModuleId(const PIPELINE_STATE::StageStateVec &stages) {
bool result = false;
for (const auto &stage : stages) {
const auto module_id_info = LvlFindInChain<VkPipelineShaderStageModuleIdentifierCreateInfoEXT>(stage.create_info->pNext);
if (module_id_info) result |= (module_id_info->identifierSize > 0);
}
return result;
}
static layer_data::unordered_set<uint32_t> GetFSOutputLocations(const PIPELINE_STATE::StageStateVec &stage_states) {
layer_data::unordered_set<uint32_t> result;
for (const auto &stage : stage_states) {
if (!stage.entrypoint) {
continue;
}
if (stage.stage_flag == VK_SHADER_STAGE_FRAGMENT_BIT) {
result = stage.module_state->CollectWritableOutputLocationinFS(*(stage.entrypoint));
break;
}
}
return result;
}
static VkPrimitiveTopology GetTopologyAtRasterizer(const PIPELINE_STATE::StageStateVec &stage_states,
const safe_VkPipelineInputAssemblyStateCreateInfo *assembly_state) {
VkPrimitiveTopology result = assembly_state ? assembly_state->topology : static_cast<VkPrimitiveTopology>(0);
for (const auto &stage : stage_states) {
if (!stage.entrypoint) {
continue;
}
auto stage_topo = stage.module_state->GetTopology(*(stage.entrypoint));
if (stage_topo) {
result = *stage_topo;
}
}
return result;
}
// static
std::shared_ptr<VertexInputState> PIPELINE_STATE::CreateVertexInputState(const PIPELINE_STATE &p,
const ValidationStateTracker &state,
const safe_VkGraphicsPipelineCreateInfo &create_info) {
const auto lib_type = GetGraphicsLibType(create_info);
if (lib_type & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) { // Vertex input graphics library
return std::make_shared<VertexInputState>(p, create_info);
}
const auto link_info = LvlFindInChain<VkPipelineLibraryCreateInfoKHR>(create_info.pNext);
if (link_info) {
auto ss = GetLibSubState<VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT>(state, *link_info);
if (ss) {
return ss;
}
} else {
if (lib_type == static_cast<VkGraphicsPipelineLibraryFlagsEXT>(0)) { // Not a graphics library
return std::make_shared<VertexInputState>(p, create_info);
}
}
// We shouldn't get here...
return {};
}
// static
std::shared_ptr<PreRasterState> PIPELINE_STATE::CreatePreRasterState(const PIPELINE_STATE &p, const ValidationStateTracker &state,
const safe_VkGraphicsPipelineCreateInfo &create_info,
std::shared_ptr<const RENDER_PASS_STATE> rp) {
const auto lib_type = GetGraphicsLibType(create_info);
if (lib_type & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) { // Pre-raster graphics library
return std::make_shared<PreRasterState>(p, state, create_info, rp);
}
const auto link_info = LvlFindInChain<VkPipelineLibraryCreateInfoKHR>(create_info.pNext);
if (link_info) {
auto ss = GetLibSubState<VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT>(state, *link_info);
if (ss) {
return ss;
}
} else {
if (lib_type == static_cast<VkGraphicsPipelineLibraryFlagsEXT>(0)) { // Not a graphics library
return std::make_shared<PreRasterState>(p, state, create_info, rp);
}
}
// We shouldn't get here...
return {};
}
// static
std::shared_ptr<FragmentShaderState> PIPELINE_STATE::CreateFragmentShaderState(
const PIPELINE_STATE &p, const ValidationStateTracker &state, const VkGraphicsPipelineCreateInfo &create_info,
const safe_VkGraphicsPipelineCreateInfo &safe_create_info, std::shared_ptr<const RENDER_PASS_STATE> rp) {
const auto lib_type = GetGraphicsLibType(create_info);
if (lib_type & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) { // Fragment shader graphics library
return std::make_shared<FragmentShaderState>(p, state, create_info, rp);
}
const auto link_info = LvlFindInChain<VkPipelineLibraryCreateInfoKHR>(create_info.pNext);
if (link_info) {
auto ss = GetLibSubState<VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT>(state, *link_info);
if (ss) {
return ss;
}
} else {
if (lib_type == static_cast<VkGraphicsPipelineLibraryFlagsEXT>(0)) { // Not a graphics library
return std::make_shared<FragmentShaderState>(p, state, safe_create_info, rp);
}
}
// We shouldn't get here...
return {};
}
// static
// Pointers that should be ignored have been set to null in safe_create_info, but if this is a graphics library we need the "raw"
// create_info.
std::shared_ptr<FragmentOutputState> PIPELINE_STATE::CreateFragmentOutputState(
const PIPELINE_STATE &p, const ValidationStateTracker &state, const VkGraphicsPipelineCreateInfo &create_info,
const safe_VkGraphicsPipelineCreateInfo &safe_create_info, std::shared_ptr<const RENDER_PASS_STATE> rp) {
const auto lib_type = GetGraphicsLibType(create_info);
if (lib_type & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) { // Fragment output graphics library
return std::make_shared<FragmentOutputState>(p, create_info, rp);
}
const auto link_info = LvlFindInChain<VkPipelineLibraryCreateInfoKHR>(create_info.pNext);
if (link_info) {
auto ss = GetLibSubState<VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT>(state, *link_info);
if (ss) {
return ss;
}
} else {
if (lib_type == static_cast<VkGraphicsPipelineLibraryFlagsEXT>(0)) { // Not a graphics library
return std::make_shared<FragmentOutputState>(p, safe_create_info, rp);
}
}
// We shouldn't get here...
return {};
}
template <typename Substate>
void AppendDynamicStateFromSubstate(const Substate &substate, std::vector<VkDynamicState> &dyn_states,
VkPipelineDynamicStateCreateFlags &flags) {
if (substate) {
const auto *dyn_state = substate->parent.DynamicState();
if (dyn_state) {
flags |= dyn_state->flags;
for (uint32_t i = 0; i < dyn_state->dynamicStateCount; ++i) {
const auto itr = std::find(dyn_states.cbegin(), dyn_states.cend(), dyn_state->pDynamicStates[i]);
if (itr == dyn_states.cend()) {
dyn_states.emplace_back(dyn_state->pDynamicStates[i]);
}
}
}
}
}
std::vector<std::shared_ptr<const PIPELINE_LAYOUT_STATE>> PIPELINE_STATE::PipelineLayoutStateUnion() const {
std::vector<std::shared_ptr<const PIPELINE_LAYOUT_STATE>> ret;
ret.reserve(2);
// Only need to check pre-raster _or_ fragment shader layout; if either one is not merged_graphics_layout, then
// merged_graphics_layout is a union
if (pre_raster_state) {
if (pre_raster_state->pipeline_layout != fragment_shader_state->pipeline_layout) {
return {pre_raster_state->pipeline_layout, fragment_shader_state->pipeline_layout};
} else {
return {pre_raster_state->pipeline_layout};
}
}
return {merged_graphics_layout};
}
template <>
VkPipeline PIPELINE_STATE::BasePipeline<VkGraphicsPipelineCreateInfo>() const {
assert(create_info.graphics.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO);
return create_info.graphics.basePipelineHandle;
}
template <>
VkPipeline PIPELINE_STATE::BasePipeline<VkComputePipelineCreateInfo>() const {
assert(create_info.compute.sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO);
return create_info.compute.basePipelineHandle;
}
template <>
VkPipeline PIPELINE_STATE::BasePipeline<VkRayTracingPipelineCreateInfoKHR>() const {
assert(create_info.raytracing.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR);
return create_info.raytracing.basePipelineHandle;
}
template <>
VkPipeline PIPELINE_STATE::BasePipeline<VkRayTracingPipelineCreateInfoNV>() const {
assert(create_info.raytracing.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV);
return create_info.raytracing.basePipelineHandle;
}
template <>
int32_t PIPELINE_STATE::BasePipelineIndex<VkGraphicsPipelineCreateInfo>() const {
assert(create_info.graphics.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO);
return create_info.graphics.basePipelineIndex;
}
template <>
int32_t PIPELINE_STATE::BasePipelineIndex<VkComputePipelineCreateInfo>() const {
assert(create_info.compute.sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO);
return create_info.compute.basePipelineIndex;
}
template <>
int32_t PIPELINE_STATE::BasePipelineIndex<VkRayTracingPipelineCreateInfoKHR>() const {
assert(create_info.raytracing.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR);
return create_info.raytracing.basePipelineIndex;
}
template <>
int32_t PIPELINE_STATE::BasePipelineIndex<VkRayTracingPipelineCreateInfoNV>() const {
assert(create_info.raytracing.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV);
return create_info.raytracing.basePipelineIndex;
}
template <>
VkShaderModule PIPELINE_STATE::PIPELINE_STATE::GetShaderModuleByCIIndex<VkGraphicsPipelineCreateInfo>(uint32_t i) {
assert(create_info.graphics.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO);
return create_info.graphics.pStages[i].module;
}
template <>
VkShaderModule PIPELINE_STATE::GetShaderModuleByCIIndex<VkComputePipelineCreateInfo>(uint32_t) {
assert(create_info.compute.sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO);
return create_info.compute.stage.module;
}
template <>
VkShaderModule PIPELINE_STATE::GetShaderModuleByCIIndex<VkRayTracingPipelineCreateInfoKHR>(uint32_t i) {
assert(create_info.raytracing.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR);
return create_info.raytracing.pStages[i].module;
}
template <>
VkShaderModule PIPELINE_STATE::GetShaderModuleByCIIndex<VkRayTracingPipelineCreateInfoNV>(uint32_t i) {
assert(create_info.raytracing.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV);
return create_info.raytracing.pStages[i].module;
}
PIPELINE_STATE::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)
: BASE_NODE(static_cast<VkPipeline>(VK_NULL_HANDLE), kVulkanObjectTypePipeline),
rp_state(rpstate),
create_info(pCreateInfo, rpstate),
graphics_lib_type(GetGraphicsLibType(create_info.graphics)),
vertex_input_state(CreateVertexInputState(*this, *state_data, create_info.graphics)),
pre_raster_state(CreatePreRasterState(*this, *state_data, create_info.graphics, rpstate)),
fragment_shader_state(CreateFragmentShaderState(*this, *state_data, *pCreateInfo, create_info.graphics, rpstate)),
fragment_output_state(CreateFragmentOutputState(*this, *state_data, *pCreateInfo, create_info.graphics, rpstate)),
rendering_create_info(LvlFindInChain<VkPipelineRenderingCreateInfo>(PNext())),
stage_state(GetStageStates(*state_data, *this)),
fragmentShader_writable_output_location_list(GetFSOutputLocations(stage_state)),
active_slots(GetActiveSlots(stage_state)),
max_active_slot(GetMaxActiveSlot(active_slots)),
active_shaders(GetActiveShaders(stage_state)),
topology_at_rasterizer(GetTopologyAtRasterizer(stage_state, create_info.graphics.pInputAssemblyState)),
uses_shader_module_id(UsesShaderModuleId(stage_state)) {
const auto link_info = LvlFindInChain<VkPipelineLibraryCreateInfoKHR>(PNext());
if (link_info) {
// accumulate dynamic state
// TODO is this correct?
auto *dyn_state_ci = const_cast<safe_VkPipelineDynamicStateCreateInfo *>(create_info.graphics.pDynamicState);
std::vector<VkDynamicState> dyn_states;
VkPipelineDynamicStateCreateFlags dyn_flags = 0;
if (create_info.graphics.pDynamicState) {
std::copy(dyn_state_ci->pDynamicStates, dyn_state_ci->pDynamicStates + dyn_state_ci->dynamicStateCount,
std::back_inserter(dyn_states));
dyn_flags = dyn_state_ci->flags;
}
AppendDynamicStateFromSubstate(vertex_input_state, dyn_states, dyn_flags);
AppendDynamicStateFromSubstate(pre_raster_state, dyn_states, dyn_flags);
AppendDynamicStateFromSubstate(fragment_shader_state, dyn_states, dyn_flags);
AppendDynamicStateFromSubstate(fragment_output_state, dyn_states, dyn_flags);
if (dyn_states.size() > 0) {
// We have dynamic state
if (!dyn_state_ci || (dyn_state_ci->dynamicStateCount < dyn_states.size())) {
// There is dynamic state defined in libraries that the is not included in this pipeline's create info
if (!dyn_state_ci) {
// *All* dynamic state defined is coming from graphics libraries
// NOTE: heap allocation cleaned up in ~safe_VkGraphicsPipelineCreateInfo
dyn_state_ci = new safe_VkPipelineDynamicStateCreateInfo;
const_cast<safe_VkGraphicsPipelineCreateInfo *>(&create_info.graphics)->pDynamicState = dyn_state_ci;
}
dyn_state_ci->flags = dyn_flags;
dyn_state_ci->dynamicStateCount = static_cast<uint32_t>(dyn_states.size());
// NOTE: heap allocation cleaned up in ~safe_VkPipelineDynamicStateCreateInfo
dyn_state_ci->pDynamicStates = new VkDynamicState[dyn_states.size()];
std::copy(&dyn_states.front(), &dyn_states.front() + dyn_states.size(),
const_cast<VkDynamicState *>(dyn_state_ci->pDynamicStates));
}
}
const auto &exe_layout_state = state_data->Get<PIPELINE_LAYOUT_STATE>(create_info.graphics.layout);
const auto *exe_layout = exe_layout_state.get();
const auto *pre_raster_layout =
(pre_raster_state && pre_raster_state->pipeline_layout) ? pre_raster_state->pipeline_layout.get() : nullptr;
const auto *fragment_shader_layout = (fragment_shader_state && fragment_shader_state->pipeline_layout)
? fragment_shader_state->pipeline_layout.get()
: nullptr;
std::array<decltype(exe_layout), 3> layouts;
layouts[0] = exe_layout;
layouts[1] = fragment_shader_layout;
layouts[2] = pre_raster_layout;
merged_graphics_layout = std::make_shared<PIPELINE_LAYOUT_STATE>(layouts);
// TODO Could store the graphics_lib_type in the sub-state rather than searching for it again here.
// Or, could store a pointer back to the owning PIPELINE_STATE.
for (uint32_t i = 0; i < link_info->libraryCount; ++i) {
const auto &state = state_data->Get<PIPELINE_STATE>(link_info->pLibraries[i]);
if (state) {
graphics_lib_type |= state->graphics_lib_type;
}
}
}
}
PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *state_data, const VkComputePipelineCreateInfo *pCreateInfo,
std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout)
: BASE_NODE(static_cast<VkPipeline>(VK_NULL_HANDLE), kVulkanObjectTypePipeline),
create_info(pCreateInfo),
stage_state(GetStageStates(*state_data, *this)),
active_slots(GetActiveSlots(stage_state)),
active_shaders(GetActiveShaders(stage_state)),
topology_at_rasterizer{},
uses_shader_module_id(UsesShaderModuleId(stage_state)),
merged_graphics_layout(layout) {
assert(active_shaders == VK_SHADER_STAGE_COMPUTE_BIT);
}
PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *state_data, const VkRayTracingPipelineCreateInfoKHR *pCreateInfo,
std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout)
: BASE_NODE(static_cast<VkPipeline>(VK_NULL_HANDLE), kVulkanObjectTypePipeline),
create_info(pCreateInfo),
stage_state(GetStageStates(*state_data, *this)),
active_slots(GetActiveSlots(stage_state)),
active_shaders(GetActiveShaders(stage_state)),
topology_at_rasterizer{},
uses_shader_module_id(UsesShaderModuleId(stage_state)),
merged_graphics_layout(std::move(layout)) {
assert(0 == (active_shaders &
~(VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR |
VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR)));
}
PIPELINE_STATE::PIPELINE_STATE(const ValidationStateTracker *state_data, const VkRayTracingPipelineCreateInfoNV *pCreateInfo,
std::shared_ptr<const PIPELINE_LAYOUT_STATE> &&layout)
: BASE_NODE(static_cast<VkPipeline>(VK_NULL_HANDLE), kVulkanObjectTypePipeline),
create_info(pCreateInfo),
stage_state(GetStageStates(*state_data, *this)),
active_slots(GetActiveSlots(stage_state)),
active_shaders(GetActiveShaders(stage_state)),
topology_at_rasterizer{},
uses_shader_module_id(UsesShaderModuleId(stage_state)),
merged_graphics_layout(std::move(layout)) {
assert(0 == (active_shaders &
~(VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR |
VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR)));
}
void LAST_BOUND_STATE::UnbindAndResetPushDescriptorSet(std::shared_ptr<cvdescriptorset::DescriptorSet> &&ds) {
if (push_descriptor_set) {
for (auto &ps : per_set) {
if (ps.bound_descriptor_set == push_descriptor_set) {
cb_state.RemoveChild(ps.bound_descriptor_set);
ps.bound_descriptor_set.reset();
}
}
}
cb_state.AddChild(ds);
push_descriptor_set = std::move(ds);
}
void LAST_BOUND_STATE::Reset() {
pipeline_state = nullptr;
pipeline_layout = VK_NULL_HANDLE;
if (push_descriptor_set) {
cb_state.RemoveChild(push_descriptor_set);
push_descriptor_set->Destroy();
}
push_descriptor_set.reset();
per_set.clear();
}