blob: 798e5a7873b5085c54bb58b3d90bf9e132cef254 [file]
/*
* Copyright (c) 2020-2026 The Khronos Group Inc.
* Copyright (c) 2020-2026 Valve Corporation
* Copyright (c) 2020-2026 LunarG, Inc.
* Copyright (c) 2020-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 <vulkan/vulkan_core.h>
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/buffer_helper.h"
#include "../framework/shader_helper.h"
class PositiveGpuAVVertexAttributeFetch : public GpuAVTest {};
TEST_F(PositiveGpuAVVertexAttributeFetch, IndirectDrawZeroStride) {
TEST_DESCRIPTION("Validation must take into account a VkVertexInputBindingDescription::stride of 0");
RETURN_IF_SKIP(InitGpuAvFramework());
RETURN_IF_SKIP(InitState());
InitRenderTarget();
const char* vsSource = R"glsl(
#version 450
layout(location=0) in vec3 pos;
void main() {
gl_Position = vec4(pos, 1.0);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
CreatePipelineHelper pipe(*this);
VkVertexInputBindingDescription input_binding = {0, 0, VK_VERTEX_INPUT_RATE_VERTEX};
VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0};
pipe.vi_ci_.pVertexBindingDescriptions = &input_binding;
pipe.vi_ci_.vertexBindingDescriptionCount = 1;
pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib;
pipe.vi_ci_.vertexAttributeDescriptionCount = 1;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
VkDrawIndexedIndirectCommand draw_params{};
draw_params.indexCount = 3;
draw_params.instanceCount = 1;
draw_params.firstIndex = 0;
draw_params.vertexOffset = 0;
draw_params.firstInstance = 0;
vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params});
VkCommandBufferBeginInfo begin_info = vku::InitStructHelper();
m_command_buffer.Begin(&begin_info);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42});
vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f});
VkDeviceSize vertex_buffer_offset = 0;
vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32);
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset);
vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand));
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(PositiveGpuAVVertexAttributeFetch, NoVertexInput) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11475");
RETURN_IF_SKIP(InitGpuAvFramework());
RETURN_IF_SKIP(InitState());
InitRenderTarget();
const char* vs_source = R"glsl(
#version 450
layout (location = 0) out vec3 outEyespacePosition;
layout (location = 1) out vec2 outTexcoords;
void main() {
outEyespacePosition = vec3(0);
outTexcoords = vec2(0);
}
)glsl";
VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT);
const char* fs_source = R"glsl(
#version 450
layout (location = 0) in vec3 inEyeSpacePosition;
layout (location = 0) out vec4 outColour;
void main() {
outColour = vec4(0);
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
VkVertexInputBindingDescription input_binding = {0, 0, VK_VERTEX_INPUT_RATE_VERTEX};
VkVertexInputAttributeDescription input_attrib = {1, 0, VK_FORMAT_A2B10G10R10_UNORM_PACK32, 0};
pipe.vi_ci_.pVertexBindingDescriptions = &input_binding;
pipe.vi_ci_.vertexBindingDescriptionCount = 1;
pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib;
pipe.vi_ci_.vertexAttributeDescriptionCount = 1;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
VkCommandBufferBeginInfo begin_info = vku::InitStructHelper();
m_command_buffer.Begin(&begin_info);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42});
vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f});
VkDeviceSize vertex_buffer_offset = 0;
vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32);
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset);
vk::CmdDrawIndexed(m_command_buffer, 3, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(PositiveGpuAVVertexAttributeFetch, NoVertexInputWithBuiltin) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11475");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::shaderDrawParameters);
RETURN_IF_SKIP(InitGpuAvFramework());
RETURN_IF_SKIP(InitState());
InitRenderTarget();
// Declares the variable for builtin [VertexIndex, InstanceIndex, BaseVertex] but never accesses them
const char* vs_source = R"(
OpCapability DrawParameters
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %entryPointParam_main_outEyespacePosition %entryPointParam_main_outTexcoords
OpDecorate %entryPointParam_main_outEyespacePosition Location 0
OpDecorate %entryPointParam_main_outTexcoords Location 1
OpDecorate %gl_Position BuiltIn Position
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
OpDecorate %15 BuiltIn BaseVertex
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%_ptr_Output_v3float = OpTypePointer Output %v3float
%v2float = OpTypeVector %float 2
%_ptr_Output_v2float = OpTypePointer Output %v2float
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%int = OpTypeInt 32 1
%_ptr_Input_int = OpTypePointer Input %int
%void = OpTypeVoid
%18 = OpTypeFunction %void
%float_0 = OpConstant %float 0
%20 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%23 = OpConstantComposite %v2float %float_0 %float_0
%entryPointParam_main_outEyespacePosition = OpVariable %_ptr_Output_v3float Output
%entryPointParam_main_outTexcoords = OpVariable %_ptr_Output_v2float Output
%gl_Position = OpVariable %_ptr_Output_v4float Output
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
%gl_InstanceIndex = OpVariable %_ptr_Input_int Input
%15 = OpVariable %_ptr_Input_int Input
%main = OpFunction %void None %18
%19 = OpLabel
OpStore %entryPointParam_main_outEyespacePosition %20
OpStore %entryPointParam_main_outTexcoords %23
OpReturn
OpFunctionEnd
)";
VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM);
const char* fs_source = R"glsl(
#version 450
layout (location = 0) in vec3 inEyeSpacePosition;
layout (location = 0) out vec4 outColour;
void main() {
outColour = vec4(0);
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2);
CreatePipelineHelper pipe(*this);
VkVertexInputBindingDescription input_binding = {0, 0, VK_VERTEX_INPUT_RATE_VERTEX};
VkVertexInputAttributeDescription input_attrib = {1, 0, VK_FORMAT_A2B10G10R10_UNORM_PACK32, 0};
pipe.vi_ci_.pVertexBindingDescriptions = &input_binding;
pipe.vi_ci_.vertexBindingDescriptionCount = 1;
pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib;
pipe.vi_ci_.vertexAttributeDescriptionCount = 1;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
VkCommandBufferBeginInfo begin_info = vku::InitStructHelper();
m_command_buffer.Begin(&begin_info);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42});
vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f});
VkDeviceSize vertex_buffer_offset = 0;
vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32);
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset);
vk::CmdDrawIndexed(m_command_buffer, 3, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}