blob: 497bdf0ab346b88ae03624747e793c1e36c346a3 [file] [log] [blame]
/* Copyright (c) 2015-2017, 2019-2023 The Khronos Group Inc.
* Copyright (c) 2015-2017, 2019-2023 Valve Corporation
* Copyright (c) 2015-2017, 2019-2023 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_sub_state.h"
#include "state_tracker/pipeline_state.h"
VkPipelineLayoutCreateFlags PipelineSubState::PipelineLayoutCreateFlags() const {
const auto layout_state = parent.PipelineLayoutState();
return (layout_state) ? layout_state->CreateFlags() : static_cast<VkPipelineLayoutCreateFlags>(0);
}
VertexInputState::VertexInputState(const PIPELINE_STATE &p, const safe_VkGraphicsPipelineCreateInfo &create_info)
: PipelineSubState(p), input_state(create_info.pVertexInputState), input_assembly_state(create_info.pInputAssemblyState) {
if (create_info.pVertexInputState) {
const auto *vici = create_info.pVertexInputState;
if (vici->vertexBindingDescriptionCount) {
const auto count = vici->vertexBindingDescriptionCount;
binding_descriptions.reserve(count);
binding_to_index_map.reserve(count);
for (uint32_t i = 0; i < count; i++) {
binding_descriptions.emplace_back(vici->pVertexBindingDescriptions[i]);
binding_to_index_map[binding_descriptions.back().binding] = i;
}
}
if (vici->vertexAttributeDescriptionCount) {
vertex_attribute_descriptions.reserve(vici->vertexAttributeDescriptionCount);
std::copy(vici->pVertexAttributeDescriptions,
vici->pVertexAttributeDescriptions + vici->vertexAttributeDescriptionCount,
std::back_inserter(vertex_attribute_descriptions));
}
vertex_attribute_alignments.reserve(vertex_attribute_descriptions.size());
for (const auto &attr : vertex_attribute_descriptions) {
VkDeviceSize vtx_attrib_req_alignment = vkuFormatElementSize(attr.format);
if (vkuFormatElementIsTexel(attr.format)) {
vtx_attrib_req_alignment = SafeDivision(vtx_attrib_req_alignment, vkuFormatComponentCount(attr.format));
}
vertex_attribute_alignments.push_back(vtx_attrib_req_alignment);
}
}
}
PreRasterState::PreRasterState(const PIPELINE_STATE &p, const ValidationStateTracker &state_data,
const safe_VkGraphicsPipelineCreateInfo &create_info, std::shared_ptr<const RENDER_PASS_STATE> rp)
: PipelineSubState(p), rp_state(rp), subpass(create_info.subpass) {
pipeline_layout = state_data.Get<PIPELINE_LAYOUT_STATE>(create_info.layout);
viewport_state = create_info.pViewportState;
rp_state = state_data.Get<RENDER_PASS_STATE>(create_info.renderPass);
raster_state = create_info.pRasterizationState;
tess_create_info = create_info.pTessellationState;
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;
// TODO might need to filter out more than just fragment shaders here
if (stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
continue;
}
all_stages |= stage;
auto module_state = state_data.Get<SHADER_MODULE_STATE>(stage_ci.module);
if (!module_state) {
// 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 = vku::FindStructInPNextChain<VkShaderModuleCreateInfo>(stage_ci.pNext);
if (shader_ci) {
// don't need to worry about GroupDecoration in GPL
auto spirv_module = std::make_shared<SPIRV_MODULE_STATE>(shader_ci->codeSize, shader_ci->pCode);
module_state = std::make_shared<SHADER_MODULE_STATE>(VK_NULL_HANDLE, spirv_module, 0);
}
}
// 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:
// TODO is this an error?
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 safe_VkPipelineColorBlendStateCreateInfo> ToSafeColorBlendState(
const 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 safe_VkPipelineColorBlendStateCreateInfo>(cbs);
}
std::unique_ptr<const safe_VkPipelineColorBlendStateCreateInfo> ToSafeColorBlendState(
const VkPipelineColorBlendStateCreateInfo &cbs) {
return std::make_unique<const safe_VkPipelineColorBlendStateCreateInfo>(&cbs);
}
std::unique_ptr<const safe_VkPipelineMultisampleStateCreateInfo> ToSafeMultisampleState(
const 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 safe_VkPipelineMultisampleStateCreateInfo>(cbs);
}
std::unique_ptr<const safe_VkPipelineMultisampleStateCreateInfo> ToSafeMultisampleState(
const VkPipelineMultisampleStateCreateInfo &cbs) {
return std::make_unique<const safe_VkPipelineMultisampleStateCreateInfo>(&cbs);
}
std::unique_ptr<const safe_VkPipelineDepthStencilStateCreateInfo> ToSafeDepthStencilState(
const 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 safe_VkPipelineDepthStencilStateCreateInfo>(cbs);
}
std::unique_ptr<const safe_VkPipelineDepthStencilStateCreateInfo> ToSafeDepthStencilState(
const VkPipelineDepthStencilStateCreateInfo &cbs) {
return std::make_unique<const safe_VkPipelineDepthStencilStateCreateInfo>(&cbs);
}
std::unique_ptr<const safe_VkPipelineShaderStageCreateInfo> ToShaderStageCI(const 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 safe_VkPipelineShaderStageCreateInfo>(cbs);
}
std::unique_ptr<const safe_VkPipelineShaderStageCreateInfo> ToShaderStageCI(const VkPipelineShaderStageCreateInfo &cbs) {
return std::make_unique<const safe_VkPipelineShaderStageCreateInfo>(&cbs);
}
template <typename CreateInfo>
void SetFragmentShaderInfoPrivate(FragmentShaderState &fs_state, const ValidationStateTracker &state_data,
const CreateInfo &create_info) {
for (uint32_t i = 0; i < create_info.stageCount; ++i) {
if (create_info.pStages[i].stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
auto module_state = state_data.Get<SHADER_MODULE_STATE>(create_info.pStages[i].module);
if (!module_state) {
// 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 = vku::FindStructInPNextChain<VkShaderModuleCreateInfo>(create_info.pStages[i].pNext);
if (shader_ci) {
// don't need to worry about GroupDecoration in GPL
auto spirv_module = std::make_shared<SPIRV_MODULE_STATE>(shader_ci->codeSize, shader_ci->pCode);
module_state = std::make_shared<SHADER_MODULE_STATE>(VK_NULL_HANDLE, spirv_module, 0);
}
}
// 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]);
}
}
}
}
// static
void FragmentShaderState::SetFragmentShaderInfo(FragmentShaderState &fs_state, const ValidationStateTracker &state_data,
const VkGraphicsPipelineCreateInfo &create_info) {
SetFragmentShaderInfoPrivate(fs_state, state_data, create_info);
}
// static
void FragmentShaderState::SetFragmentShaderInfo(FragmentShaderState &fs_state, const ValidationStateTracker &state_data,
const safe_VkGraphicsPipelineCreateInfo &create_info) {
SetFragmentShaderInfoPrivate(fs_state, state_data, create_info);
}
FragmentShaderState::FragmentShaderState(const PIPELINE_STATE &p, const ValidationStateTracker &dev_data,
std::shared_ptr<const RENDER_PASS_STATE> rp, uint32_t subp, VkPipelineLayout layout)
: PipelineSubState(p), rp_state(rp), subpass(subp), pipeline_layout(dev_data.Get<PIPELINE_LAYOUT_STATE>(layout)) {}
FragmentOutputState::FragmentOutputState(const PIPELINE_STATE &p, std::shared_ptr<const RENDER_PASS_STATE> rp, uint32_t sp)
: PipelineSubState(p), rp_state(rp), subpass(sp) {}
// static
bool FragmentOutputState::IsBlendConstantsEnabled(const AttachmentVector &attachments) {
bool result = false;
for (const auto &attachment : attachments) {
if (VK_TRUE == attachment.blendEnable) {
if (((attachment.dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
(attachment.dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
((attachment.dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
(attachment.dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
((attachment.srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
(attachment.srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
((attachment.srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
(attachment.srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
result = true;
break;
}
}
}
return result;
}
// static
bool FragmentOutputState::GetDualSourceBlending(const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state) {
if (!color_blend_state) {
return false;
}
for (uint32_t i = 0; i < color_blend_state->attachmentCount; ++i) {
const auto &attachment = color_blend_state->pAttachments[i];
if (attachment.blendEnable) {
if (IsSecondaryColorInputBlendFactor(attachment.srcColorBlendFactor) ||
IsSecondaryColorInputBlendFactor(attachment.dstColorBlendFactor) ||
IsSecondaryColorInputBlendFactor(attachment.srcAlphaBlendFactor) ||
IsSecondaryColorInputBlendFactor(attachment.dstAlphaBlendFactor)) {
return true;
}
}
}
return false;
}