| /* |
| * Copyright (c) 2015-2025 The Khronos Group Inc. |
| * Copyright (c) 2015-2025 Valve Corporation |
| * Copyright (c) 2015-2025 LunarG, Inc. |
| * Copyright (c) 2015-2025 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 "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| |
| class PositivePipelineBinary : public VkLayerTest {}; |
| |
| TEST_F(PositivePipelineBinary, CreateBinaryFromPipeline) { |
| TEST_DESCRIPTION("Create pipeline binaries from a pipeline"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| AddRequiredExtensions(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::pipelineBinaries); |
| RETURN_IF_SKIP(Init()); |
| |
| VkPipelineCreateFlags2CreateInfo flags2 = vku::InitStructHelper(); |
| flags2.flags = VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR; |
| |
| CreateComputePipelineHelper pipe(*this, &flags2); |
| pipe.CreateComputePipeline(true, true); |
| |
| VkPipelineBinaryCreateInfoKHR binary_create_info = vku::InitStructHelper(); |
| binary_create_info.pipeline = pipe; |
| |
| VkPipelineBinaryKHR pipeline_binary; |
| VkPipelineBinaryHandlesInfoKHR handles_info = vku::InitStructHelper(); |
| handles_info.pipelineBinaryCount = 1; |
| handles_info.pPipelineBinaries = &pipeline_binary; |
| |
| vk::CreatePipelineBinariesKHR(device(), &binary_create_info, nullptr, &handles_info); |
| vk::DestroyPipelineBinaryKHR(device(), pipeline_binary, nullptr); |
| } |
| |
| TEST_F(PositivePipelineBinary, CreateBinaryFromData) { |
| TEST_DESCRIPTION("Create pipeline binary from data blob"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| AddRequiredExtensions(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::pipelineBinaries); |
| RETURN_IF_SKIP(Init()); |
| |
| VkResult err; |
| |
| VkPipelineCreateFlags2CreateInfo flags2 = vku::InitStructHelper(); |
| flags2.flags = VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR; |
| |
| std::vector<uint8_t> binary_data; |
| size_t data_size; |
| VkPipelineBinaryKeyKHR binary_key = vku::InitStructHelper(); |
| |
| // create binary from pipeline |
| { |
| CreateComputePipelineHelper pipe(*this, &flags2); |
| pipe.CreateComputePipeline(true, true); |
| |
| VkPipelineBinaryCreateInfoKHR binary_create_info = vku::InitStructHelper(); |
| binary_create_info.pipeline = pipe; |
| |
| VkPipelineBinaryHandlesInfoKHR handles_info = vku::InitStructHelper(); |
| handles_info.pPipelineBinaries = nullptr; |
| |
| err = vk::CreatePipelineBinariesKHR(device(), &binary_create_info, nullptr, &handles_info); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| if (handles_info.pipelineBinaryCount != 1) { |
| for (uint32_t i = 0; i < handles_info.pipelineBinaryCount; i++) { |
| vk::DestroyPipelineBinaryKHR(device(), handles_info.pPipelineBinaries[i], nullptr); |
| } |
| |
| GTEST_SKIP() << "Test doesn't support multiple binaries"; |
| } |
| |
| VkPipelineBinaryKHR pipeline_binary1; |
| handles_info.pPipelineBinaries = &pipeline_binary1; |
| |
| err = vk::CreatePipelineBinariesKHR(device(), &binary_create_info, nullptr, &handles_info); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| pipe.Destroy(); |
| |
| VkPipelineBinaryDataInfoKHR data_info = vku::InitStructHelper(); |
| data_info.pipelineBinary = pipeline_binary1; |
| |
| err = vk::GetPipelineBinaryDataKHR(device(), &data_info, &binary_key, &data_size, nullptr); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| binary_data.resize(data_size); |
| |
| err = vk::GetPipelineBinaryDataKHR(device(), &data_info, &binary_key, &data_size, binary_data.data()); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| vk::DestroyPipelineBinaryKHR(device(), pipeline_binary1, nullptr); |
| } |
| |
| // create binary from data, then create pipeline from binary |
| { |
| VkPipelineBinaryKHR pipeline_binary2; |
| |
| VkPipelineBinaryDataKHR data; |
| data.dataSize = data_size; |
| data.pData = binary_data.data(); |
| |
| VkPipelineBinaryKeysAndDataKHR keys_data_info; |
| keys_data_info.binaryCount = 1; |
| keys_data_info.pPipelineBinaryKeys = &binary_key; |
| keys_data_info.pPipelineBinaryData = &data; |
| |
| VkPipelineBinaryCreateInfoKHR binary_create_info = vku::InitStructHelper(); |
| binary_create_info.pKeysAndDataInfo = &keys_data_info; |
| |
| VkPipelineBinaryHandlesInfoKHR handles_info = vku::InitStructHelper(); |
| handles_info.pipelineBinaryCount = 1; |
| handles_info.pPipelineBinaries = &pipeline_binary2; |
| |
| err = vk::CreatePipelineBinariesKHR(device(), &binary_create_info, nullptr, &handles_info); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| VkPipelineBinaryInfoKHR binary_info = vku::InitStructHelper(); |
| |
| binary_info.binaryCount = 1; |
| binary_info.pPipelineBinaries = &pipeline_binary2; |
| |
| flags2.pNext = &binary_info; |
| |
| CreateComputePipelineHelper pipe2(*this, &flags2); |
| pipe2.CreateComputePipeline(true, true); |
| |
| vk::DestroyPipelineBinaryKHR(device(), pipeline_binary2, nullptr); |
| } |
| } |
| |
| TEST_F(PositivePipelineBinary, GetPipelineKey) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8540"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::pipelineBinaries); |
| RETURN_IF_SKIP(Init()); |
| |
| VkShaderObj cs(*m_device, kMinimalShaderGlsl, VK_SHADER_STAGE_COMPUTE_BIT); |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings(0); |
| const vkt::DescriptorSetLayout pipeline_dsl(*m_device, bindings); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&pipeline_dsl}); |
| |
| VkComputePipelineCreateInfo compute_create_info = vku::InitStructHelper(); |
| compute_create_info.stage = cs.GetStageCreateInfo(); |
| compute_create_info.layout = pipeline_layout; |
| |
| VkPipelineBinaryInfoKHR pipeline_binary_info = vku::InitStructHelper(); |
| pipeline_binary_info.binaryCount = 0; |
| |
| compute_create_info.pNext = &pipeline_binary_info; |
| |
| VkPipelineCreateInfoKHR pipeline_create_info = vku::InitStructHelper(&compute_create_info); |
| |
| VkPipelineBinaryKeyKHR pipeline_key = vku::InitStructHelper(); |
| |
| ASSERT_EQ(VK_SUCCESS, vk::GetPipelineKeyKHR(device(), &pipeline_create_info, &pipeline_key)); |
| } |
| |
| TEST_F(PositivePipelineBinary, GetPipelineKeyGlobal) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8544"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::pipelineBinaries); |
| RETURN_IF_SKIP(Init()); |
| VkPipelineBinaryKeyKHR pipeline_key = vku::InitStructHelper(); |
| ASSERT_EQ(VK_SUCCESS, vk::GetPipelineKeyKHR(device(), nullptr, &pipeline_key)); |
| } |
| |
| TEST_F(PositivePipelineBinary, Draw) { |
| TEST_DESCRIPTION("Create pipeline binary from data blob"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| AddRequiredExtensions(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::pipelineBinaries); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Pipeline binaries not supported on MockICD"; |
| } |
| |
| VkResult err; |
| |
| VkPipelineCreateFlags2CreateInfo flags2 = vku::InitStructHelper(); |
| flags2.flags = VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR; |
| |
| uint32_t binary_count = 0u; |
| std::vector<uint8_t> binary_data[2]; |
| size_t data_size[2]; |
| VkPipelineBinaryKeyKHR binary_key[2]; |
| binary_key[0] = vku::InitStructHelper(); |
| binary_key[1] = vku::InitStructHelper(); |
| |
| // create binary from pipeline |
| { |
| CreatePipelineHelper pipe(*this, &flags2); |
| pipe.CreateGraphicsPipeline(true, true); |
| |
| VkPipelineBinaryCreateInfoKHR binary_create_info = vku::InitStructHelper(); |
| binary_create_info.pipeline = pipe; |
| |
| VkPipelineBinaryHandlesInfoKHR handles_info = vku::InitStructHelper(); |
| handles_info.pPipelineBinaries = nullptr; |
| |
| err = vk::CreatePipelineBinariesKHR(device(), &binary_create_info, nullptr, &handles_info); |
| ASSERT_EQ(VK_SUCCESS, err); |
| std::vector<VkPipelineBinaryKHR> pipeline_binaries(handles_info.pipelineBinaryCount); |
| handles_info.pPipelineBinaries = pipeline_binaries.data(); |
| err = vk::CreatePipelineBinariesKHR(device(), &binary_create_info, nullptr, &handles_info); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| pipe.Destroy(); |
| binary_count = handles_info.pipelineBinaryCount; |
| |
| for (uint32_t i = 0; i < binary_count; i++) { |
| VkPipelineBinaryDataInfoKHR data_info = vku::InitStructHelper(); |
| data_info.pipelineBinary = handles_info.pPipelineBinaries[i]; |
| |
| err = vk::GetPipelineBinaryDataKHR(device(), &data_info, &binary_key[i], &data_size[i], nullptr); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| binary_data[i].resize(data_size[i]); |
| |
| err = vk::GetPipelineBinaryDataKHR(device(), &data_info, &binary_key[i], &data_size[i], binary_data[i].data()); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| vk::DestroyPipelineBinaryKHR(device(), handles_info.pPipelineBinaries[i], nullptr); |
| } |
| } |
| |
| // create binary from data, then create pipeline from binary |
| { |
| VkPipelineBinaryKHR pipeline_binaries[2]; |
| |
| VkPipelineBinaryDataKHR data[2]; |
| for (uint32_t i = 0; i < binary_count; i++) { |
| data[i].dataSize = data_size[i]; |
| data[i].pData = binary_data[i].data(); |
| } |
| |
| VkPipelineBinaryKeysAndDataKHR keys_data_info; |
| keys_data_info.binaryCount = binary_count; |
| keys_data_info.pPipelineBinaryKeys = binary_key; |
| keys_data_info.pPipelineBinaryData = data; |
| |
| VkPipelineBinaryCreateInfoKHR binary_create_info = vku::InitStructHelper(); |
| binary_create_info.pKeysAndDataInfo = &keys_data_info; |
| |
| VkPipelineBinaryHandlesInfoKHR handles_info = vku::InitStructHelper(); |
| handles_info.pipelineBinaryCount = binary_count; |
| handles_info.pPipelineBinaries = pipeline_binaries; |
| |
| err = vk::CreatePipelineBinariesKHR(device(), &binary_create_info, nullptr, &handles_info); |
| ASSERT_EQ(VK_SUCCESS, err); |
| |
| VkPipelineBinaryInfoKHR binary_info = vku::InitStructHelper(); |
| |
| binary_info.binaryCount = binary_count; |
| binary_info.pPipelineBinaries = pipeline_binaries; |
| |
| flags2.pNext = &binary_info; |
| |
| CreatePipelineHelper pipe2(*this, &flags2); |
| pipe2.shader_stages_[0].module = VK_NULL_HANDLE; |
| pipe2.shader_stages_[1].module = VK_NULL_HANDLE; |
| pipe2.CreateGraphicsPipeline(true, true); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2); |
| vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| for (uint32_t i = 0; i < binary_count; i++) { |
| vk::DestroyPipelineBinaryKHR(device(), pipeline_binaries[i], nullptr); |
| } |
| } |
| } |