| /* |
| * Copyright (c) 2015-2026 The Khronos Group Inc. |
| * Copyright (c) 2015-2026 Valve Corporation |
| * Copyright (c) 2015-2026 LunarG, Inc. |
| * Copyright (c) 2015-2026 Google, 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 <spirv-tools/libspirv.h> |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| #include "../framework/descriptor_helper.h" |
| #include "test_framework.h" |
| |
| void GraphicsLibraryTest::InitBasicGraphicsLibrary() { |
| AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary); |
| RETURN_IF_SKIP(Init()); |
| } |
| |
| class PositiveGraphicsLibrary : public GraphicsLibraryTest {}; |
| |
| TEST_F(PositiveGraphicsLibrary, VertexInput) { |
| TEST_DESCRIPTION("Create a vertex input graphics library"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitVertexInputLibInfo(); |
| pipe.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, PreRaster) { |
| TEST_DESCRIPTION("Create a pre-raster graphics library"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| InitRenderTarget(); |
| |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pipe.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, FragmentShader) { |
| TEST_DESCRIPTION("Create a fragment shader graphics library"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pipe(*this); |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| pipe.InitFragmentLibInfo(&fs_stage.stage_ci); |
| pipe.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, FragmentOutput) { |
| TEST_DESCRIPTION("Create a fragment output graphics library"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitFragmentOutputLibInfo(); |
| pipe.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, FragmentMixedAttachmentSamplesAMD) { |
| TEST_DESCRIPTION("Create a fragment graphics library with mixed attachement sample support"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitFragmentOutputLibInfo(); |
| pipe.gp_ci_.pRasterizationState = nullptr; |
| |
| pipe.gp_ci_.pRasterizationState = nullptr; |
| |
| // Ensure validation runs with pRasterizationState being nullptr. |
| // It's legal for this fragment library to not have a raster state defined. |
| ASSERT_TRUE(pipe.gp_ci_.pRasterizationState == nullptr); |
| |
| pipe.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, ExeLibrary) { |
| TEST_DESCRIPTION("Create an executable library by linking one or more graphics libraries"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| // Note - Don't need renderPass when doing full link |
| // https://gitlab.khronos.org/vulkan/vulkan/-/issues/3764#note_451564 |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pre_raster_lib.gp_ci_.layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, CombinedShaderSubsets) { |
| TEST_DESCRIPTION("Build Pre-Rasterization and Fragment Shader stage together"); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper shader_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| std::vector<VkPipelineShaderStageCreateInfo> stages = {vs_stage.stage_ci, fs_stage.stage_ci}; |
| shader_lib.InitShaderLibInfo(stages); |
| shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[3] = { |
| vertex_input_lib, |
| shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = shader_lib.gp_ci_.layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DrawWithNullDSLs) { |
| TEST_DESCRIPTION("Make a draw with a pipeline layout derived from null DSLs"); |
| |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| // Prepare descriptors |
| OneOffDescriptorSet ds(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet ds2(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| }); |
| |
| // We _vs and _fs layouts are identical, but we want them to be separate handles handles for the sake layout merging |
| vkt::PipelineLayout pipeline_layout_vs(*m_device, {&ds.layout_, &ds.layout_, nullptr}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_fs(*m_device, {&ds.layout_, nullptr, &ds2.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_null(*m_device, {&ds.layout_, nullptr, nullptr}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| const std::array<VkDescriptorSet, 3> desc_sets = {ds.set_, VK_NULL_HANDLE, VK_NULL_HANDLE}; |
| |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| ds.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds.UpdateDescriptorSets(); |
| ds2.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds2.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const char vs_src[] = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform foo { float x; } bar; |
| void main() { |
| gl_Position = vec4(bar.x); |
| } |
| )glsl"; |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_src); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout_vs; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout_fs; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pipeline_layout_null; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| // Draw with pipeline created with null set |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_null, 0, |
| static_cast<uint32_t>(desc_sets.size()), desc_sets.data(), 0, nullptr); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, MultipleIndependentSetsUsed) { |
| TEST_DESCRIPTION("Main issues with other variations is they are not statically using the sets in the shader"); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| OneOffDescriptorSet ds_v(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet ds_f(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet ds_extra_v(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet ds_extra_f(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| }); |
| |
| vkt::PipelineLayout pipeline_layout_vs(*m_device, {nullptr, &ds_v.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_fs(*m_device, {&ds_f.layout_}, {}, VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_null(*m_device, {nullptr, nullptr}, {}, VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_link(*m_device, {&ds_extra_f.layout_, &ds_extra_v.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| ds_v.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds_v.UpdateDescriptorSets(); |
| ds_f.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds_f.UpdateDescriptorSets(); |
| ds_extra_v.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds_extra_v.UpdateDescriptorSets(); |
| ds_extra_f.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds_extra_f.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const char* vs_src = R"glsl( |
| #version 450 |
| layout(set=1, binding=0) uniform foo { vec4 x; }; |
| void main() { |
| gl_Position = x; |
| } |
| )glsl"; |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_src); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout_vs; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const char* fs_src = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform UBO { |
| vec4 data; |
| }; |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = data; |
| } |
| )glsl"; |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fs_src); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout_fs; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pipeline_layout_null; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| // Draw with pipeline created with null set |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| const VkDescriptorSet set_handles[2] = {ds_extra_f.set_, ds_v.set_}; |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_link, 0, 2, set_handles, 0, |
| nullptr); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, VertexInputAttributeDescriptionOffset) { |
| TEST_DESCRIPTION("Test VUID-VkVertexInputAttributeDescription-offset-00622: is not trigged with graphics library"); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| VkPhysicalDeviceProperties device_props = {}; |
| vk::GetPhysicalDeviceProperties(Gpu(), &device_props); |
| if (device_props.limits.maxVertexInputAttributeOffset == 0xFFFFFFFF) { |
| GTEST_SKIP() << "maxVertexInputAttributeOffset is max<uint32_t> already"; |
| } |
| |
| InitRenderTarget(); |
| |
| VkVertexInputBindingDescription vertex_input_binding_description{}; |
| vertex_input_binding_description.binding = 0; |
| vertex_input_binding_description.stride = m_device->Physical().limits_.maxVertexInputBindingStride; |
| vertex_input_binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
| // Test when offset is greater than maximum. |
| VkVertexInputAttributeDescription vertex_input_attribute_description{}; |
| vertex_input_attribute_description.format = VK_FORMAT_R8_UNORM; |
| vertex_input_attribute_description.offset = device_props.limits.maxVertexInputAttributeOffset + 1; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| // override vertex input |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.vi_ci_.pVertexBindingDescriptions = &vertex_input_binding_description; |
| frag_shader_lib.vi_ci_.vertexBindingDescriptionCount = 1; |
| frag_shader_lib.vi_ci_.pVertexAttributeDescriptions = &vertex_input_attribute_description; |
| frag_shader_lib.vi_ci_.vertexAttributeDescriptionCount = 1; |
| frag_shader_lib.gp_ci_.pVertexInputState = &frag_shader_lib.vi_ci_; |
| |
| // VUID-VkVertexInputAttributeDescription-offset-00622 shouldn't be trigged |
| frag_shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, VertexAttributeDivisorInstanceRateZero) { |
| TEST_DESCRIPTION("VK_EXT_vertex_attribute_divisor is not checked with VK_EXT_graphics_pipeline_library"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| InitRenderTarget(); |
| |
| VkVertexInputBindingDivisorDescription divisor_description = {}; |
| divisor_description.binding = 0; |
| divisor_description.divisor = 0; |
| VkPipelineVertexInputDivisorStateCreateInfo divisor_state_create_info = vku::InitStructHelper(); |
| divisor_state_create_info.vertexBindingDivisorCount = 1; |
| divisor_state_create_info.pVertexBindingDivisors = &divisor_description; |
| VkVertexInputBindingDescription vertex_input_binding_description = {divisor_description.binding, 12, |
| VK_VERTEX_INPUT_RATE_INSTANCE}; |
| VkVertexInputAttributeDescription vertex_input_attribute_description = {0, 0, VK_FORMAT_R8_UNORM, 0}; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| |
| // override vertex input |
| frag_shader_lib.vi_ci_.pNext = &divisor_state_create_info; |
| frag_shader_lib.vi_ci_.pVertexBindingDescriptions = &vertex_input_binding_description; |
| frag_shader_lib.vi_ci_.vertexBindingDescriptionCount = 1; |
| frag_shader_lib.vi_ci_.pVertexAttributeDescriptions = &vertex_input_attribute_description; |
| frag_shader_lib.vi_ci_.vertexAttributeDescriptionCount = 1; |
| frag_shader_lib.gp_ci_.pVertexInputState = &frag_shader_lib.vi_ci_; |
| |
| // VUID-VkVertexInputBindingDivisorDescription-vertexAttributeInstanceRateZeroDivisor-02228 shouldn't be trigged |
| frag_shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, NotAttachmentDynamicBlendEnable) { |
| TEST_DESCRIPTION("make sure using an empty pAttachments doesn't crash a GPL pipeline"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dualSrcBlend); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorWriteMask); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendAdvanced); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitFragmentOutputLibInfo(); |
| pipe.cb_ci_.pAttachments = nullptr; |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT); |
| pipe.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DynamicPrimitiveTopolgyAllState) { |
| TEST_DESCRIPTION("VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY works when GPL sets it in every state"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkDynamicState dynamic_states[1] = {VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY}; |
| VkPipelineDynamicStateCreateInfo dynamic_create_info = vku::InitStructHelper(); |
| dynamic_create_info.pDynamicStates = dynamic_states; |
| dynamic_create_info.dynamicStateCount = 1; |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| VkPipelineInputAssemblyStateCreateInfo ia_state = vku::InitStructHelper(); |
| ia_state.primitiveRestartEnable = false; |
| ia_state.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.gp_ci_.pDynamicState = &dynamic_create_info; |
| vertex_input_lib.gp_ci_.pInputAssemblyState = &ia_state; |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| // change here and make sure other libraries don't consume this |
| ia_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.pDynamicState = &dynamic_create_info; |
| pre_raster_lib.gp_ci_.pInputAssemblyState = &ia_state; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.gp_ci_.pDynamicState = &dynamic_create_info; |
| frag_shader_lib.gp_ci_.pInputAssemblyState = &ia_state; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.gp_ci_.pDynamicState = &dynamic_create_info; |
| frag_out_lib.gp_ci_.pInputAssemblyState = &ia_state; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.pInputAssemblyState = &ia_state; |
| exe_pipe_ci.pDynamicState = &dynamic_create_info; |
| exe_pipe_ci.layout = layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| vk::CmdSetPrimitiveTopology(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_LINE_LIST); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DynamicPrimitiveTopolgyVertexStateAndLinked) { |
| TEST_DESCRIPTION("set VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY in Vertex State only and at Link time"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkDynamicState dynamic_states[1] = {VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY}; |
| VkPipelineDynamicStateCreateInfo dynamic_create_info = vku::InitStructHelper(); |
| dynamic_create_info.pDynamicStates = dynamic_states; |
| dynamic_create_info.dynamicStateCount = 1; |
| |
| // Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| VkRenderPass render_pass = VK_NULL_HANDLE; |
| uint32_t subpass = 0; |
| |
| VkPipelineInputAssemblyStateCreateInfo ia_state = vku::InitStructHelper(); |
| ia_state.primitiveRestartEnable = false; |
| ia_state.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.gp_ci_.pDynamicState = &dynamic_create_info; |
| vertex_input_lib.gp_ci_.pInputAssemblyState = &ia_state; |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| // change here and make sure other libraries don't consume this |
| ia_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| render_pass = pre_raster_lib.gp_ci_.renderPass; |
| subpass = pre_raster_lib.gp_ci_.subpass; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.gp_ci_.renderPass = render_pass; |
| frag_shader_lib.gp_ci_.subpass = subpass; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.gp_ci_.renderPass = render_pass; |
| frag_out_lib.gp_ci_.subpass = subpass; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.pInputAssemblyState = &ia_state; |
| exe_pipe_ci.pDynamicState = &dynamic_create_info; |
| exe_pipe_ci.layout = layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| vk::CmdSetPrimitiveTopology(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_LINE_LIST); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DynamicPrimitiveTopolgyVertexStateOnly) { |
| TEST_DESCRIPTION("set VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY in Vertex State only, but not at Link time"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| // Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| VkRenderPass render_pass = VK_NULL_HANDLE; |
| uint32_t subpass = 0; |
| |
| VkPipelineInputAssemblyStateCreateInfo ia_state = vku::InitStructHelper(); |
| ia_state.primitiveRestartEnable = false; |
| ia_state.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY); |
| vertex_input_lib.gp_ci_.pInputAssemblyState = &ia_state; |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| // change here and make sure other libraries don't consume this |
| ia_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| render_pass = pre_raster_lib.gp_ci_.renderPass; |
| subpass = pre_raster_lib.gp_ci_.subpass; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.gp_ci_.renderPass = render_pass; |
| frag_shader_lib.gp_ci_.subpass = subpass; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.gp_ci_.renderPass = render_pass; |
| frag_out_lib.gp_ci_.subpass = subpass; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| vk::CmdSetPrimitiveTopology(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_LINE_LIST); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DynamicAlphaToOneEnableFragmentOutput) { |
| TEST_DESCRIPTION("set VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT in Fragment Output"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::alphaToOne); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToOneEnable); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| // Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| VkRenderPass render_pass = VK_NULL_HANDLE; |
| uint32_t subpass = 0; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| render_pass = pre_raster_lib.gp_ci_.renderPass; |
| subpass = pre_raster_lib.gp_ci_.subpass; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.gp_ci_.renderPass = render_pass; |
| frag_shader_lib.gp_ci_.subpass = subpass; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.gp_ci_.renderPass = render_pass; |
| frag_out_lib.gp_ci_.subpass = subpass; |
| frag_out_lib.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| vk::CmdSetAlphaToOneEnableEXT(m_command_buffer, VK_TRUE); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DynamicAlphaToOneEnableFragmentShader) { |
| TEST_DESCRIPTION("set VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT in Fragment Shader"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToOneEnable); |
| AddRequiredFeature(vkt::Feature::alphaToOne); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| // Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| VkRenderPass render_pass = VK_NULL_HANDLE; |
| uint32_t subpass = 0; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| render_pass = pre_raster_lib.gp_ci_.renderPass; |
| subpass = pre_raster_lib.gp_ci_.subpass; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.gp_ci_.renderPass = render_pass; |
| frag_shader_lib.gp_ci_.subpass = subpass; |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT); |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.gp_ci_.renderPass = render_pass; |
| frag_out_lib.gp_ci_.subpass = subpass; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| vk::CmdSetAlphaToOneEnableEXT(m_command_buffer, VK_TRUE); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, FragmentShaderNoStageCount) { |
| TEST_DESCRIPTION("Don't need a stageCount if only have fragment shader library"); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| vkt::PipelineLayout pipeline_layout(*m_device); |
| CreatePipelineHelper frag_shader_lib(*this); |
| frag_shader_lib.InitFragmentLibInfo(nullptr); |
| frag_shader_lib.gp_ci_.stageCount = 0; |
| frag_shader_lib.shader_stages_.clear(); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, LinkingInputAttachment) { |
| TEST_DESCRIPTION("Make sure OpCapability InputAttachment is not detected at linking time"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| // kFragmentMinimalGlsl with manually added OpCapability |
| const char fs_src[] = R"( |
| OpCapability Shader |
| OpCapability InputAttachment |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" %uFragColor |
| OpExecutionMode %main OriginUpperLeft |
| OpDecorate %uFragColor Location 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v4float = OpTypeVector %float 4 |
| %_ptr_Output_v4float = OpTypePointer Output %v4float |
| %uFragColor = OpVariable %_ptr_Output_v4float Output |
| %float_0 = OpConstant %float 0 |
| %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpStore %uFragColor %12 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| std::vector<uint32_t> fs_spv; |
| ASMtoSPV(SPV_ENV_VULKAN_1_0, 0, fs_src, fs_spv); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, FSIgnoredPointerGPLDynamicRendering) { |
| TEST_DESCRIPTION("Check ignored pointers with dynamics rendering and GPL"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu()); |
| m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); |
| m_depthStencil->SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); |
| InitRenderTarget(&depth_image_view.handle()); |
| |
| // Create a full pipeline with the same bad rendering info, but enable rasterizer discard to ignore the bad data |
| CreatePipelineHelper vi_lib(*this); |
| vi_lib.InitVertexInputLibInfo(); |
| vi_lib.CreateGraphicsPipeline(); |
| |
| // Create an executable pipeline with rasterization disabled |
| // Pass rendering info with null pointers that should be ignored |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.colorAttachmentCount = 2; // <- bad data that should be ignored |
| |
| CreatePipelineHelper fs_lib(*this); |
| { |
| VkStencilOpState stencil = {}; |
| stencil.failOp = VK_STENCIL_OP_KEEP; |
| stencil.passOp = VK_STENCIL_OP_KEEP; |
| stencil.depthFailOp = VK_STENCIL_OP_KEEP; |
| stencil.compareOp = VK_COMPARE_OP_NEVER; |
| |
| VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper(); |
| ds_ci.depthTestEnable = VK_FALSE; |
| ds_ci.depthWriteEnable = VK_TRUE; |
| ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER; |
| ds_ci.depthBoundsTestEnable = VK_FALSE; |
| ds_ci.stencilTestEnable = VK_TRUE; |
| ds_ci.front = stencil; |
| ds_ci.back = stencil; |
| |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| fs_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &pipeline_rendering_info); |
| fs_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| fs_lib.gp_ci_.pDepthStencilState = &ds_ci; |
| fs_lib.CreateGraphicsPipeline(); |
| } |
| |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| CreatePipelineHelper pr_lib(*this); |
| pr_lib.InitPreRasterLibInfo(&vs_stage.stage_ci, &pipeline_rendering_info); |
| pr_lib.rs_state_ci_.rasterizerDiscardEnable = |
| VK_TRUE; // This should cause the bad info in pipeline_rendering_info to be ignored |
| pr_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| pr_lib.CreateGraphicsPipeline(); |
| |
| VkPipeline libraries[3] = { |
| vi_lib, |
| pr_lib, |
| fs_lib, |
| // fragment output not needed due to rasterization being disabled |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pr_lib.gp_ci_.layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, FSIgnoredPointerGPLDynamicRendering2) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9527"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.pColorAttachmentFormats = reinterpret_cast<VkFormat*>(static_cast<uintptr_t>(0xffffdead)); |
| pipeline_rendering_info.colorAttachmentCount = 2; |
| |
| CreatePipelineHelper vi_lib(*this); |
| vi_lib.InitVertexInputLibInfo(&pipeline_rendering_info); |
| vi_lib.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, GPLDynamicRenderingWithDepthDraw) { |
| TEST_DESCRIPTION("Check ignored pointers with dynamics rendering and GPL"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu()); |
| m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); |
| m_depthStencil->SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); |
| InitRenderTarget(&depth_image_view.handle()); |
| |
| // Create a full pipeline with the same bad rendering info, but enable rasterizer discard to ignore the bad data |
| CreatePipelineHelper vi_lib(*this); |
| vi_lib.InitVertexInputLibInfo(); |
| vi_lib.CreateGraphicsPipeline(); |
| |
| // Create an executable pipeline with rasterization enabled and make a draw call using dynamic rendering |
| CreatePipelineHelper fs_lib(*this); |
| { |
| VkStencilOpState stencil = {}; |
| stencil.failOp = VK_STENCIL_OP_KEEP; |
| stencil.passOp = VK_STENCIL_OP_KEEP; |
| stencil.depthFailOp = VK_STENCIL_OP_KEEP; |
| stencil.compareOp = VK_COMPARE_OP_NEVER; |
| |
| VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper(); |
| ds_ci.depthTestEnable = VK_FALSE; |
| ds_ci.depthWriteEnable = VK_TRUE; |
| ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER; |
| ds_ci.depthBoundsTestEnable = VK_FALSE; |
| ds_ci.stencilTestEnable = VK_TRUE; |
| ds_ci.front = stencil; |
| ds_ci.back = stencil; |
| |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| fs_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| fs_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| fs_lib.gp_ci_.pDepthStencilState = &ds_ci; |
| fs_lib.CreateGraphicsPipeline(); |
| } |
| |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| CreatePipelineHelper pr_lib(*this); |
| pr_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pr_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| pr_lib.CreateGraphicsPipeline(); |
| |
| VkFormat color_formats = VK_FORMAT_UNDEFINED; |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_formats; |
| pipeline_rendering_info.depthAttachmentFormat = m_depth_stencil_fmt; |
| |
| CreatePipelineHelper fo_lib(*this); |
| fo_lib.InitFragmentOutputLibInfo(&pipeline_rendering_info); |
| fo_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| fo_lib.CreateGraphicsPipeline(false); |
| |
| // Create an executable pipeline with rasterization disabled |
| VkPipeline libraries[4] = { |
| vi_lib, |
| pr_lib, |
| fs_lib, |
| fo_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pr_lib.gp_ci_.layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| vkt::ImageView depth_stencil_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); |
| VkRenderingAttachmentInfo depth_attachment = vku::InitStructHelper(); |
| depth_attachment.imageView = depth_stencil_view; |
| depth_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.colorAttachmentCount = 1; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.pDepthAttachment = &depth_attachment; |
| begin_rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(begin_rendering_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DepthState) { |
| TEST_DESCRIPTION("Create a GPL with depth state"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu()); |
| m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); |
| m_depthStencil->SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); |
| InitRenderTarget(&depth_image_view.handle()); |
| |
| CreatePipelineHelper fs_lib(*this); |
| { |
| VkStencilOpState stencil = {}; |
| stencil.failOp = VK_STENCIL_OP_KEEP; |
| stencil.passOp = VK_STENCIL_OP_KEEP; |
| stencil.depthFailOp = VK_STENCIL_OP_KEEP; |
| stencil.compareOp = VK_COMPARE_OP_NEVER; |
| |
| VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper(); |
| ds_ci.depthTestEnable = VK_FALSE; |
| ds_ci.depthWriteEnable = VK_TRUE; |
| ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER; |
| ds_ci.depthBoundsTestEnable = VK_FALSE; |
| ds_ci.stencilTestEnable = VK_FALSE; |
| ds_ci.front = stencil; |
| ds_ci.back = stencil; |
| |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| fs_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| fs_lib.gp_ci_.pDepthStencilState = &ds_ci; |
| fs_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper vi_lib(*this); |
| vi_lib.InitVertexInputLibInfo(); |
| vi_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper fo_lib(*this); |
| fo_lib.InitFragmentOutputLibInfo(); |
| fo_lib.CreateGraphicsPipeline(false); |
| |
| // Create a GPL and subpass that utilizes depth |
| { |
| CreatePipelineHelper pr_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| pr_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pr_lib.CreateGraphicsPipeline(); |
| } |
| |
| VkPipeline libraries[4] = { |
| vi_lib, |
| pr_lib, |
| fs_lib, |
| fo_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pr_lib.gp_ci_.layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| // Create a GPL and subpass that utilizes depth, but specifies rasterizerDiscardEnabled dynamically |
| CreatePipelineHelper pr_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| pr_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pr_lib.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE; // This should get ignored due to its state being set as dynamic |
| pr_lib.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE); |
| pr_lib.gp_ci_.layout = fs_lib.gp_ci_.layout; |
| pr_lib.CreateGraphicsPipeline(false); |
| } |
| |
| VkPipeline libraries[4] = { |
| vi_lib, |
| pr_lib, |
| fs_lib, |
| fo_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pr_lib.gp_ci_.layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, FOIgnoredDynamicRendering) { |
| TEST_DESCRIPTION("Check ignored pointers with dynamics rendering and no fragment output state"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu()); |
| m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); |
| m_depthStencil->SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); |
| InitRenderTarget(&depth_image_view.handle()); |
| |
| // Create an executable pipeline with rasterization disabled |
| // Pass rendering info with null pointers that should be ignored |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.colorAttachmentCount = 2; // <- bad data that should be ignored |
| |
| VkGraphicsPipelineLibraryCreateInfoEXT lib_info = vku::InitStructHelper(&pipeline_rendering_info); |
| lib_info.flags = |
| VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT | VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT; |
| |
| VkStencilOpState stencil = {}; |
| stencil.failOp = VK_STENCIL_OP_KEEP; |
| stencil.passOp = VK_STENCIL_OP_KEEP; |
| stencil.depthFailOp = VK_STENCIL_OP_KEEP; |
| stencil.compareOp = VK_COMPARE_OP_NEVER; |
| |
| VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper(); |
| ds_ci.depthTestEnable = VK_FALSE; |
| ds_ci.depthWriteEnable = VK_TRUE; |
| ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER; |
| ds_ci.depthBoundsTestEnable = VK_FALSE; |
| ds_ci.stencilTestEnable = VK_TRUE; |
| ds_ci.front = stencil; |
| ds_ci.back = stencil; |
| |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| std::array stages = {vs_stage.stage_ci, fs_stage.stage_ci}; |
| |
| CreatePipelineHelper lib(*this, &lib_info); |
| lib.gp_ci_.flags |= VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| lib.gp_ci_.pDepthStencilState = &ds_ci; |
| lib.gp_ci_.stageCount = size32(stages); |
| lib.gp_ci_.pStages = stages.data(); |
| |
| // Remove VI and FO state-related pointers |
| lib.gp_ci_.pVertexInputState = nullptr; |
| lib.gp_ci_.pVertexInputState = nullptr; |
| lib.gp_ci_.pColorBlendState = nullptr; |
| lib.gp_ci_.pMultisampleState = nullptr; |
| lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| |
| lib.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, ShaderModuleIdentifier) { |
| TEST_DESCRIPTION("Create pipeline sub-state that references shader module identifiers"); |
| AddRequiredExtensions(VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary); |
| AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl); |
| AddRequiredFeature(vkt::Feature::shaderModuleIdentifier); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| // Create a pre-raster pipeline referencing a VS via identifier, with the VS identifier queried from a shader module |
| VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| ASSERT_TRUE(vs.initialized()); |
| |
| VkShaderModuleIdentifierEXT vs_identifier = vku::InitStructHelper(); |
| vk::GetShaderModuleIdentifierEXT(device(), vs, &vs_identifier); |
| |
| VkPipelineShaderStageModuleIdentifierCreateInfoEXT sm_id_create_info = vku::InitStructHelper(); |
| sm_id_create_info.identifierSize = vs_identifier.identifierSize; |
| sm_id_create_info.pIdentifier = vs_identifier.identifier; |
| |
| VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&sm_id_create_info); |
| stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT; |
| stage_ci.module = VK_NULL_HANDLE; |
| stage_ci.pName = "main"; |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitPreRasterLibInfo(&stage_ci); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT; |
| VkResult result = pipe.CreateGraphicsPipeline(); |
| if (result == VK_PIPELINE_COMPILE_REQUIRED) { |
| GTEST_SKIP() << "This test needs to be ran with driver cache on in order to know about this pipeline"; |
| } |
| |
| // Create a fragment shader library with FS referencing an identifier queried from VkShaderModuleCreateInfo |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| VkShaderModuleCreateInfo fs_ci = vku::InitStructHelper(); |
| fs_ci.codeSize = fs_spv.size() * sizeof(decltype(fs_spv)::value_type); |
| fs_ci.pCode = fs_spv.data(); |
| |
| VkShaderModuleIdentifierEXT fs_identifier = vku::InitStructHelper(); |
| vk::GetShaderModuleCreateInfoIdentifierEXT(device(), &fs_ci, &fs_identifier); |
| |
| sm_id_create_info.identifierSize = fs_identifier.identifierSize; |
| sm_id_create_info.pIdentifier = fs_identifier.identifier; |
| |
| VkPipelineShaderStageCreateInfo fs_stage_ci = vku::InitStructHelper(&sm_id_create_info); |
| fs_stage_ci.stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| fs_stage_ci.module = VK_NULL_HANDLE; |
| fs_stage_ci.pName = "main"; |
| |
| CreatePipelineHelper fs_pipe(*this); |
| fs_pipe.InitFragmentLibInfo(&fs_stage_ci); |
| fs_pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT; |
| fs_pipe.gp_ci_.layout = pipe.gp_ci_.layout; |
| result = fs_pipe.CreateGraphicsPipeline(false); |
| if (result == VK_PIPELINE_COMPILE_REQUIRED) { |
| GTEST_SKIP() << "This test needs to be ran with driver cache on in order to know about this pipeline"; |
| } |
| |
| // Create a complete pipeline with the above pre-raster fs libraries |
| CreatePipelineHelper vi_pipe(*this); |
| vi_pipe.InitVertexInputLibInfo(); |
| vi_pipe.CreateGraphicsPipeline(); |
| |
| CreatePipelineHelper fo_pipe(*this); |
| fo_pipe.InitFragmentOutputLibInfo(); |
| fo_pipe.CreateGraphicsPipeline(); |
| |
| VkPipeline libraries[4] = { |
| vi_pipe, |
| pipe, |
| fs_pipe, |
| fo_pipe, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo pipe_ci = vku::InitStructHelper(&link_info); |
| pipe_ci.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT; |
| pipe_ci.layout = pipe.gp_ci_.layout; |
| pipe_ci.renderPass = RenderPass(); |
| VkPipeline pipeline; |
| result = vk::CreateGraphicsPipelines(device(), VK_NULL_HANDLE, 1u, &pipe_ci, nullptr, &pipeline); |
| ASSERT_TRUE(result == VK_SUCCESS || result == VK_PIPELINE_COMPILE_REQUIRED); |
| if (result == VK_SUCCESS) { |
| vk::DestroyPipeline(device(), pipeline, nullptr); |
| } |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DepthStencilStateIgnored) { |
| TEST_DESCRIPTION("Create a library with fragment shader state, but no fragment output state, and no DS state, but ignored"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| |
| frag_shader_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| frag_shader_lib.gp_ci_.pDepthStencilState = nullptr; |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE); |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE); |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_COMPARE_OP); |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE); |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE); |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_OP); |
| frag_shader_lib.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS); |
| frag_shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, ColorBlendStateIgnored) { |
| TEST_DESCRIPTION("Create a library with fragment output state and invalid ColorBlendState state"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState2LogicOp); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3LogicOpEnable); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorWriteMask); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM; |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| |
| pre_raster_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| pre_raster_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper frag_output_lib(*this); |
| { |
| link_info.pNext = &pipeline_rendering_info; |
| link_info.libraryCount = 1; |
| link_info.pLibraries = &pre_raster_lib.Handle(); |
| |
| frag_output_lib.InitFragmentOutputLibInfo(&link_info); |
| |
| frag_output_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| frag_output_lib.gp_ci_.pColorBlendState = nullptr; |
| frag_output_lib.AddDynamicState(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT); |
| frag_output_lib.AddDynamicState(VK_DYNAMIC_STATE_LOGIC_OP_EXT); |
| frag_output_lib.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT); |
| frag_output_lib.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT); |
| frag_output_lib.AddDynamicState(VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT); |
| frag_output_lib.AddDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS); |
| frag_output_lib.CreateGraphicsPipeline(); |
| } |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, PipelineLibraryNoRendering) { |
| TEST_DESCRIPTION("Create a pipeline library without a render pass or rendering info"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, IgnoredTessellationState) { |
| TEST_DESCRIPTION("Create a pipeline library with tessellation shader but no tessellation state"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState2); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState2PatchControlPoints); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.ia_ci_.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| VkPipelineShaderStageCreateInfo stages[2]; |
| |
| const auto tcs_spv = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, kTessellationControlMinimalGlsl); |
| VkShaderModuleCreateInfo tcs_ci = vku::InitStructHelper(); |
| tcs_ci.codeSize = tcs_spv.size() * sizeof(decltype(tcs_spv)::value_type); |
| tcs_ci.pCode = tcs_spv.data(); |
| stages[0] = vku::InitStructHelper(&tcs_ci); |
| stages[0].stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; |
| stages[0].module = VK_NULL_HANDLE; |
| stages[0].pName = "main"; |
| |
| const auto tes_spv = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, kTessellationEvalMinimalGlsl); |
| VkShaderModuleCreateInfo tes_ci = vku::InitStructHelper(); |
| tes_ci.codeSize = tes_spv.size() * sizeof(decltype(tes_spv)::value_type); |
| tes_ci.pCode = tes_spv.data(); |
| stages[1] = vku::InitStructHelper(&tes_ci); |
| stages[1].stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; |
| stages[1].module = VK_NULL_HANDLE; |
| stages[1].pName = "main"; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.AddDynamicState(VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT); |
| pre_raster_lib.shader_stages_ = {pre_raster_lib.vs_->GetStageCreateInfo(), stages[0], stages[1]}; |
| pre_raster_lib.gp_ci_.stageCount = pre_raster_lib.shader_stages_.size(); |
| pre_raster_lib.gp_ci_.pStages = pre_raster_lib.shader_stages_.data(); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, PushConstant) { |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| const char* const vs_source = R"glsl( |
| #version 450 |
| layout(push_constant, std430) uniform foo { float x; } constants; |
| void main(){ |
| gl_Position = vec4(constants.x); |
| } |
| )glsl"; |
| |
| VkPushConstantRange pc_range = {VK_SHADER_STAGE_VERTEX_BIT, 0, 8}; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_source); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.pipeline_layout_ci_.pushConstantRangeCount = 1; |
| pre_raster_lib.pipeline_layout_ci_.pPushConstantRanges = &pc_range; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.pipeline_layout_ci_.pushConstantRangeCount = 0; |
| frag_shader_lib.pipeline_layout_ci_.pPushConstantRanges = &pc_range; |
| frag_shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| VkPipeline libraries[2] = { |
| pre_raster_lib, |
| frag_shader_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| lib_ci.layout = pre_raster_lib.gp_ci_.layout; |
| lib_ci.renderPass = RenderPass(); |
| vkt::Pipeline lib(*m_device, lib_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, PushConstantOneLibrary) { |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| const char* const vs_source = R"glsl( |
| #version 450 |
| layout(push_constant, std430) uniform foo { float x; } constants; |
| void main(){ |
| gl_Position = vec4(constants.x); |
| } |
| )glsl"; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_source); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| VkPushConstantRange pc_range = {VK_SHADER_STAGE_ALL, 0, 4}; |
| pre_raster_lib.pipeline_layout_ci_.pushConstantRangeCount = 1; |
| pre_raster_lib.pipeline_layout_ci_.pPushConstantRanges = &pc_range; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.pipeline_layout_ci_.pushConstantRangeCount = 0; |
| frag_shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| VkPipeline libraries[2] = { |
| pre_raster_lib, |
| frag_shader_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| lib_ci.layout = pre_raster_lib.gp_ci_.layout; |
| lib_ci.renderPass = RenderPass(); |
| vkt::Pipeline lib(*m_device, lib_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, SetLayoutCount) { |
| TEST_DESCRIPTION("Have setLayoutCount not be the same between pipeline layouts"); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| OneOffDescriptorSet ds(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_GEOMETRY_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet ds2(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_GEOMETRY_BIT, nullptr}, |
| }); |
| |
| // with VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT, we can have different setLayoutCount |
| vkt::PipelineLayout pipeline_layout_vs(*m_device, {&ds.layout_, &ds2.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_fs(*m_device, {&ds.layout_}, {}, VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout_vs; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = 1; |
| link_info.pLibraries = &pre_raster_lib.Handle(); |
| |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &link_info); |
| |
| frag_shader_lib.gp_ci_.layout = pipeline_layout_fs; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, MultisampleStateFragShaderNull) { |
| TEST_DESCRIPTION( |
| "you're allowed to have the fragment shader subset have a multisample state of NULL and the fragment output subset have a " |
| "non-NULL multisample state as long as sample shading is false."); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.ms_ci_.sampleShadingEnable = VK_FALSE; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = 1; |
| link_info.pLibraries = &frag_out_lib.Handle(); |
| |
| vkt::PipelineLayout pipeline_layout(*m_device, {}); |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| CreatePipelineHelper frag_shader_lib(*this); |
| |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &link_info); |
| frag_shader_lib.gp_ci_.pMultisampleState = nullptr; |
| frag_shader_lib.gp_ci_.layout = pipeline_layout; |
| frag_shader_lib.gp_ci_.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, BadRenderPassVertexInput) { |
| TEST_DESCRIPTION("Create a vertex input graphics library with a bogus VkRenderPass"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitVertexInputLibInfo(); |
| // Vertex Input doesn't need the renderpass so it should be ignored |
| VkRenderPass bad_rp = CastToHandle<VkRenderPass, uintptr_t>(0xbaadbeef); |
| pipe.gp_ci_.renderPass = bad_rp; |
| pipe.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, LinkWithNoLayout) { |
| TEST_DESCRIPTION("You don't need a layout if fragment shader / pre-rasterization not required"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| |
| // Linking != Required pre-rasterization shader state |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = 1; |
| link_info.pLibraries = &pre_raster_lib.Handle(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(&link_info); |
| vertex_input_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| vertex_input_lib.gp_ci_.renderPass = RenderPass(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, LinkWithNoRenderPass) { |
| TEST_DESCRIPTION("You don't need a Renderpass if only using vertex input"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = 1; |
| link_info.pLibraries = &pre_raster_lib.Handle(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(&link_info); |
| vertex_input_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| } |
| |
| // Regression https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7551 |
| TEST_F(PositiveGraphicsLibrary, MultisampleStateSampleMaskArray) { |
| TEST_DESCRIPTION("pSampleMask can have different pointers of same value"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| VkSampleMask mask_a = 1; |
| VkSampleMask mask_b = 1; |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.ms_ci_.pSampleMask = &mask_a; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.ms_ci_.pSampleMask = &mask_b; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pre_raster_lib.gp_ci_.layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, VertexInputIgnoreVertexInputState) { |
| TEST_DESCRIPTION("ignore pVertexInputState with dynamic state so it is valid"); |
| AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::vertexInputDynamicState); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitVertexInputLibInfo(); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); |
| pipe.gp_ci_.pVertexInputState = nullptr; |
| pipe.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, VertexInputIgnoreAllState) { |
| TEST_DESCRIPTION("ignore pVertexInputState and pInputAssemblyState with dynamic state so it is valid"); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState2); |
| AddRequiredFeature(vkt::Feature::vertexInputDynamicState); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| VkPhysicalDeviceExtendedDynamicState3PropertiesEXT dynamic_state_3_props = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(dynamic_state_3_props); |
| if (!dynamic_state_3_props.dynamicPrimitiveTopologyUnrestricted) { |
| GTEST_SKIP() << "dynamicPrimitiveTopologyUnrestricted is VK_FALSE"; |
| } |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitVertexInputLibInfo(); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY); |
| pipe.gp_ci_.pVertexInputState = nullptr; |
| pipe.gp_ci_.pInputAssemblyState = nullptr; |
| pipe.CreateGraphicsPipeline(false); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, RasterizerDiscardEnable) { |
| TEST_DESCRIPTION("Ingore fragment output/shader using rasterizerDiscardEnable"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| // Can ignore fragment output/shader |
| pre_raster_lib.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| VkPipeline libraries[2] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pre_raster_lib.gp_ci_.layout; |
| exe_pipe_ci.renderPass = RenderPass(); |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, LegacyDitheringEnable) { |
| TEST_DESCRIPTION("Use enable legacy dithering flag with graphics libraries and dynamic rendering."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredExtensions(VK_EXT_LEGACY_DITHERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::legacyDithering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM; |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| |
| VkPipelineCreateFlags2CreateInfo create_flags2 = vku::InitStructHelper(); |
| create_flags2.flags = VK_PIPELINE_CREATE_2_ENABLE_LEGACY_DITHERING_BIT_EXT | VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | |
| VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; |
| create_flags2.pNext = &pipeline_rendering_info; |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(&create_flags2); |
| frag_out_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pre_raster_lib.gp_ci_.layout; |
| exe_pipe_ci.renderPass = VK_NULL_HANDLE; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| |
| vkt::Image color_image(*m_device, 32, 32, color_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| vkt::ImageView color_image_view = color_image.CreateView(); |
| |
| VkRenderingAttachmentInfoKHR color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| color_attachment.imageView = color_image_view; |
| |
| VkRenderingInfoKHR begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.colorAttachmentCount = 1; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| begin_rendering_info.flags = VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(begin_rendering_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, LinkWithNonIndependent) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9870"); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| OneOffDescriptorSet ds(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet ds2(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| }); |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| ds.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds.UpdateDescriptorSets(); |
| ds2.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds2.UpdateDescriptorSets(); |
| |
| vkt::PipelineLayout pipeline_layout_vs(*m_device, {&ds.layout_, &ds.layout_, nullptr}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_fs(*m_device, {&ds.layout_, nullptr, &ds2.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_link(*m_device, {&ds.layout_, &ds.layout_, &ds2.layout_}, {}); |
| // seperate layout to test compatibility |
| vkt::PipelineLayout pipeline_layout_ds(*m_device, {&ds.layout_, &ds.layout_, &ds2.layout_}, {}); |
| const std::array<VkDescriptorSet, 3> desc_sets = {ds.set_, ds.set_, ds2.set_}; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const char vs_src[] = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform foo { float x; } bar; |
| void main() { |
| gl_Position = vec4(bar.x); |
| } |
| )glsl"; |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_src); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; |
| pre_raster_lib.gp_ci_.layout = pipeline_layout_vs; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; |
| frag_shader_lib.gp_ci_.layout = pipeline_layout_fs; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pipeline_layout_link; |
| exe_pipe_ci.flags |= VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_ds, 0, |
| static_cast<uint32_t>(desc_sets.size()), desc_sets.data(), 0, nullptr); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, LinkWithIndependent) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9870"); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| OneOffDescriptorSet ds(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet ds2(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| }); |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| ds.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds.UpdateDescriptorSets(); |
| ds2.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE); |
| ds2.UpdateDescriptorSets(); |
| |
| vkt::PipelineLayout pipeline_layout_vs(*m_device, {&ds.layout_, &ds.layout_, nullptr}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_fs(*m_device, {&ds.layout_, nullptr, &ds2.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_link(*m_device, {&ds.layout_, &ds.layout_, &ds2.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| // seperate layout to test compatibility |
| vkt::PipelineLayout pipeline_layout_ds(*m_device, {&ds.layout_, &ds.layout_, &ds2.layout_}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| const std::array<VkDescriptorSet, 3> desc_sets = {ds.set_, ds.set_, ds2.set_}; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const char vs_src[] = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform foo { float x; } bar; |
| void main() { |
| gl_Position = vec4(bar.x); |
| } |
| )glsl"; |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_src); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout_vs; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout_fs; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pipeline_layout_link; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_ds, 0, |
| static_cast<uint32_t>(desc_sets.size()), desc_sets.data(), 0, nullptr); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DestroyImmutableSampler) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/issues/4348"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| vkt::Sampler sampler1(*m_device, SafeSaneSamplerCreateInfo()); |
| vkt::Sampler sampler2(*m_device, SafeSaneSamplerCreateInfo()); |
| OneOffDescriptorSet ds1(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler1.handle()}, |
| }); |
| OneOffDescriptorSet ds2(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler2.handle()}, |
| }); |
| vkt::PipelineLayout pipeline_layout1(*m_device, {&ds1.layout_}, {}, VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout2(*m_device, {&ds2.layout_}, {}, VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout1; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| // This is allowed with maintenance4 |
| pipeline_layout1.Destroy(); |
| sampler1.Destroy(); |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout2; |
| frag_shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.layout = pipeline_layout2; |
| vkt::Pipeline exe_pipe(*m_device, lib_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, Mesh) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/issues/4433"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto ms_spv = GLSLToSPV(VK_SHADER_STAGE_MESH_BIT_EXT, kMeshMinimalGlsl, SPV_ENV_VULKAN_1_3); |
| vkt::GraphicsPipelineLibraryStage ms_stage(ms_spv, VK_SHADER_STAGE_MESH_BIT_EXT); |
| pre_raster_lib.InitPreRasterLibInfo(&ms_stage.stage_ci); |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| // Vertex input lib not required for mesh |
| VkPipeline libraries[3] = { |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = pre_raster_lib.gp_ci_.layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, CustomResolve) { |
| AddRequiredExtensions(VK_EXT_CUSTOM_RESOLVE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::customResolve); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM; |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| |
| VkCustomResolveCreateInfoEXT custom_resolve_info = vku::InitStructHelper(&pipeline_rendering_info); |
| custom_resolve_info.customResolve = VK_TRUE; |
| custom_resolve_info.colorAttachmentCount = 1; |
| custom_resolve_info.pColorAttachmentFormats = &color_format; |
| |
| vkt::PipelineLayout pipeline_layout(*m_device); |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| VkStencilOpState stencil = {}; |
| stencil.failOp = VK_STENCIL_OP_KEEP; |
| stencil.passOp = VK_STENCIL_OP_KEEP; |
| stencil.depthFailOp = VK_STENCIL_OP_KEEP; |
| stencil.compareOp = VK_COMPARE_OP_NEVER; |
| |
| VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper(); |
| ds_ci.depthTestEnable = VK_FALSE; |
| ds_ci.depthWriteEnable = VK_TRUE; |
| ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER; |
| ds_ci.depthBoundsTestEnable = VK_FALSE; |
| ds_ci.stencilTestEnable = VK_FALSE; |
| ds_ci.front = stencil; |
| ds_ci.back = stencil; |
| |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &pipeline_rendering_info); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout; |
| frag_shader_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| frag_shader_lib.gp_ci_.pDepthStencilState = &ds_ci; |
| frag_shader_lib.CreateGraphicsPipeline(); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(&custom_resolve_info); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.layout = pipeline_layout; |
| lib_ci.renderPass = VK_NULL_HANDLE; |
| vkt::Pipeline exe_pipe(*m_device, lib_ci); |
| |
| VkImageCreateInfo image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, color_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| image_ci.samples = VK_SAMPLE_COUNT_4_BIT; |
| vkt::Image color_image(*m_device, image_ci); |
| vkt::ImageView color_image_view = color_image.CreateView(); |
| |
| image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| vkt::Image resolve_image(*m_device, image_ci); |
| vkt::ImageView resolve_image_view = resolve_image.CreateView(); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| color_attachment.imageView = color_image_view; |
| color_attachment.resolveMode = VK_RESOLVE_MODE_CUSTOM_BIT_EXT; |
| color_attachment.resolveImageView = resolve_image_view; |
| color_attachment.resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.flags = VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT; |
| begin_rendering_info.colorAttachmentCount = 1; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| VkBeginCustomResolveInfoEXT begin_resolve_info = vku::InitStructHelper(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(begin_rendering_info); |
| vk::CmdBeginCustomResolveEXT(m_command_buffer, &begin_resolve_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DescriptorHeapSetLayoutCount) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorHeap); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkPipelineCreateFlags2CreateInfoKHR create_flags = vku::InitStructHelper(); |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci, &create_flags); |
| pre_raster_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(&create_flags); |
| link_info.libraryCount = 1; |
| link_info.pLibraries = &pre_raster_lib.Handle(); |
| |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &link_info); |
| |
| frag_shader_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DescriptorHeapSetLayoutCountLinking) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorHeap); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkPipelineCreateFlags2CreateInfoKHR create_flags = vku::InitStructHelper(); |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci, &create_flags); |
| pre_raster_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &create_flags); |
| frag_shader_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| VkPipeline libraries[2] = { |
| pre_raster_lib, |
| frag_shader_lib, |
| }; |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(&create_flags); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| lib_ci.layout = pre_raster_lib.gp_ci_.layout; |
| lib_ci.renderPass = RenderPass(); |
| vkt::Pipeline lib(*m_device, lib_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DescriptorHeapPushConstantStages) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorHeap); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| VkPipelineCreateFlags2CreateInfoKHR create_flags = vku::InitStructHelper(); |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci, &create_flags); |
| pre_raster_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &create_flags); |
| frag_shader_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(&create_flags); |
| frag_shader_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[3] = { |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(&create_flags); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| lib_ci.layout = pre_raster_lib.gp_ci_.layout; |
| lib_ci.renderPass = RenderPass(); |
| vkt::Pipeline lib(*m_device, lib_ci); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, DescriptorHeapUnusedPipelineLayouts) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorHeap); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| InitRenderTarget(); |
| |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| OneOffDescriptorSet ds(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler.handle()}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds.layout_}, {}, VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR create_flags = vku::InitStructHelper(); |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR; |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(&create_flags); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci, &create_flags); |
| pre_raster_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &create_flags); |
| frag_shader_lib.gp_ci_.layout = VK_NULL_HANDLE; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(&create_flags); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| { |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(&create_flags); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.layout = VK_NULL_HANDLE; |
| vkt::Pipeline exe_pipe(*m_device, lib_ci); |
| } |
| |
| { |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR; |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(&create_flags); |
| link_info.libraryCount = 2u; |
| link_info.pLibraries = &libraries[0]; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.layout = VK_NULL_HANDLE; |
| vkt::Pipeline lib1(*m_device, lib_ci); |
| |
| link_info.pLibraries = &libraries[2]; |
| vkt::Pipeline lib2(*m_device, lib_ci); |
| |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| VkPipeline sub_libraries[2] = {lib1.handle(), lib2.handle()}; |
| link_info.pLibraries = sub_libraries; |
| vkt::Pipeline exe_pipe(*m_device, lib_ci); |
| } |
| |
| { |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR; |
| |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(&create_flags); |
| link_info.libraryCount = 1u; |
| link_info.pLibraries = &libraries[0]; |
| |
| VkGraphicsPipelineCreateInfo lib_ci = vku::InitStructHelper(&link_info); |
| lib_ci.layout = VK_NULL_HANDLE; |
| vkt::Pipeline vertex_input_lib_copy(*m_device, lib_ci); |
| |
| create_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| VkPipeline libraries2[4] = { |
| vertex_input_lib_copy, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| |
| link_info.libraryCount = size32(libraries2); |
| link_info.pLibraries = libraries2; |
| |
| lib_ci.layout = VK_NULL_HANDLE; |
| vkt::Pipeline exe_pipe(*m_device, lib_ci); |
| } |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, MultiViewDraw) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| VkPipelineLayout layout = VK_NULL_HANDLE; |
| |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| VkFormat color_format = VK_FORMAT_UNDEFINED; |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| pipeline_rendering_info.viewMask = 0x1; |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci, &pipeline_rendering_info); |
| pre_raster_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| pre_raster_lib.CreateGraphicsPipeline(); |
| } |
| |
| layout = pre_raster_lib.gp_ci_.layout; |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| VkStencilOpState stencil = {}; |
| stencil.failOp = VK_STENCIL_OP_KEEP; |
| stencil.passOp = VK_STENCIL_OP_KEEP; |
| stencil.depthFailOp = VK_STENCIL_OP_KEEP; |
| stencil.compareOp = VK_COMPARE_OP_NEVER; |
| |
| VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper(); |
| ds_ci.depthTestEnable = VK_FALSE; |
| ds_ci.depthWriteEnable = VK_TRUE; |
| ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER; |
| ds_ci.depthBoundsTestEnable = VK_FALSE; |
| ds_ci.stencilTestEnable = VK_TRUE; |
| ds_ci.front = stencil; |
| ds_ci.back = stencil; |
| |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci, &pipeline_rendering_info); |
| frag_shader_lib.gp_ci_.layout = layout; |
| frag_shader_lib.gp_ci_.pDepthStencilState = &ds_ci; |
| frag_shader_lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| pipeline_rendering_info.viewMask = 0x0; // ignored for fragment output |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.InitFragmentOutputLibInfo(&pipeline_rendering_info); |
| frag_out_lib.CreateGraphicsPipeline(false); |
| |
| VkPipeline libraries[4] = { |
| vertex_input_lib, |
| pre_raster_lib, |
| frag_shader_lib, |
| frag_out_lib, |
| }; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(); |
| link_info.libraryCount = size32(libraries); |
| link_info.pLibraries = libraries; |
| |
| VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info); |
| exe_pipe_ci.layout = layout; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.colorAttachmentCount = 1; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| begin_rendering_info.viewMask = 0x1; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(begin_rendering_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 1, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveGraphicsLibrary, MultiViewDraw2) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11600"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitBasicGraphicsLibrary()); |
| |
| VkFormat color_format = VK_FORMAT_UNDEFINED; |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| pipeline_rendering_info.viewMask = 0x1; |
| |
| VkGraphicsPipelineLibraryCreateInfoEXT lib_info = vku::InitStructHelper(&pipeline_rendering_info); |
| lib_info.flags = |
| VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT | VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT; |
| CreatePipelineHelper lib(*this, &lib_info); |
| lib.ds_ci_ = vku::InitStructHelper(); |
| lib.gp_ci_.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| lib.gp_ci_.renderPass = VK_NULL_HANDLE; |
| lib.CreateGraphicsPipeline(); |
| |
| lib_info.flags = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT | |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT; |
| VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper(&lib_info); |
| link_info.libraryCount = 1; |
| link_info.pLibraries = &lib.Handle(); |
| |
| CreatePipelineHelper exe_pipe(*this, &link_info); |
| exe_pipe.gp_ci_.renderPass = VK_NULL_HANDLE; |
| exe_pipe.gp_ci_.stageCount = 0; |
| exe_pipe.shader_stages_.clear(); |
| exe_pipe.CreateGraphicsPipeline(); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.colorAttachmentCount = 1; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| begin_rendering_info.viewMask = 0x1; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(begin_rendering_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdDraw(m_command_buffer, 1, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |