blob: e557c624ca7263b985907328458ef3538109e5fe [file]
/* Copyright (c) 2015-2017, 2019-2026 The Khronos Group Inc.
* Copyright (c) 2015-2017, 2019-2026 Valve Corporation
* Copyright (c) 2015-2017, 2019-2026 LunarG, Inc.
*
* 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.
*/
#include "state_tracker/pipeline_library_state.h"
#include "state_tracker/pipeline_state.h"
#include "state_tracker/shader_module.h"
#include "containers/container_utils.h"
bool PipelineLibraryState::IsIndependentSets() const {
if (const auto layout_state = parent.PipelineLayoutState()) {
if (layout_state->CreateFlags() & VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT) {
return true;
}
}
return false;
}
VertexInputState::VertexInputState(const vvl::Pipeline& p, const vku::safe_VkGraphicsPipelineCreateInfo& create_info)
: PipelineLibraryState(p) {
for (uint32_t i = 0; i < create_info.stageCount; i++) {
if (create_info.pStages && create_info.pStages[i].stage == VK_SHADER_STAGE_MESH_BIT_EXT) {
return; // if mesh shaders are used, all vertex input state is ignored
}
}
input_state = create_info.pVertexInputState;
input_assembly_state = create_info.pInputAssemblyState;
if (input_state) {
if (input_state->vertexBindingDescriptionCount) {
for (const auto [i, description] :
vvl::enumerate(input_state->pVertexBindingDescriptions, input_state->vertexBindingDescriptionCount)) {
bindings.emplace(description.binding, VertexBindingState(i, &description));
}
const auto* divisor_info = vku::FindStructInPNextChain<VkPipelineVertexInputDivisorStateCreateInfo>(input_state->pNext);
if (divisor_info) {
for (const auto [i, di] :
vvl::enumerate(divisor_info->pVertexBindingDivisors, divisor_info->vertexBindingDivisorCount)) {
if (auto* binding_state = vvl::Find(bindings, di.binding)) {
binding_state->desc.divisor = di.divisor;
}
}
}
}
for (const auto [i, description] :
vvl::enumerate(input_state->pVertexAttributeDescriptions, input_state->vertexAttributeDescriptionCount)) {
auto* binding_state = vvl::Find(bindings, description.binding);
if (!binding_state) {
continue;
}
binding_state->locations.emplace(description.location, VertexAttrState(i, &description));
}
}
}
PreRasterState::PreRasterState(const vvl::Pipeline& p, const vvl::DeviceState& state_data,
const vku::safe_VkGraphicsPipelineCreateInfo& create_info, std::shared_ptr<const vvl::RenderPass> rp,
spirv::StatelessData stateless_data[kCommonMaxGraphicsShaderStages])
: PipelineLibraryState(p),
pipeline_layout(state_data.Get<vvl::PipelineLayout>(create_info.layout)),
viewport_state(create_info.pViewportState),
raster_state(create_info.pRasterizationState),
tessellation_state(create_info.pTessellationState),
rp_state(rp),
subpass(create_info.subpass) {
VkShaderStageFlags all_stages = 0;
for (uint32_t i = 0; i < create_info.stageCount; ++i) {
const auto& stage_ci = create_info.pStages[i];
const VkShaderStageFlagBits stage = stage_ci.stage;
if ((stage & ValidShaderStages()) == 0) {
continue;
}
all_stages |= stage;
auto module_state = state_data.Get<vvl::ShaderModule>(stage_ci.module);
if (!module_state && p.pipeline_cache) {
// Attempt to look up the pipeline cache for shader module data
module_state = p.pipeline_cache->GetStageModule(p, i);
}
if (!module_state) {
// Using VkShaderModuleCreateInfo to inline with VK_KHR_maintenance5
if (const auto shader_ci = vku::FindStructInPNextChain<VkShaderModuleCreateInfo>(stage_ci.pNext)) {
spirv::StatelessData* stateless_data_stage =
(stateless_data && i < kCommonMaxGraphicsShaderStages) ? &stateless_data[i] : nullptr;
auto spirv_module = vvl::CreateSpirvModuleState(shader_ci->codeSize, shader_ci->pCode, state_data.global_settings,
stateless_data_stage);
module_state = std::make_shared<vvl::ShaderModule>(VK_NULL_HANDLE, spirv_module);
if (stateless_data_stage) {
stateless_data_stage->pipeline_pnext_module = spirv_module;
}
}
}
// Check if a shader module identifier is used to reference the shader module.
if (!module_state) {
if (const auto shader_stage_id =
vku::FindStructInPNextChain<VkPipelineShaderStageModuleIdentifierCreateInfoEXT>(stage_ci.pNext);
shader_stage_id) {
module_state = state_data.GetShaderModuleStateFromIdentifier(*shader_stage_id);
}
}
if (module_state) {
switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT:
vertex_shader = std::move(module_state);
vertex_shader_ci = &stage_ci;
break;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
tessc_shader = std::move(module_state);
tessc_shader_ci = &stage_ci;
break;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
tesse_shader = std::move(module_state);
tesse_shader_ci = &stage_ci;
break;
case VK_SHADER_STAGE_GEOMETRY_BIT:
geometry_shader = std::move(module_state);
geometry_shader_ci = &stage_ci;
break;
case VK_SHADER_STAGE_TASK_BIT_EXT:
task_shader = std::move(module_state);
task_shader_ci = &stage_ci;
break;
case VK_SHADER_STAGE_MESH_BIT_EXT:
mesh_shader = std::move(module_state);
mesh_shader_ci = &stage_ci;
break;
default:
assert(false); // Not a valid pre-raster shader stage
break;
}
}
}
if (all_stages & VK_SHADER_STAGE_MESH_BIT_EXT) {
last_stage = VK_SHADER_STAGE_MESH_BIT_EXT;
} else if (all_stages & VK_SHADER_STAGE_TASK_BIT_EXT) {
last_stage = VK_SHADER_STAGE_TASK_BIT_EXT;
} else if (all_stages & VK_SHADER_STAGE_GEOMETRY_BIT) {
last_stage = VK_SHADER_STAGE_GEOMETRY_BIT;
} else if (all_stages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
last_stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
} else if (all_stages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
last_stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
} else if (all_stages & VK_SHADER_STAGE_VERTEX_BIT) {
last_stage = VK_SHADER_STAGE_VERTEX_BIT;
}
}
std::unique_ptr<const vku::safe_VkPipelineColorBlendStateCreateInfo> ToSafeColorBlendState(
const vku::safe_VkPipelineColorBlendStateCreateInfo& cbs) {
// This is needlessly copied here. Might better to make this a plain pointer, with an optional "backing unique_ptr"
return std::make_unique<const vku::safe_VkPipelineColorBlendStateCreateInfo>(cbs);
}
std::unique_ptr<const vku::safe_VkPipelineColorBlendStateCreateInfo> ToSafeColorBlendState(
const VkPipelineColorBlendStateCreateInfo& cbs) {
return std::make_unique<const vku::safe_VkPipelineColorBlendStateCreateInfo>(&cbs);
}
std::unique_ptr<const vku::safe_VkPipelineMultisampleStateCreateInfo> ToSafeMultisampleState(
const vku::safe_VkPipelineMultisampleStateCreateInfo& cbs) {
// This is needlessly copied here. Might better to make this a plain pointer, with an optional "backing unique_ptr"
return std::make_unique<const vku::safe_VkPipelineMultisampleStateCreateInfo>(cbs);
}
std::unique_ptr<const vku::safe_VkPipelineMultisampleStateCreateInfo> ToSafeMultisampleState(
const VkPipelineMultisampleStateCreateInfo& cbs) {
return std::make_unique<const vku::safe_VkPipelineMultisampleStateCreateInfo>(&cbs);
}
std::unique_ptr<const vku::safe_VkPipelineDepthStencilStateCreateInfo> ToSafeDepthStencilState(
const vku::safe_VkPipelineDepthStencilStateCreateInfo& cbs) {
// This is needlessly copied here. Might better to make this a plain pointer, with an optional "backing unique_ptr"
return std::make_unique<const vku::safe_VkPipelineDepthStencilStateCreateInfo>(cbs);
}
std::unique_ptr<const vku::safe_VkPipelineDepthStencilStateCreateInfo> ToSafeDepthStencilState(
const VkPipelineDepthStencilStateCreateInfo& cbs) {
return std::make_unique<const vku::safe_VkPipelineDepthStencilStateCreateInfo>(&cbs);
}
std::unique_ptr<const vku::safe_VkPipelineShaderStageCreateInfo> ToShaderStageCI(
const vku::safe_VkPipelineShaderStageCreateInfo& cbs) {
// This is needlessly copied here. Might better to make this a plain pointer, with an optional "backing unique_ptr"
return std::make_unique<const vku::safe_VkPipelineShaderStageCreateInfo>(cbs);
}
std::unique_ptr<const vku::safe_VkPipelineShaderStageCreateInfo> ToShaderStageCI(const VkPipelineShaderStageCreateInfo& cbs) {
return std::make_unique<const vku::safe_VkPipelineShaderStageCreateInfo>(&cbs);
}
template <typename CreateInfo>
void SetFragmentShaderInfoPrivate(const vvl::Pipeline& pipeline_state, FragmentShaderState& fs_state,
const vvl::DeviceState& state_data, const CreateInfo& create_info,
spirv::StatelessData stateless_data[kCommonMaxGraphicsShaderStages]) {
for (uint32_t i = 0; i < create_info.stageCount; ++i) {
if (create_info.pStages[i].stage != VK_SHADER_STAGE_FRAGMENT_BIT) {
continue;
}
auto module_state = state_data.Get<vvl::ShaderModule>(create_info.pStages[i].module);
if (!module_state && pipeline_state.pipeline_cache) {
// Attempt to look up the pipeline cache for shader module data
module_state = pipeline_state.pipeline_cache->GetStageModule(pipeline_state, i);
}
if (!module_state) {
// Using VkShaderModuleCreateInfo to inline with VK_KHR_maintenance5
if (const auto shader_ci = vku::FindStructInPNextChain<VkShaderModuleCreateInfo>(create_info.pStages[i].pNext)) {
spirv::StatelessData* stateless_data_stage =
(stateless_data && i < kCommonMaxGraphicsShaderStages) ? &stateless_data[i] : nullptr;
auto spirv_module = vvl::CreateSpirvModuleState(shader_ci->codeSize, shader_ci->pCode, state_data.global_settings,
stateless_data_stage);
module_state = std::make_shared<vvl::ShaderModule>(VK_NULL_HANDLE, spirv_module);
if (stateless_data_stage) {
stateless_data_stage->pipeline_pnext_module = spirv_module;
}
}
}
// Check if a shader module identifier is used to reference the shader module.
if (!module_state) {
if (const auto shader_stage_id =
vku::FindStructInPNextChain<VkPipelineShaderStageModuleIdentifierCreateInfoEXT>(create_info.pStages[i].pNext);
shader_stage_id) {
module_state = state_data.GetShaderModuleStateFromIdentifier(*shader_stage_id);
}
}
if (module_state) {
fs_state.fragment_shader = std::move(module_state);
fs_state.fragment_shader_ci = ToShaderStageCI(create_info.pStages[i]);
// can be null if using VK_EXT_shader_module_identifier
if (fs_state.fragment_shader->spirv) {
fs_state.fragment_entry_point = fs_state.fragment_shader->spirv->FindEntrypoint(fs_state.fragment_shader_ci->pName,
fs_state.fragment_shader_ci->stage);
}
}
}
}
// static
void FragmentShaderState::SetFragmentShaderInfo(const vvl::Pipeline& pipeline_state, FragmentShaderState& fs_state,
const vvl::DeviceState& state_data, const VkGraphicsPipelineCreateInfo& create_info,
spirv::StatelessData stateless_data[kCommonMaxGraphicsShaderStages]) {
SetFragmentShaderInfoPrivate(pipeline_state, fs_state, state_data, create_info, stateless_data);
}
// static
void FragmentShaderState::SetFragmentShaderInfo(const vvl::Pipeline& pipeline_state, FragmentShaderState& fs_state,
const vvl::DeviceState& state_data,
const vku::safe_VkGraphicsPipelineCreateInfo& create_info,
spirv::StatelessData stateless_data[kCommonMaxGraphicsShaderStages]) {
SetFragmentShaderInfoPrivate(pipeline_state, fs_state, state_data, create_info, stateless_data);
}
FragmentShaderState::FragmentShaderState(const vvl::Pipeline& p, const vvl::DeviceState& dev_data,
std::shared_ptr<const vvl::RenderPass> rp, uint32_t subpass_index, VkPipelineLayout layout)
: PipelineLibraryState(p), rp_state(rp), subpass(subpass_index), pipeline_layout(dev_data.Get<vvl::PipelineLayout>(layout)) {}
FragmentOutputState::FragmentOutputState(const vvl::Pipeline& p, std::shared_ptr<const vvl::RenderPass> rp, uint32_t subpass_index)
: PipelineLibraryState(p), rp_state(rp), subpass(subpass_index) {}