blob: 4c4d74d1789dc76c57ba1b2f812ab55afb15f548 [file] [log] [blame]
/*
* Copyright (c) 2023 The Khronos Group Inc.
* Copyright (c) 2023 Valve Corporation
* Copyright (c) 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
*/
#include "pipeline_helper.h"
CreatePipelineHelper::CreatePipelineHelper(VkLayerTest &test, uint32_t color_attachments_count)
: cb_attachments_(color_attachments_count), layer_test_(test) {
// default VkDevice, can be overwritten if multi-device tests
device_ = layer_test_.DeviceObj();
// InitDescriptorSetInfo
dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
// InitInputAndVertexInfo
vi_ci_ = vku::InitStructHelper();
ia_ci_ = vku::InitStructHelper();
ia_ci_.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
// InitMultisampleInfo
pipe_ms_state_ci_ = vku::InitStructHelper();
pipe_ms_state_ci_.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
pipe_ms_state_ci_.sampleShadingEnable = VK_FALSE;
pipe_ms_state_ci_.minSampleShading = 1.0;
pipe_ms_state_ci_.pSampleMask = nullptr;
// InitPipelineLayoutInfo
pipeline_layout_ci_ = vku::InitStructHelper();
pipeline_layout_ci_.setLayoutCount = 1; // Not really changeable because InitState() sets exactly one pSetLayout
pipeline_layout_ci_.pSetLayouts = nullptr; // must bound after it is created
// InitViewportInfo
viewport_ = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f};
scissor_ = {{0, 0}, {64, 64}};
vp_state_ci_ = vku::InitStructHelper();
vp_state_ci_.viewportCount = 1;
vp_state_ci_.pViewports = &viewport_;
vp_state_ci_.scissorCount = 1;
vp_state_ci_.pScissors = &scissor_;
// InitRasterizationInfo
rs_state_ci_ = vku::InitStructHelper(&line_state_ci_);
rs_state_ci_.flags = 0;
rs_state_ci_.depthClampEnable = VK_FALSE;
rs_state_ci_.rasterizerDiscardEnable = VK_FALSE;
rs_state_ci_.polygonMode = VK_POLYGON_MODE_FILL;
rs_state_ci_.cullMode = VK_CULL_MODE_BACK_BIT;
rs_state_ci_.frontFace = VK_FRONT_FACE_CLOCKWISE;
rs_state_ci_.depthBiasEnable = VK_FALSE;
rs_state_ci_.lineWidth = 1.0F;
// InitLineRasterizationInfo
line_state_ci_ = vku::InitStructHelper();
line_state_ci_.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
line_state_ci_.stippledLineEnable = VK_FALSE;
line_state_ci_.lineStippleFactor = 0;
line_state_ci_.lineStipplePattern = 0;
// InitBlendStateInfo
cb_ci_ = vku::InitStructHelper();
cb_ci_.logicOpEnable = VK_FALSE;
cb_ci_.logicOp = VK_LOGIC_OP_COPY; // ignored if enable is VK_FALSE above
cb_ci_.attachmentCount = cb_attachments_.size();
cb_ci_.pAttachments = cb_attachments_.data();
for (int i = 0; i < 4; i++) {
cb_ci_.blendConstants[0] = 1.0F;
}
// InitPipelineCacheInfo
pc_ci_ = vku::InitStructHelper();
pc_ci_.flags = 0;
pc_ci_.initialDataSize = 0;
pc_ci_.pInitialData = nullptr;
InitShaderInfo();
// Color-only rendering in a subpass with no depth/stencil attachment
// Active Pipeline Shader Stages
// Vertex Shader
// Fragment Shader
// Required: Fixed-Function Pipeline Stages
// VkPipelineVertexInputStateCreateInfo
// VkPipelineInputAssemblyStateCreateInfo
// VkPipelineViewportStateCreateInfo
// VkPipelineRasterizationStateCreateInfo
// VkPipelineMultisampleStateCreateInfo
// VkPipelineColorBlendStateCreateInfo
gp_ci_ = vku::InitStructHelper();
gp_ci_.layout = VK_NULL_HANDLE;
gp_ci_.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT;
gp_ci_.pVertexInputState = &vi_ci_;
gp_ci_.pInputAssemblyState = &ia_ci_;
gp_ci_.pTessellationState = nullptr;
gp_ci_.pViewportState = &vp_state_ci_;
gp_ci_.pMultisampleState = &pipe_ms_state_ci_;
gp_ci_.pRasterizationState = &rs_state_ci_;
gp_ci_.pDepthStencilState = nullptr;
gp_ci_.pColorBlendState = &cb_ci_;
gp_ci_.pDynamicState = nullptr;
gp_ci_.renderPass = layer_test_.renderPass();
}
CreatePipelineHelper::~CreatePipelineHelper() {
if (pipeline_cache_ != VK_NULL_HANDLE) {
vk::DestroyPipelineCache(device_->handle(), pipeline_cache_, nullptr);
pipeline_cache_ = VK_NULL_HANDLE;
}
if (pipeline_ != VK_NULL_HANDLE) {
vk::DestroyPipeline(device_->handle(), pipeline_, nullptr);
pipeline_ = VK_NULL_HANDLE;
}
}
void CreatePipelineHelper::InitShaderInfo() { ResetShaderInfo(kVertexMinimalGlsl, kFragmentMinimalGlsl); }
void CreatePipelineHelper::ResetShaderInfo(const char *vertex_shader_text, const char *fragment_shader_text) {
vs_ = std::make_unique<VkShaderObj>(&layer_test_, vertex_shader_text, VK_SHADER_STAGE_VERTEX_BIT);
fs_ = std::make_unique<VkShaderObj>(&layer_test_, fragment_shader_text, VK_SHADER_STAGE_FRAGMENT_BIT);
// We shouldn't need a fragment shader but add it to be able to run on more devices
shader_stages_ = {vs_->GetStageCreateInfo(), fs_->GetStageCreateInfo()};
}
// Designed for majority of cases that just need to simply add dynamic state
void CreatePipelineHelper::AddDynamicState(VkDynamicState dynamic_state) {
dynamic_states_.push_back(dynamic_state);
dyn_state_ci_ = vku::InitStructHelper();
dyn_state_ci_.pDynamicStates = dynamic_states_.data();
dyn_state_ci_.dynamicStateCount = dynamic_states_.size();
// Set here and don't have have to worry about late bind setting it
gp_ci_.pDynamicState = &dyn_state_ci_;
}
void CreatePipelineHelper::InitVertexInputLibInfo(void *p_next) {
gpl_info.emplace(vku::InitStruct<VkGraphicsPipelineLibraryCreateInfoEXT>(p_next));
gpl_info->flags = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT;
gp_ci_ = vku::InitStructHelper(&gpl_info);
gp_ci_.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
gp_ci_.pVertexInputState = &vi_ci_;
gp_ci_.pInputAssemblyState = &ia_ci_;
gp_ci_.stageCount = 0;
shader_stages_.clear();
}
void CreatePipelineHelper::InitPreRasterLibInfo(const VkPipelineShaderStageCreateInfo *info, void *p_next) {
gpl_info.emplace(vku::InitStruct<VkGraphicsPipelineLibraryCreateInfoEXT>(p_next));
gpl_info->flags = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT;
gp_ci_ = vku::InitStructHelper(&gpl_info);
gp_ci_.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
gp_ci_.pViewportState = &vp_state_ci_;
gp_ci_.pRasterizationState = &rs_state_ci_;
// If using Dynamic Rendering, will need to be set to null
// otherwise needs to be shared across libraries in the same executable pipeline
gp_ci_.renderPass = layer_test_.renderPass();
gp_ci_.subpass = 0;
gp_ci_.stageCount = 1; // default is just the Vertex shader
gp_ci_.pStages = info;
}
void CreatePipelineHelper::InitFragmentLibInfo(const VkPipelineShaderStageCreateInfo *info, void *p_next) {
gpl_info.emplace(vku::InitStruct<VkGraphicsPipelineLibraryCreateInfoEXT>(p_next));
gpl_info->flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
gp_ci_ = vku::InitStructHelper(&gpl_info);
gp_ci_.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
// gp_ci_.pTessellationState = nullptr; // TODO
gp_ci_.pViewportState = &vp_state_ci_;
// If using Dynamic Rendering, will need to be set to null
// otherwise needs to be shared across libraries in the same executable pipeline
gp_ci_.renderPass = layer_test_.renderPass();
gp_ci_.subpass = 0;
// TODO if renderPass is null, MS info is not needed
gp_ci_.pMultisampleState = &pipe_ms_state_ci_;
gp_ci_.stageCount = 1; // default is just the Fragment shader
gp_ci_.pStages = info;
}
void CreatePipelineHelper::InitFragmentOutputLibInfo(void *p_next) {
gpl_info.emplace(vku::InitStruct<VkGraphicsPipelineLibraryCreateInfoEXT>(p_next));
gpl_info->flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
gp_ci_ = vku::InitStructHelper(&gpl_info);
gp_ci_.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT;
gp_ci_.pColorBlendState = &cb_ci_;
gp_ci_.pMultisampleState = &pipe_ms_state_ci_;
gp_ci_.pRasterizationState = &rs_state_ci_;
// If using Dynamic Rendering, will need to be set to null
// otherwise needs to be shared across libraries in the same executable pipeline
gp_ci_.renderPass = layer_test_.renderPass();
gp_ci_.subpass = 0;
gp_ci_.stageCount = 0;
shader_stages_.clear();
}
void CreatePipelineHelper::InitState() {
descriptor_set_.reset(new OneOffDescriptorSet(device_, dsl_bindings_));
ASSERT_TRUE(descriptor_set_->Initialized());
const std::vector<VkPushConstantRange> push_ranges(
pipeline_layout_ci_.pPushConstantRanges,
pipeline_layout_ci_.pPushConstantRanges + pipeline_layout_ci_.pushConstantRangeCount);
pipeline_layout_ = vkt::PipelineLayout(*device_, {&descriptor_set_->layout_}, push_ranges, pipeline_layout_ci_.flags);
InitPipelineCache();
}
void CreatePipelineHelper::InitPipelineCache() {
if (pipeline_cache_ != VK_NULL_HANDLE) {
vk::DestroyPipelineCache(device_->handle(), pipeline_cache_, nullptr);
}
VkResult err = vk::CreatePipelineCache(device_->handle(), &pc_ci_, NULL, &pipeline_cache_);
ASSERT_EQ(VK_SUCCESS, err);
}
void CreatePipelineHelper::LateBindPipelineInfo() {
// By value or dynamically located items must be late bound
if (gp_ci_.layout == VK_NULL_HANDLE) {
gp_ci_.layout = pipeline_layout_.handle();
}
if (gp_ci_.stageCount == 0) {
gp_ci_.stageCount = shader_stages_.size();
gp_ci_.pStages = shader_stages_.data();
}
if ((gp_ci_.pTessellationState == nullptr) && IsValidVkStruct(tess_ci_)) {
gp_ci_.pTessellationState = &tess_ci_;
}
if ((gp_ci_.pDynamicState == nullptr) && IsValidVkStruct(dyn_state_ci_)) {
gp_ci_.pDynamicState = &dyn_state_ci_;
}
if ((gp_ci_.pDepthStencilState == nullptr) && IsValidVkStruct(ds_ci_)) {
gp_ci_.pDepthStencilState = &ds_ci_;
}
}
VkResult CreatePipelineHelper::CreateGraphicsPipeline(bool do_late_bind) {
if (do_late_bind) {
LateBindPipelineInfo();
}
return vk::CreateGraphicsPipelines(device_->handle(), pipeline_cache_, 1, &gp_ci_, NULL, &pipeline_);
}
CreateComputePipelineHelper::CreateComputePipelineHelper(VkLayerTest &test) : layer_test_(test) {
// InitDescriptorSetInfo
dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
// InitPipelineLayoutInfo
pipeline_layout_ci_ = vku::InitStructHelper();
pipeline_layout_ci_.setLayoutCount = 1; // Not really changeable because InitState() sets exactly one pSetLayout
pipeline_layout_ci_.pSetLayouts = nullptr; // must bound after it is created
// InitPipelineCacheInfo
pc_ci_ = vku::InitStructHelper();
pc_ci_.flags = 0;
pc_ci_.initialDataSize = 0;
pc_ci_.pInitialData = nullptr;
InitShaderInfo();
cp_ci_ = vku::InitStructHelper();
cp_ci_.flags = 0;
cp_ci_.layout = VK_NULL_HANDLE;
}
CreateComputePipelineHelper::~CreateComputePipelineHelper() {
VkDevice device = layer_test_.device();
if (pipeline_cache_ != VK_NULL_HANDLE) {
vk::DestroyPipelineCache(device, pipeline_cache_, nullptr);
pipeline_cache_ = VK_NULL_HANDLE;
}
if (pipeline_ != VK_NULL_HANDLE) {
vk::DestroyPipeline(device, pipeline_, nullptr);
pipeline_ = VK_NULL_HANDLE;
}
}
void CreateComputePipelineHelper::InitShaderInfo() {
cs_ = std::make_unique<VkShaderObj>(&layer_test_, kMinimalShaderGlsl, VK_SHADER_STAGE_COMPUTE_BIT);
// We shouldn't need a fragment shader but add it to be able to run on more devices
}
void CreateComputePipelineHelper::InitState() {
descriptor_set_.reset(new OneOffDescriptorSet(layer_test_.DeviceObj(), dsl_bindings_));
ASSERT_TRUE(descriptor_set_->Initialized());
const std::vector<VkPushConstantRange> push_ranges(
pipeline_layout_ci_.pPushConstantRanges,
pipeline_layout_ci_.pPushConstantRanges + pipeline_layout_ci_.pushConstantRangeCount);
pipeline_layout_ = vkt::PipelineLayout(*layer_test_.DeviceObj(), {&descriptor_set_->layout_}, push_ranges);
InitPipelineCache();
}
void CreateComputePipelineHelper::InitPipelineCache() {
if (pipeline_cache_ != VK_NULL_HANDLE) {
vk::DestroyPipelineCache(layer_test_.device(), pipeline_cache_, nullptr);
}
VkResult err = vk::CreatePipelineCache(layer_test_.device(), &pc_ci_, NULL, &pipeline_cache_);
ASSERT_EQ(VK_SUCCESS, err);
}
void CreateComputePipelineHelper::LateBindPipelineInfo() {
// By value or dynamically located items must be late bound
if (cp_ci_.layout == VK_NULL_HANDLE) {
cp_ci_.layout = pipeline_layout_.handle();
}
cp_ci_.stage = cs_.get()->GetStageCreateInfo();
}
VkResult CreateComputePipelineHelper::CreateComputePipeline(bool do_late_bind) {
if (do_late_bind) {
LateBindPipelineInfo();
}
return vk::CreateComputePipelines(layer_test_.device(), pipeline_cache_, 1, &cp_ci_, NULL, &pipeline_);
}
RayTracingPipelineHelper::RayTracingPipelineHelper(VkLayerTest &test) : layer_test_(test) { InitInfo(); }
RayTracingPipelineHelper::~RayTracingPipelineHelper() {
VkDevice device = layer_test_.device();
if (pipeline_cache_ != VK_NULL_HANDLE) {
vk::DestroyPipelineCache(device, pipeline_cache_, nullptr);
pipeline_cache_ = VK_NULL_HANDLE;
}
if (pipeline_ != VK_NULL_HANDLE) {
vk::DestroyPipeline(device, pipeline_, nullptr);
pipeline_ = VK_NULL_HANDLE;
}
}
void RayTracingPipelineHelper::InitShaderGroups() {
{
VkRayTracingShaderGroupCreateInfoNV group = vku::InitStructHelper();
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
group.generalShader = 0;
group.closestHitShader = VK_SHADER_UNUSED_NV;
group.anyHitShader = VK_SHADER_UNUSED_NV;
group.intersectionShader = VK_SHADER_UNUSED_NV;
groups_.push_back(group);
}
{
VkRayTracingShaderGroupCreateInfoNV group = vku::InitStructHelper();
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV;
group.generalShader = VK_SHADER_UNUSED_NV;
group.closestHitShader = 1;
group.anyHitShader = VK_SHADER_UNUSED_NV;
group.intersectionShader = VK_SHADER_UNUSED_NV;
groups_.push_back(group);
}
{
VkRayTracingShaderGroupCreateInfoNV group = vku::InitStructHelper();
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
group.generalShader = 2;
group.closestHitShader = VK_SHADER_UNUSED_NV;
group.anyHitShader = VK_SHADER_UNUSED_NV;
group.intersectionShader = VK_SHADER_UNUSED_NV;
groups_.push_back(group);
}
}
void RayTracingPipelineHelper::InitShaderGroupsKHR() {
{
VkRayTracingShaderGroupCreateInfoKHR group = vku::InitStructHelper();
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
group.generalShader = 0;
group.closestHitShader = VK_SHADER_UNUSED_KHR;
group.anyHitShader = VK_SHADER_UNUSED_KHR;
group.intersectionShader = VK_SHADER_UNUSED_KHR;
groups_KHR_.push_back(group);
}
{
VkRayTracingShaderGroupCreateInfoKHR group = vku::InitStructHelper();
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
group.generalShader = VK_SHADER_UNUSED_KHR;
group.closestHitShader = 1;
group.anyHitShader = VK_SHADER_UNUSED_KHR;
group.intersectionShader = VK_SHADER_UNUSED_KHR;
groups_KHR_.push_back(group);
}
{
VkRayTracingShaderGroupCreateInfoKHR group = vku::InitStructHelper();
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
group.generalShader = 2;
group.closestHitShader = VK_SHADER_UNUSED_KHR;
group.anyHitShader = VK_SHADER_UNUSED_KHR;
group.intersectionShader = VK_SHADER_UNUSED_KHR;
groups_KHR_.push_back(group);
}
}
void RayTracingPipelineHelper::InitDescriptorSetInfo() {
dsl_bindings_ = {
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_NV, nullptr},
{1, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1, VK_SHADER_STAGE_RAYGEN_BIT_NV, nullptr},
};
}
void RayTracingPipelineHelper::InitDescriptorSetInfoKHR() {
dsl_bindings_ = {
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR, nullptr},
{1, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR, nullptr},
};
}
void RayTracingPipelineHelper::InitPipelineLayoutInfo() {
pipeline_layout_ci_ = vku::InitStructHelper();
pipeline_layout_ci_.setLayoutCount = 1; // Not really changeable because InitState() sets exactly one pSetLayout
pipeline_layout_ci_.pSetLayouts = nullptr; // must bound after it is created
}
void RayTracingPipelineHelper::InitShaderInfoKHR() {
rgs_ = std::make_unique<VkShaderObj>(&layer_test_, kRayGenGlsl, VK_SHADER_STAGE_RAYGEN_BIT_KHR, SPV_ENV_VULKAN_1_2);
chs_ = std::make_unique<VkShaderObj>(&layer_test_, kRayTracingPayloadMinimalGlsl, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
SPV_ENV_VULKAN_1_2);
mis_ = std::make_unique<VkShaderObj>(&layer_test_, kMissGlsl, VK_SHADER_STAGE_MISS_BIT_KHR, SPV_ENV_VULKAN_1_2);
shader_stages_ = {rgs_->GetStageCreateInfo(), chs_->GetStageCreateInfo(), mis_->GetStageCreateInfo()};
}
void RayTracingPipelineHelper::InitShaderInfo() { // DONE
static const char rayGenShaderText[] = R"glsl(
#version 460 core
#extension GL_NV_ray_tracing : require
layout(set = 0, binding = 0, rgba8) uniform image2D image;
layout(set = 0, binding = 1) uniform accelerationStructureNV as;
layout(location = 0) rayPayloadNV float payload;
void main()
{
vec4 col = vec4(0, 0, 0, 1);
vec3 origin = vec3(float(gl_LaunchIDNV.x)/float(gl_LaunchSizeNV.x), float(gl_LaunchIDNV.y)/float(gl_LaunchSizeNV.y), 1.0);
vec3 dir = vec3(0.0, 0.0, -1.0);
payload = 0.5;
traceNV(as, gl_RayFlagsCullBackFacingTrianglesNV, 0xff, 0, 1, 0, origin, 0.0, dir, 1000.0, 0);
col.y = payload;
imageStore(image, ivec2(gl_LaunchIDNV.xy), col);
}
)glsl";
static char const closestHitShaderText[] = R"glsl(
#version 460 core
#extension GL_NV_ray_tracing : require
layout(location = 0) rayPayloadInNV float hitValue;
void main() {
hitValue = 1.0;
}
)glsl";
static char const missShaderText[] = R"glsl(
#version 460 core
#extension GL_NV_ray_tracing : require
layout(location = 0) rayPayloadInNV float hitValue;
void main() {
hitValue = 0.0;
}
)glsl";
rgs_ = std::make_unique<VkShaderObj>(&layer_test_, rayGenShaderText, VK_SHADER_STAGE_RAYGEN_BIT_NV);
chs_ = std::make_unique<VkShaderObj>(&layer_test_, closestHitShaderText, VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV);
mis_ = std::make_unique<VkShaderObj>(&layer_test_, missShaderText, VK_SHADER_STAGE_MISS_BIT_NV);
shader_stages_ = {rgs_->GetStageCreateInfo(), chs_->GetStageCreateInfo(), mis_->GetStageCreateInfo()};
}
void RayTracingPipelineHelper::InitNVRayTracingPipelineInfo() {
rp_ci_ = vku::InitStructHelper();
rp_ci_.maxRecursionDepth = 0;
rp_ci_.stageCount = shader_stages_.size();
rp_ci_.pStages = shader_stages_.data();
rp_ci_.groupCount = groups_.size();
rp_ci_.pGroups = groups_.data();
}
void RayTracingPipelineHelper::InitKHRRayTracingPipelineInfo(VkPipelineCreateFlags flags) {
rp_ci_KHR_ = vku::InitStructHelper();
rp_ci_KHR_.flags = flags;
rp_ci_KHR_.maxPipelineRayRecursionDepth = 0;
rp_ci_KHR_.stageCount = shader_stages_.size();
rp_ci_KHR_.pStages = shader_stages_.data();
rp_ci_KHR_.groupCount = groups_KHR_.size();
rp_ci_KHR_.pGroups = groups_KHR_.data();
}
void RayTracingPipelineHelper::AddLibrary(const RayTracingPipelineHelper &library) {
libraries_.emplace_back(library.pipeline_);
rp_library_ci_ = vku::InitStructHelper();
rp_library_ci_.libraryCount = size32(libraries_);
rp_library_ci_.pLibraries = libraries_.data();
rp_ci_KHR_.pLibraryInfo = &rp_library_ci_;
}
void RayTracingPipelineHelper::InitPipelineCacheInfo() {
pc_ci_ = vku::InitStructHelper();
pc_ci_.flags = 0;
pc_ci_.initialDataSize = 0;
pc_ci_.pInitialData = nullptr;
}
void RayTracingPipelineHelper::InitInfo(bool isKHR) {
isKHR ? InitShaderGroupsKHR() : InitShaderGroups();
isKHR ? InitDescriptorSetInfoKHR() : InitDescriptorSetInfo();
InitPipelineLayoutInfo();
isKHR ? InitShaderInfoKHR() : InitShaderInfo();
isKHR ? InitKHRRayTracingPipelineInfo() : InitNVRayTracingPipelineInfo();
InitPipelineCacheInfo();
}
void RayTracingPipelineHelper::InitLibraryInfoKHR(VkPipelineCreateFlags flags) {
InitShaderGroupsKHR();
InitDescriptorSetInfoKHR();
InitPipelineLayoutInfo();
InitShaderInfoKHR();
InitKHRRayTracingPipelineInfo(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | flags);
VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_pipeline_props = vku::InitStructHelper();
layer_test_.GetPhysicalDeviceProperties2(ray_tracing_pipeline_props);
rp_i_ci_ = vku::InitStructHelper();
rp_i_ci_->maxPipelineRayPayloadSize = sizeof(float); // Set according to payload defined in kRayGenShaderText
rp_i_ci_->maxPipelineRayHitAttributeSize = ray_tracing_pipeline_props.maxRayHitAttributeSize;
rp_ci_KHR_.pLibraryInterface = &rp_i_ci_.value();
InitPipelineCacheInfo();
}
void RayTracingPipelineHelper::InitState() {
descriptor_set_.reset(new OneOffDescriptorSet(layer_test_.DeviceObj(), dsl_bindings_));
ASSERT_TRUE(descriptor_set_->Initialized());
pipeline_layout_ = vkt::PipelineLayout(*layer_test_.DeviceObj(), {&descriptor_set_->layout_});
InitPipelineCache();
}
void RayTracingPipelineHelper::InitPipelineCache() {
if (pipeline_cache_ != VK_NULL_HANDLE) {
vk::DestroyPipelineCache(layer_test_.device(), pipeline_cache_, nullptr);
}
VkResult err = vk::CreatePipelineCache(layer_test_.device(), &pc_ci_, NULL, &pipeline_cache_);
ASSERT_EQ(VK_SUCCESS, err);
}
void RayTracingPipelineHelper::LateBindPipelineInfo(bool isKHR) {
// By value or dynamically located items must be late bound
if (isKHR) {
rp_ci_KHR_.layout = pipeline_layout_.handle();
rp_ci_KHR_.stageCount = shader_stages_.size();
rp_ci_KHR_.pStages = shader_stages_.data();
} else {
rp_ci_.layout = pipeline_layout_.handle();
rp_ci_.stageCount = shader_stages_.size();
rp_ci_.pStages = shader_stages_.data();
}
}
VkResult RayTracingPipelineHelper::CreateNVRayTracingPipeline(bool do_late_bind) {
if (do_late_bind) {
LateBindPipelineInfo();
}
PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV =
(PFN_vkCreateRayTracingPipelinesNV)vk::GetInstanceProcAddr(layer_test_.instance(), "vkCreateRayTracingPipelinesNV");
return vkCreateRayTracingPipelinesNV(layer_test_.device(), pipeline_cache_, 1, &rp_ci_, nullptr, &pipeline_);
}
VkResult RayTracingPipelineHelper::CreateKHRRayTracingPipeline(bool do_late_bind) {
if (do_late_bind) {
LateBindPipelineInfo(true /*isKHR*/);
}
return vk::CreateRayTracingPipelinesKHR(layer_test_.device(), 0, pipeline_cache_, 1, &rp_ci_KHR_, nullptr, &pipeline_);
}
void SetDefaultDynamicStates(VkCommandBuffer cmdBuffer) {
uint32_t width = 32;
uint32_t height = 32;
VkViewport viewport = {0, 0, static_cast<float>(width), static_cast<float>(height), 0.0f, 1.0f};
VkRect2D scissor = {{0, 0}, {width, height}};
vk::CmdSetViewportWithCountEXT(cmdBuffer, 1u, &viewport);
vk::CmdSetScissorWithCountEXT(cmdBuffer, 1u, &scissor);
vk::CmdSetLineWidth(cmdBuffer, 1.0f);
vk::CmdSetDepthBias(cmdBuffer, 1.0f, 0.0f, 1.0f);
float blendConstants[4] = {1.0f, 1.0f, 1.0f, 1.0f};
vk::CmdSetBlendConstants(cmdBuffer, blendConstants);
vk::CmdSetDepthBounds(cmdBuffer, 0.0f, 1.0f);
vk::CmdSetStencilCompareMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFFFFFFF);
vk::CmdSetStencilWriteMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFFFFFFF);
vk::CmdSetStencilReference(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFFFFFFF);
vk::CmdSetCullModeEXT(cmdBuffer, VK_CULL_MODE_NONE);
vk::CmdSetDepthBoundsTestEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetDepthCompareOpEXT(cmdBuffer, VK_COMPARE_OP_NEVER);
vk::CmdSetDepthTestEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetDepthWriteEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetFrontFaceEXT(cmdBuffer, VK_FRONT_FACE_CLOCKWISE);
vk::CmdSetPrimitiveTopologyEXT(cmdBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
vk::CmdSetStencilOpEXT(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP,
VK_COMPARE_OP_NEVER);
vk::CmdSetStencilTestEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetDepthBiasEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetPrimitiveRestartEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetRasterizerDiscardEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetVertexInputEXT(cmdBuffer, 0u, nullptr, 0u, nullptr);
vk::CmdSetLogicOpEXT(cmdBuffer, VK_LOGIC_OP_COPY);
vk::CmdSetPatchControlPointsEXT(cmdBuffer, 4u);
vk::CmdSetTessellationDomainOriginEXT(cmdBuffer, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT);
vk::CmdSetDepthClampEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetPolygonModeEXT(cmdBuffer, VK_POLYGON_MODE_FILL);
vk::CmdSetRasterizationSamplesEXT(cmdBuffer, VK_SAMPLE_COUNT_1_BIT);
VkSampleMask sampleMask = 0xFFFFFFFF;
vk::CmdSetSampleMaskEXT(cmdBuffer, VK_SAMPLE_COUNT_1_BIT, &sampleMask);
vk::CmdSetAlphaToCoverageEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetAlphaToOneEnableEXT(cmdBuffer, VK_FALSE);
vk::CmdSetLogicOpEnableEXT(cmdBuffer, VK_FALSE);
VkBool32 colorBlendEnable = VK_FALSE;
vk::CmdSetColorBlendEnableEXT(cmdBuffer, 0u, 1u, &colorBlendEnable);
VkColorBlendEquationEXT colorBlendEquation = {
VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD,
};
vk::CmdSetColorBlendEquationEXT(cmdBuffer, 0u, 1u, &colorBlendEquation);
VkColorComponentFlags colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
vk::CmdSetColorWriteMaskEXT(cmdBuffer, 0u, 1u, &colorWriteMask);
}