| /* |
| * Copyright (c) 2020-2025 The Khronos Group Inc. |
| * Copyright (c) 2020-2025 Valve Corporation |
| * Copyright (c) 2020-2025 LunarG, Inc. |
| * Copyright (c) 2020-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 <vulkan/vulkan_core.h> |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| #include "../framework/buffer_helper.h" |
| |
| class NegativeGpuAVVertexAttributeFetch : public GpuAVTest {}; |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, IndexBufferOOB) { |
| TEST_DESCRIPTION("Validate overruning the index buffer"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.CreateGraphicsPipeline(); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 1; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {1, 2, 3}); |
| |
| 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); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndexedIndirectCommand-robustBufferAccess2-08798", |
| "Index 4 is not within the bound index buffer."); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| 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(NegativeGpuAVVertexAttributeFetch, IndexBufferOOB2) { |
| TEST_DESCRIPTION("Validate overruning the index buffer - large indirect draw"); |
| AddRequiredExtensions(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiDrawIndirect); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.CreateGraphicsPipeline(); |
| |
| std::vector<VkDrawIndexedIndirectCommand> draw_params(64 * 64 + 1); |
| for (size_t i = 0; i < draw_params.size(); ++i) { |
| draw_params[i].indexCount = 3; |
| draw_params[i].instanceCount = 1; |
| draw_params[i].vertexOffset = 0; |
| draw_params[i].firstInstance = 0; |
| |
| // What really needs to be tested is ability to catch an error in the last |
| // indirect draw, if validation dispatch size is computed incorrectly |
| // it will be missed |
| if (i == (draw_params.size() - 1)) { |
| draw_params[i].firstIndex = 1; |
| } else { |
| draw_params[i].firstIndex = 0; |
| } |
| } |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, draw_params); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {1, 2, 3}); |
| |
| 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); |
| |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-VkDrawIndexedIndirectCommand-robustBufferAccess2-08798", |
| "Index 4 is not within the bound index buffer. Computed from VkDrawIndexedIndirectCommand\\[4096\\]"); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, size32(draw_params), sizeof(VkDrawIndexedIndirectCommand)); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, IndirectDrawBadVertexIndex32) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint32_t index"); |
| 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, 3 * sizeof(float), 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, 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); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| 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(NegativeGpuAVVertexAttributeFetch, IndirectDrawBadVertexIndex16) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint16_t index"); |
| 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, 3 * sizeof(float), 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); |
| |
| // Two OOB indices |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 42, 128}); |
| 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_UINT16); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 128"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| 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(NegativeGpuAVVertexAttributeFetch, IndirectDrawBadVertexIndex8) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint8_t index"); |
| AddRequiredExtensions(VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::indexTypeUint8); |
| 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, 3 * sizeof(float), 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<uint8_t>(*m_device, {0, 128, 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_UINT8_KHR); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 128"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| 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(NegativeGpuAVVertexAttributeFetch, DrawBadVertexIndex32) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint32_t index"); |
| 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, gl_VertexIndex); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), 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(); |
| |
| 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); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexed(m_command_buffer, 3, 1, 0, 0, 0); |
| |
| // vertexOffset = 3 |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 3"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 669"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 45"); |
| vk::CmdDrawIndexed(m_command_buffer, 3, 1, 0, 3, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, DrawBadVertexIndex32ShaderObject) { |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitDynamicRenderTarget(); |
| |
| const char *vs_source = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, gl_VertexIndex); |
| } |
| )glsl"; |
| |
| const vkt::Shader vs(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_source)); |
| const vkt::Shader fs(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| VkVertexInputBindingDescription2EXT input_binding = vku::InitStructHelper(); |
| input_binding.binding = 0; |
| input_binding.stride = 3 * sizeof(float); |
| input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
| input_binding.divisor = 1; |
| VkVertexInputAttributeDescription2EXT input_attrib = vku::InitStructHelper(); |
| input_attrib.location = 0; |
| input_attrib.binding = 0; |
| input_attrib.format = VK_FORMAT_R32G32B32_SFLOAT; |
| input_attrib.offset = 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| m_command_buffer.BindShaders(vs, fs); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE}); |
| |
| 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::CmdSetVertexInputEXT(m_command_buffer, 1, &input_binding, 1, &input_attrib); |
| |
| vk::CmdDrawIndexed(m_command_buffer, 3, 1, 0, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 42"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, DrawInSecondaryCmdBufferBadVertexIndex32) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint32_t index. Draw recorded in secondary command buffer."); |
| 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, 3 * sizeof(float), 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(); |
| |
| 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}); |
| |
| std::vector<vkt::CommandBuffer> secondary_cmd_buffers; |
| std::vector<VkCommandBuffer> secondary_cmd_buffers_handles; |
| |
| VkCommandBufferInheritanceInfo inheritance_info = vku::InitStructHelper(); |
| inheritance_info.renderPass = m_renderPass; |
| inheritance_info.subpass = 0; |
| inheritance_info.framebuffer = Framebuffer(); |
| |
| VkCommandBufferBeginInfo secondary_begin_info = vku::InitStructHelper(); |
| secondary_begin_info.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; |
| secondary_begin_info.pInheritanceInfo = &inheritance_info; |
| |
| constexpr uint32_t secondary_cmd_buffer_executes_count = 2; |
| for (uint32_t i = 0; i < secondary_cmd_buffer_executes_count; ++i) { |
| vkt::CommandBuffer &secondary_cmd_buffer = |
| secondary_cmd_buffers.emplace_back(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| secondary_cmd_buffers_handles.push_back(secondary_cmd_buffer); |
| |
| secondary_cmd_buffer.Begin(&secondary_begin_info); |
| vk::CmdBindPipeline(secondary_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(secondary_cmd_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(secondary_cmd_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexed(secondary_cmd_buffer, 3, 1, 0, 0, 0); |
| |
| // vertexOffset = 3 |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 3"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 669"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 45"); |
| vk::CmdDrawIndexed(secondary_cmd_buffer, 3, 1, 0, 3, 0); |
| |
| secondary_cmd_buffer.End(); |
| } |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); |
| |
| vk::CmdExecuteCommands(m_command_buffer, size32(secondary_cmd_buffers_handles), secondary_cmd_buffers_handles.data()); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, DrawBadVertexIndex16) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint16_t index"); |
| 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, 3 * sizeof(float), 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(); |
| |
| 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); |
| |
| // Two OOB indices |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 3, 666}); |
| 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_UINT16); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 3"); |
| 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(NegativeGpuAVVertexAttributeFetch, DrawBadVertexIndex16_2) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint16_t index"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| struct Vertex { |
| std::array<float, 3> position; |
| std::array<float, 2> uv; |
| std::array<float, 3> normal; |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| layout(location=1) in vec2 uv; |
| layout(location=2) in vec3 normal; |
| void main() { |
| gl_Position = vec4(pos + uv.xyx + normal, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| // "Array of structs" style vertices |
| VkVertexInputBindingDescription input_binding = {0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; |
| std::array<VkVertexInputAttributeDescription, 3> vertex_attributes = {}; |
| // Position |
| vertex_attributes[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| // UV |
| vertex_attributes[1] = {1, 0, VK_FORMAT_R32G32_SFLOAT, 3 * sizeof(float)}; |
| // Normal |
| vertex_attributes[2] = {2, 0, VK_FORMAT_R32G32B32_SFLOAT, (3 + 2) * sizeof(float)}; |
| |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = vertex_attributes.data(); |
| pipe.vi_ci_.vertexAttributeDescriptionCount = size32(vertex_attributes); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.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); |
| |
| std::vector<Vertex> vertices; |
| for (int i = 0; i < 3; ++i) { |
| const Vertex vertex = {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}; |
| vertices.emplace_back(vertex); |
| } |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<Vertex>(*m_device, vertices); |
| // Offset vertex buffer so that only first Vertex can correctly be fetched |
| VkDeviceSize vertex_buffer_offset = 2 * sizeof(Vertex); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 1, 0}); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 1"); |
| |
| 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(NegativeGpuAVVertexAttributeFetch, DrawBadVertexIndex8) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint8_t index"); |
| AddRequiredExtensions(VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::indexTypeUint8); |
| 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, 3 * sizeof(float), 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(); |
| |
| 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<uint8_t>(*m_device, {12, 66, 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_UINT8_KHR); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 12"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 66"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 42"); |
| 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(NegativeGpuAVVertexAttributeFetch, DrawBadVertexIndex16DebugLabel) { |
| TEST_DESCRIPTION( |
| "Validate illegal index buffer values - uint16_t index. Also make sure debug label regions are properly accounted for."); |
| AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| struct Vertex { |
| std::array<float, 3> position; |
| std::array<float, 2> uv; |
| std::array<float, 3> normal; |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| layout(location=1) in vec2 uv; |
| layout(location=2) in vec3 normal; |
| void main() { |
| gl_Position = vec4(pos + uv.xyx + normal, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| // "Array of structs" style vertices |
| VkVertexInputBindingDescription input_binding = {0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; |
| std::array<VkVertexInputAttributeDescription, 3> vertex_attributes = {}; |
| // Position |
| vertex_attributes[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| // UV |
| vertex_attributes[1] = {1, 0, VK_FORMAT_R32G32_SFLOAT, 3 * sizeof(float)}; |
| // Normal |
| vertex_attributes[2] = {2, 0, VK_FORMAT_R32G32B32_SFLOAT, (3 + 2) * sizeof(float)}; |
| |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = vertex_attributes.data(); |
| pipe.vi_ci_.vertexAttributeDescriptionCount = size32(vertex_attributes); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.CreateGraphicsPipeline(); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| VkDebugUtilsLabelEXT label = vku::InitStructHelper(); |
| label.pLabelName = "my_pipeline"; |
| vk::CmdBeginDebugUtilsLabelEXT(m_command_buffer, &label); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| label.pLabelName = "my_draw"; |
| vk::CmdBeginDebugUtilsLabelEXT(m_command_buffer, &label); |
| |
| std::vector<Vertex> vertices; |
| for (int i = 0; i < 3; ++i) { |
| const Vertex vertex = {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}; |
| vertices.emplace_back(vertex); |
| } |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<Vertex>(*m_device, vertices); |
| // Offset vertex buffer so that only first Vertex can correctly be fetched |
| VkDeviceSize vertex_buffer_offset = 2 * sizeof(Vertex); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 1, 0}); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "my_pipeline::my_draw([\\s\\S]*)Vertex index 1"); |
| |
| vk::CmdDrawIndexed(m_command_buffer, 3, 1, 0, 0, 0); |
| |
| vk::CmdEndDebugUtilsLabelEXT(m_command_buffer); |
| vk::CmdEndDebugUtilsLabelEXT(m_command_buffer); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, IndirectDrawBadVertexIndex32DebugLabel) { |
| TEST_DESCRIPTION( |
| "Validate illegal index buffer values - uint32_t index. Also make sure debug label regions are properly accounted for."); |
| AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| 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, 3 * sizeof(float), 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); |
| |
| VkDebugUtilsLabelEXT label = vku::InitStructHelper(); |
| label.pLabelName = "my_pipeline"; |
| vk::CmdBeginDebugUtilsLabelEXT(m_command_buffer, &label); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| label.pLabelName = "my_draw"; |
| vk::CmdBeginDebugUtilsLabelEXT(m_command_buffer, &label); |
| 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); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", |
| "my_pipeline::my_draw([\\s\\S]*)Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", |
| "my_pipeline::my_draw([\\s\\S]*)Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| vk::CmdEndDebugUtilsLabelEXT(m_command_buffer); |
| vk::CmdEndDebugUtilsLabelEXT(m_command_buffer); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, InstanceIndex) { |
| TEST_DESCRIPTION("Validate illegal instance index values"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| struct Vertex { |
| std::array<float, 3> position; |
| std::array<float, 2> uv; |
| std::array<float, 3> normal; |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| layout(location=1) in vec2 uv; |
| layout(location=2) in vec3 normal; |
| layout(location=3) in float instance_float; |
| void main() { |
| gl_Position = vec4(pos + uv.xyx + normal + instance_float, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| // "Array of structs" style vertices |
| std::array<VkVertexInputBindingDescription, 2> input_bindings = { |
| {{0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX}, {1, sizeof(float), VK_VERTEX_INPUT_RATE_INSTANCE}}}; |
| std::array<VkVertexInputAttributeDescription, 4> vertex_attributes = {}; |
| // Position |
| vertex_attributes[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| // UV |
| vertex_attributes[1] = {1, 0, VK_FORMAT_R32G32_SFLOAT, 3 * sizeof(float)}; |
| // Normal |
| vertex_attributes[2] = {2, 0, VK_FORMAT_R32G32B32_SFLOAT, (3 + 2) * sizeof(float)}; |
| // Instance float |
| vertex_attributes[3] = {3, 1, VK_FORMAT_R32_SFLOAT, 0}; |
| |
| pipe.vi_ci_.vertexBindingDescriptionCount = size32(input_bindings); |
| pipe.vi_ci_.pVertexBindingDescriptions = input_bindings.data(); |
| pipe.vi_ci_.vertexAttributeDescriptionCount = size32(vertex_attributes); |
| pipe.vi_ci_.pVertexAttributeDescriptions = vertex_attributes.data(); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.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); |
| |
| std::vector<Vertex> vertices; |
| for (int i = 0; i < 3; ++i) { |
| const Vertex vertex = {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}; |
| vertices.emplace_back(vertex); |
| } |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<Vertex>(*m_device, vertices); |
| // Offset vertex buffer so that only first Vertex can correctly be fetched |
| const VkDeviceSize vertex_buffer_offset = 2 * sizeof(Vertex); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| std::vector<float> instance_data = {42.0f}; |
| vkt::Buffer instance_buffer = vkt::VertexBuffer<float>(*m_device, instance_data); |
| const VkDeviceSize instance_data_offset = 0; |
| vk::CmdBindVertexBuffers(m_command_buffer, 1, 1, &instance_buffer.handle(), &instance_data_offset); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 0, 0}); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Instance index 1"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Instance index 2"); |
| |
| vk::CmdDrawIndexed(m_command_buffer, 3, 3, 0, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, InstanceIndexVertexAttributeDivisor) { |
| TEST_DESCRIPTION("Validate illegal instance index values, when using vertex attribute divisor"); |
| AddRequiredExtensions(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::vertexAttributeInstanceRateDivisor); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| struct Vertex { |
| std::array<float, 3> position; |
| std::array<float, 2> uv; |
| std::array<float, 3> normal; |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| layout(location=1) in vec2 uv; |
| layout(location=2) in vec3 normal; |
| layout(location=3) in float instance_float; |
| void main() { |
| gl_Position = vec4(pos + uv.xyx + normal + instance_float, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| // "Array of structs" style vertices |
| std::array<VkVertexInputBindingDescription, 2> input_bindings = { |
| {{0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX}, {1, sizeof(float), VK_VERTEX_INPUT_RATE_INSTANCE}}}; |
| std::array<VkVertexInputAttributeDescription, 4> vertex_attributes = {}; |
| // Position |
| vertex_attributes[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| // UV |
| vertex_attributes[1] = {1, 0, VK_FORMAT_R32G32_SFLOAT, 3 * sizeof(float)}; |
| // Normal |
| vertex_attributes[2] = {2, 0, VK_FORMAT_R32G32B32_SFLOAT, (3 + 2) * sizeof(float)}; |
| // Instance float |
| vertex_attributes[3] = {3, 1, VK_FORMAT_R32_SFLOAT, 0}; |
| |
| VkVertexInputBindingDivisorDescription vertex_binding_divisor; |
| vertex_binding_divisor.binding = 1u; |
| vertex_binding_divisor.divisor = 2u; |
| |
| VkPipelineVertexInputDivisorStateCreateInfo vertex_input_divisor_state = vku::InitStructHelper(); |
| vertex_input_divisor_state.vertexBindingDivisorCount = 1u; |
| vertex_input_divisor_state.pVertexBindingDivisors = &vertex_binding_divisor; |
| |
| pipe.vi_ci_.pNext = &vertex_input_divisor_state; |
| pipe.vi_ci_.vertexBindingDescriptionCount = size32(input_bindings); |
| pipe.vi_ci_.pVertexBindingDescriptions = input_bindings.data(); |
| pipe.vi_ci_.vertexAttributeDescriptionCount = size32(vertex_attributes); |
| pipe.vi_ci_.pVertexAttributeDescriptions = vertex_attributes.data(); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.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); |
| |
| std::vector<Vertex> vertices; |
| for (int i = 0; i < 3; ++i) { |
| const Vertex vertex = {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}; |
| vertices.emplace_back(vertex); |
| } |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<Vertex>(*m_device, vertices); |
| // Offset vertex buffer so that only first Vertex can correctly be fetched |
| const VkDeviceSize vertex_buffer_offset = 2 * sizeof(Vertex); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| std::vector<float> instance_data = {42.0f}; |
| vkt::Buffer instance_buffer = vkt::VertexBuffer<float>(*m_device, instance_data); |
| const VkDeviceSize instance_data_offset = 0; |
| vk::CmdBindVertexBuffers(m_command_buffer, 1, 1, &instance_buffer.handle(), &instance_data_offset); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 0, 0}); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); |
| |
| // gl_InstanceIndex of 1 divided by 2 => effective instance index of 0, so no OOB |
| // m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Instance index 1"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Instance index 2"); |
| |
| vk::CmdDrawIndexed(m_command_buffer, 3, 3, 0, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, InstanceIndexVertexAttributeDivisorDynamic) { |
| TEST_DESCRIPTION("Validate illegal instance index values, when using vertex attribute divisor. Vertex input state is dynamic"); |
| AddRequiredExtensions(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::vertexAttributeInstanceRateDivisor); |
| AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::vertexInputDynamicState); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| struct Vertex { |
| std::array<float, 3> position; |
| std::array<float, 2> uv; |
| std::array<float, 3> normal; |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| layout(location=1) in vec2 uv; |
| layout(location=2) in vec3 normal; |
| layout(location=3) in float instance_float; |
| void main() { |
| gl_Position = vec4(pos + uv.xyx + normal + instance_float, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| // "Array of structs" style vertices |
| std::array<VkVertexInputBindingDescription2EXT, 2> input_bindings = {}; |
| input_bindings[0] = vku::InitStructHelper(); |
| input_bindings[0].binding = 0; |
| input_bindings[0].stride = sizeof(Vertex); |
| input_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
| input_bindings[0].divisor = 1; |
| |
| input_bindings[1] = vku::InitStructHelper(); |
| input_bindings[1].binding = 1; |
| input_bindings[1].stride = sizeof(float); |
| input_bindings[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; |
| input_bindings[1].divisor = 2; |
| |
| std::array<VkVertexInputAttributeDescription2EXT, 4> vertex_attributes = {}; |
| // Position |
| vertex_attributes[0] = vku::InitStructHelper(); |
| vertex_attributes[0].location = 0; |
| vertex_attributes[0].binding = 0; |
| vertex_attributes[0].format = VK_FORMAT_R32G32B32_SFLOAT; |
| vertex_attributes[0].offset = 0; |
| // UV |
| vertex_attributes[1] = vku::InitStructHelper(); |
| vertex_attributes[1].location = 1; |
| vertex_attributes[1].binding = 0; |
| vertex_attributes[1].format = VK_FORMAT_R32G32_SFLOAT; |
| vertex_attributes[1].offset = 3 * sizeof(float); |
| |
| // Normal |
| vertex_attributes[2] = vku::InitStructHelper(); |
| vertex_attributes[2].location = 2; |
| vertex_attributes[2].binding = 0; |
| vertex_attributes[2].format = VK_FORMAT_R32G32B32_SFLOAT; |
| vertex_attributes[2].offset = (3 + 2) * sizeof(float); |
| |
| // Instance float |
| vertex_attributes[3] = vku::InitStructHelper(); |
| vertex_attributes[3].location = 3; |
| vertex_attributes[3].binding = 1; |
| vertex_attributes[3].format = VK_FORMAT_R32_SFLOAT; |
| vertex_attributes[3].offset = 0; |
| |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.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); |
| |
| vk::CmdSetVertexInputEXT(m_command_buffer, size32(input_bindings), input_bindings.data(), size32(vertex_attributes), |
| vertex_attributes.data()); |
| |
| std::vector<Vertex> vertices; |
| for (int i = 0; i < 3; ++i) { |
| const Vertex vertex = {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}; |
| vertices.emplace_back(vertex); |
| } |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<Vertex>(*m_device, vertices); |
| // Offset vertex buffer so that only first Vertex can correctly be fetched |
| const VkDeviceSize vertex_buffer_offset = 2 * sizeof(Vertex); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| std::vector<float> instance_data = {42.0f}; |
| vkt::Buffer instance_buffer = vkt::VertexBuffer<float>(*m_device, instance_data); |
| const VkDeviceSize instance_data_offset = 0; |
| vk::CmdBindVertexBuffers(m_command_buffer, 1, 1, &instance_buffer.handle(), &instance_data_offset); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 0, 0}); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); |
| |
| // gl_InstanceIndex of 1 divided by 2 => effective instance index of 0, so no OOB |
| // m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Instance index 1"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Instance index 2"); |
| |
| vk::CmdDrawIndexed(m_command_buffer, 3, 3, 0, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVVertexAttributeFetch, CmdSetVertexInputEXT) { |
| TEST_DESCRIPTION("Simple graphics pipeline, bind vertex buffers with vkCmdSetVertexInputEXT - vertex index >1 are OOB"); |
| AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::vertexInputDynamicState); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| struct Vertex { |
| std::array<float, 3> position; |
| std::array<float, 2> uv; |
| std::array<float, 3> normal; |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| layout(location=1) in vec2 uv; |
| layout(location=2) in vec3 normal; |
| void main() { |
| gl_Position = vec4(pos + uv.xyx + normal, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); |
| pipe.gp_ci_.pVertexInputState = nullptr; |
| // "Array of structs" style vertices |
| VkVertexInputBindingDescription2EXT input_binding = vku::InitStructHelper(); |
| input_binding.binding = 0; |
| input_binding.stride = sizeof(Vertex); |
| input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
| input_binding.divisor = 1; |
| |
| std::array<VkVertexInputAttributeDescription2EXT, 3> vertex_attributes = {}; |
| // Position |
| vertex_attributes[0] = vku::InitStructHelper(); |
| vertex_attributes[0].location = 0; |
| vertex_attributes[0].binding = 0; |
| vertex_attributes[0].format = VK_FORMAT_R32G32B32_SFLOAT; |
| vertex_attributes[0].offset = 0; |
| // UV |
| vertex_attributes[1] = vku::InitStructHelper(); |
| vertex_attributes[1].location = 1; |
| vertex_attributes[1].binding = 0; |
| vertex_attributes[1].format = VK_FORMAT_R32G32_SFLOAT; |
| vertex_attributes[1].offset = 3 * sizeof(float); |
| // Normal |
| vertex_attributes[2] = vku::InitStructHelper(); |
| vertex_attributes[2].location = 2; |
| vertex_attributes[2].binding = 0; |
| vertex_attributes[2].format = VK_FORMAT_R32G32B32_SFLOAT; |
| vertex_attributes[2].offset = (3 + 2) * sizeof(float); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.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); |
| |
| vk::CmdSetVertexInputEXT(m_command_buffer, 1, &input_binding, size32(vertex_attributes), vertex_attributes.data()); |
| |
| std::vector<Vertex> vertices; |
| for (int i = 0; i < 3; ++i) { |
| const Vertex vertex = {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}; |
| vertices.emplace_back(vertex); |
| } |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<Vertex>(*m_device, vertices); |
| // Offset vertex buffer so that only first vertex can correctly be fetched |
| VkDeviceSize vertex_buffer_offset = 2 * sizeof(Vertex); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 1, 0}); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 1"); |
| 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(NegativeGpuAVVertexAttributeFetch, CmdBindVertexBuffers2EXT) { |
| TEST_DESCRIPTION( |
| "Simple graphics pipeline, use vkCmdSetVertexInputEXT and vkCmdBindVertexBuffers2EXT - vertex index >1 are OOB"); |
| AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::vertexInputDynamicState); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| struct Vertex { |
| std::array<float, 3> position; |
| std::array<float, 2> uv; |
| std::array<float, 3> normal; |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| |
| layout(location=0) in vec3 pos; |
| layout(location=1) in vec2 uv; |
| layout(location=2) in vec3 normal; |
| |
| void main() { |
| gl_Position = vec4(pos + uv.xyx + normal, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE); |
| pipe.gp_ci_.pVertexInputState = nullptr; |
| // "Array of structs" style vertices |
| VkVertexInputBindingDescription2EXT input_binding = vku::InitStructHelper(); |
| input_binding.binding = 0; |
| input_binding.stride = sizeof(Vertex); |
| input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
| input_binding.divisor = 1; |
| |
| std::array<VkVertexInputAttributeDescription2EXT, 3> vertex_attributes = {}; |
| // Position |
| vertex_attributes[0] = vku::InitStructHelper(); |
| vertex_attributes[0].location = 0; |
| vertex_attributes[0].binding = 0; |
| vertex_attributes[0].format = VK_FORMAT_R32G32B32_SFLOAT; |
| vertex_attributes[0].offset = 0; |
| // UV |
| vertex_attributes[1] = vku::InitStructHelper(); |
| vertex_attributes[1].location = 1; |
| vertex_attributes[1].binding = 0; |
| vertex_attributes[1].format = VK_FORMAT_R32G32_SFLOAT; |
| vertex_attributes[1].offset = 3 * sizeof(float); |
| // Normal |
| vertex_attributes[2] = vku::InitStructHelper(); |
| vertex_attributes[2].location = 2; |
| vertex_attributes[2].binding = 0; |
| vertex_attributes[2].format = VK_FORMAT_R32G32B32_SFLOAT; |
| vertex_attributes[2].offset = (3 + 2) * sizeof(float); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.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); |
| |
| vk::CmdSetVertexInputEXT(m_command_buffer, 1, &input_binding, size32(vertex_attributes), vertex_attributes.data()); |
| |
| std::vector<Vertex> vertices; |
| for (int i = 0; i < 3; ++i) { |
| const Vertex vertex = {{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}}; |
| vertices.emplace_back(vertex); |
| } |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<Vertex>(*m_device, vertices); |
| // Offset vertex buffer so that only first and second vertices can correctly be fetched |
| const VkDeviceSize vertex_buffer_offset = 1 * sizeof(Vertex); |
| const VkDeviceSize vertex_buffer_size = 1 * sizeof(Vertex); |
| const VkDeviceSize vertex_stride = sizeof(Vertex); |
| vk::CmdBindVertexBuffers2EXT(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset, &vertex_buffer_size, |
| &vertex_stride); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint16_t>(*m_device, {0, 1, 0}); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", "Vertex index 1"); |
| 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(NegativeGpuAVVertexAttributeFetch, DrawBadVertexIndex32MultiDraw) { |
| TEST_DESCRIPTION("Validate illegal index buffer values - uint32_t index, multi draw"); |
| AddRequiredExtensions(VK_EXT_MULTI_DRAW_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiDraw); |
| 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, gl_VertexIndex); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), 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(); |
| |
| 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); |
| |
| VkMultiDrawIndexedInfoEXT multi_draw_info[2] = {}; |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawMultiIndexedEXT-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawMultiIndexedEXT-None-02721", "Vertex index 42"); |
| multi_draw_info[0].firstIndex = 0; |
| multi_draw_info[0].indexCount = 3; |
| multi_draw_info[0].vertexOffset = 0; |
| // From vertexOffset = 3 |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawMultiIndexedEXT-None-02721", "Vertex index 3"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawMultiIndexedEXT-None-02721", "Vertex index 669"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawMultiIndexedEXT-None-02721", "Vertex index 45"); |
| multi_draw_info[1].firstIndex = 0; |
| multi_draw_info[1].indexCount = 3; |
| multi_draw_info[1].vertexOffset = 3; |
| |
| vk::CmdDrawMultiIndexedEXT(m_command_buffer, 2, multi_draw_info, 1, 0, sizeof(VkMultiDrawIndexedInfoEXT), nullptr); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |