diff --git a/layers/VkLayer_khronos_validation.json.in b/layers/VkLayer_khronos_validation.json.in index 45cb263ad1f..c1f61a418f9 100644 --- a/layers/VkLayer_khronos_validation.json.in +++ b/layers/VkLayer_khronos_validation.json.in @@ -1142,6 +1142,26 @@ } ] } + }, + { + "key": "gpuav_index_buffers", + "label": "Index buffers", + "type": "BOOL", + "default": true, + "description": "Validate that indexed draws do not fetch indices outside of the bounds of the index buffer. Also validates that those indices are not out of the bounds of the fetched vertex buffers.", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_buffers_validation", + "value": true + } + ] + } } ] }, diff --git a/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp b/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp index f6c576bd8e3..8c25209f0c9 100644 --- a/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp +++ b/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp @@ -22,6 +22,7 @@ #include "gpu/shaders/gpu_shaders_constants.h" #include "state_tracker/descriptor_sets.h" +#include "state_tracker/render_pass_state.h" #include "state_tracker/shader_object_state.h" namespace gpuav { @@ -38,8 +39,7 @@ void BindErrorLoggingDescriptorSet(Validator &gpuav, CommandBuffer &cb_state, Vk dynamic_offsets.data()); } -void RestorablePipelineState::Create(vvl::CommandBuffer &cb_state, VkPipelineBindPoint bind_point) { - cmd_buffer_ = cb_state.VkHandle(); +void RestorablePipelineState::Create(CommandBuffer &cb_state, VkPipelineBindPoint bind_point) { pipeline_bind_point_ = bind_point; const auto lv_bind_point = ConvertToLvlBindPoint(bind_point); @@ -78,11 +78,29 @@ void RestorablePipelineState::Create(vvl::CommandBuffer &cb_state, VkPipelineBin if (last_bound.push_descriptor_set) { push_descriptor_set_writes_ = last_bound.push_descriptor_set->GetWrites(); } + + // Do not handle cb_state.activeRenderPass->use_dynamic_rendering_inherited for now + if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS && cb_state.activeRenderPass->use_dynamic_rendering) { + rendering_info_ = &cb_state.activeRenderPass->dynamic_rendering_begin_rendering_info; + DispatchCmdEndRendering(cb_state.VkHandle()); + + VkRenderingInfo rendering_info = vku::InitStructHelper(); + rendering_info.renderArea = {{0, 0}, {1, 1}}; + rendering_info.layerCount = 1; + rendering_info.viewMask = 0; + rendering_info.colorAttachmentCount = 0; + DispatchCmdBeginRendering(cb_state.VkHandle(), &rendering_info); + } } void RestorablePipelineState::Restore() const { + if (rendering_info_) { + DispatchCmdEndRendering(cb_state_.VkHandle()); + DispatchCmdBeginRendering(cb_state_.VkHandle(), rendering_info_->ptr()); + } + if (pipeline_ != VK_NULL_HANDLE) { - DispatchCmdBindPipeline(cmd_buffer_, pipeline_bind_point_, pipeline_); + DispatchCmdBindPipeline(cb_state_.VkHandle(), pipeline_bind_point_, pipeline_); } if (!shader_objects_.empty()) { std::vector stages; @@ -91,29 +109,34 @@ void RestorablePipelineState::Restore() const { stages.emplace_back(shader_obj->create_info.stage); shaders.emplace_back(shader_obj->VkHandle()); } - DispatchCmdBindShadersEXT(cmd_buffer_, static_cast(shader_objects_.size()), stages.data(), shaders.data()); + DispatchCmdBindShadersEXT(cb_state_.VkHandle(), static_cast(shader_objects_.size()), stages.data(), + shaders.data()); } for (std::size_t i = 0; i < descriptor_sets_.size(); i++) { VkDescriptorSet descriptor_set = descriptor_sets_[i].first; if (descriptor_set != VK_NULL_HANDLE) { - DispatchCmdBindDescriptorSets(cmd_buffer_, pipeline_bind_point_, desc_set_pipeline_layout_, descriptor_sets_[i].second, - 1, &descriptor_set, static_cast(dynamic_offsets_[i].size()), - dynamic_offsets_[i].data()); + DispatchCmdBindDescriptorSets(cb_state_.VkHandle(), pipeline_bind_point_, desc_set_pipeline_layout_, + descriptor_sets_[i].second, 1, &descriptor_set, + static_cast(dynamic_offsets_[i].size()), dynamic_offsets_[i].data()); } } if (!push_descriptor_set_writes_.empty()) { - DispatchCmdPushDescriptorSetKHR(cmd_buffer_, pipeline_bind_point_, desc_set_pipeline_layout_, push_descriptor_set_index_, - static_cast(push_descriptor_set_writes_.size()), + DispatchCmdPushDescriptorSetKHR(cb_state_.VkHandle(), pipeline_bind_point_, desc_set_pipeline_layout_, + push_descriptor_set_index_, static_cast(push_descriptor_set_writes_.size()), reinterpret_cast(push_descriptor_set_writes_.data())); } for (const auto &push_constant_range : push_constants_data_) { - DispatchCmdPushConstants(cmd_buffer_, push_constant_range.layout, push_constant_range.stage_flags, + DispatchCmdPushConstants(cb_state_.VkHandle(), push_constant_range.layout, push_constant_range.stage_flags, push_constant_range.offset, static_cast(push_constant_range.values.size()), push_constant_range.values.data()); } + + if (pipeline_bind_point_ == VK_PIPELINE_BIND_POINT_GRAPHICS) { + cb_state_.RestoreDynamicStates(gpuav_); + } } } // namespace gpuav diff --git a/layers/gpu/cmd_validation/gpuav_cmd_validation_common.h b/layers/gpu/cmd_validation/gpuav_cmd_validation_common.h index 21e3a7c5c05..a0df677707f 100644 --- a/layers/gpu/cmd_validation/gpuav_cmd_validation_common.h +++ b/layers/gpu/cmd_validation/gpuav_cmd_validation_common.h @@ -27,14 +27,19 @@ class Validator; class RestorablePipelineState { public: - RestorablePipelineState(vvl::CommandBuffer& cb_state, VkPipelineBindPoint bind_point) { Create(cb_state, bind_point); } + RestorablePipelineState(const Validator& gpuav, CommandBuffer& cb_state, VkPipelineBindPoint bind_point) + : gpuav_(gpuav), cb_state_(cb_state) { + Create(cb_state, bind_point); + } ~RestorablePipelineState() { Restore(); } private: - void Create(vvl::CommandBuffer& cb_state, VkPipelineBindPoint bind_point); + void Create(CommandBuffer& cb_state, VkPipelineBindPoint bind_point); void Restore() const; - VkCommandBuffer cmd_buffer_; + const Validator& gpuav_; + CommandBuffer& cb_state_; + const vku::safe_VkRenderingInfo* rendering_info_ = nullptr; VkPipelineBindPoint pipeline_bind_point_ = VK_PIPELINE_BIND_POINT_MAX_ENUM; VkPipeline pipeline_ = VK_NULL_HANDLE; VkPipelineLayout desc_set_pipeline_layout_ = VK_NULL_HANDLE; diff --git a/layers/gpu/cmd_validation/gpuav_copy_buffer_to_image.cpp b/layers/gpu/cmd_validation/gpuav_copy_buffer_to_image.cpp index 6e1954a2e70..f77f85d1b1f 100644 --- a/layers/gpu/cmd_validation/gpuav_copy_buffer_to_image.cpp +++ b/layers/gpu/cmd_validation/gpuav_copy_buffer_to_image.cpp @@ -307,7 +307,7 @@ void InsertCopyBufferToImageValidation(Validator &gpuav, const Location &loc, Co DispatchUpdateDescriptorSets(gpuav.device, static_cast(desc_writes.size()), desc_writes.data(), 0, nullptr); } // Save current graphics pipeline state - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_COMPUTE); + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE); // Insert diagnostic dispatch DispatchCmdBindPipeline(cb_state.VkHandle(), VK_PIPELINE_BIND_POINT_COMPUTE, shared_copy_validation_resources.pipeline); diff --git a/layers/gpu/cmd_validation/gpuav_dispatch.cpp b/layers/gpu/cmd_validation/gpuav_dispatch.cpp index 51064c50593..03231f27a59 100644 --- a/layers/gpu/cmd_validation/gpuav_dispatch.cpp +++ b/layers/gpu/cmd_validation/gpuav_dispatch.cpp @@ -189,7 +189,7 @@ void InsertIndirectDispatchValidation(Validator &gpuav, const Location &loc, Com DispatchUpdateDescriptorSets(gpuav.device, 1, &desc_write, 0, nullptr); // Save current graphics pipeline state - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_COMPUTE); + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE); // Insert diagnostic dispatch if (use_shader_objects) { diff --git a/layers/gpu/cmd_validation/gpuav_draw.cpp b/layers/gpu/cmd_validation/gpuav_draw.cpp index bfe5941de6c..e5b91784453 100644 --- a/layers/gpu/cmd_validation/gpuav_draw.cpp +++ b/layers/gpu/cmd_validation/gpuav_draw.cpp @@ -83,16 +83,31 @@ static VkPipeline GetDrawValidationPipeline(Validator &gpuav, pipeline_stage_ci.pName = "main"; VkGraphicsPipelineCreateInfo pipeline_ci = vku::InitStructHelper(); + // As of writing, adding a VkPipelineRenderingCreateInfoKHR is not strictly needed, + // if dynamic rendering is used a default empty VkPipelineRenderingCreateInfoKHR + // is assumed. Might have to change in the future. + // VkPipelineRenderingCreateInfoKHR pipeline_rendering_ci = vku::InitStructHelper(); + // if (using_dynamic_rendering) pipeline_ci.pNext = &pipeline_rendering_ci; + VkPipelineVertexInputStateCreateInfo vertex_input_state = vku::InitStructHelper(); VkPipelineInputAssemblyStateCreateInfo input_assembly_state = vku::InitStructHelper(); input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; VkPipelineRasterizationStateCreateInfo rasterization_state = vku::InitStructHelper(); + rasterization_state.lineWidth = 1.0; rasterization_state.rasterizerDiscardEnable = VK_TRUE; VkPipelineColorBlendStateCreateInfo color_blend_state = vku::InitStructHelper(); pipeline_ci.pVertexInputState = &vertex_input_state; pipeline_ci.pInputAssemblyState = &input_assembly_state; + pipeline_ci.pTessellationState = + nullptr; // If not null, need to update gpuav::CommandBuffer::RestoreDynamicStates with corresponding dynamic states + pipeline_ci.pViewportState = + nullptr; // If not null, need to update gpuav::CommandBuffer::RestoreDynamicStates with corresponding dynamic states pipeline_ci.pRasterizationState = &rasterization_state; + pipeline_ci.pMultisampleState = + nullptr; // If not null, need to update gpuav::CommandBuffer::RestoreDynamicStates with corresponding dynamic states + pipeline_ci.pDepthStencilState = + nullptr; // If not null, need to update gpuav::CommandBuffer::RestoreDynamicStates with corresponding dynamic states pipeline_ci.pColorBlendState = &color_blend_state; pipeline_ci.renderPass = render_pass; pipeline_ci.layout = pipeline_layout; @@ -267,7 +282,12 @@ void FirstInstance(Validator &gpuav, CommandBuffer &cb_state, const Location &lo if (gpuav.enabled_features.drawIndirectFirstInstance) return; - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); + if (cb_state.activeRenderPass->use_dynamic_rendering_inherited) { + // Unhandled for now + return; + } + + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); auto &shared_draw_validation_resources = gpuav.shared_resources_manager.Get(gpuav, loc); if (!shared_draw_validation_resources.valid) return; @@ -411,7 +431,12 @@ void CountBuffer(Validator &gpuav, CommandBuffer &cb_state, const Location &loc, return; } - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); + if (cb_state.activeRenderPass->use_dynamic_rendering_inherited) { + // Unhandled for now + return; + } + + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); auto &shared_draw_validation_resources = gpuav.shared_resources_manager.Get(gpuav, loc); if (!shared_draw_validation_resources.valid) return; @@ -552,7 +577,12 @@ void DrawMeshIndirect(Validator &gpuav, CommandBuffer &cb_state, const Location return; } - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); + if (cb_state.activeRenderPass->use_dynamic_rendering_inherited) { + // Unhandled for now + return; + } + + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); const auto lv_bind_point = ConvertToLvlBindPoint(VK_PIPELINE_BIND_POINT_GRAPHICS); auto const &last_bound = cb_state.lastBound[lv_bind_point]; @@ -808,7 +838,7 @@ static SmallestVertexBufferBinding SmallestVertexAttributesCount(const vvl::Comm void DrawIndexed(Validator &gpuav, CommandBuffer &cb_state, const Location &loc, uint32_t index_count, uint32_t first_index, uint32_t vertex_offset, const char *vuid_oob_vertex) { - if (!gpuav.gpuav_settings.validate_indirect_draws_buffers) { + if (!gpuav.gpuav_settings.validate_index_buffers) { return; } @@ -820,13 +850,18 @@ void DrawIndexed(Validator &gpuav, CommandBuffer &cb_state, const Location &loc, return; } + if (cb_state.activeRenderPass->use_dynamic_rendering_inherited) { + // Unhandled for now + return; + } + const SmallestVertexBufferBinding smallest_vertex_buffer_binding = SmallestVertexAttributesCount(cb_state); if (smallest_vertex_buffer_binding.min_vertex_attributes_count == std::numeric_limits::max()) { // cannot overrun index buffer, skip validation return; } - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); auto &shared_draw_validation_resources = gpuav.shared_resources_manager.Get(gpuav, loc); if (!shared_draw_validation_resources.valid) return; @@ -983,7 +1018,7 @@ struct DrawIndexedIndirectIndexBufferShader { void DrawIndexedIndirectIndexBuffer(Validator &gpuav, CommandBuffer &cb_state, const Location &loc, VkBuffer draw_buffer, VkDeviceSize draw_buffer_offset, uint32_t draw_cmds_byte_stride, uint32_t draw_count, VkBuffer count_buffer, VkDeviceSize count_buffer_offset, const char *vuid_oob_index) { - if (!gpuav.gpuav_settings.validate_indirect_draws_buffers) { + if (!gpuav.gpuav_settings.validate_index_buffers) { return; } @@ -995,7 +1030,12 @@ void DrawIndexedIndirectIndexBuffer(Validator &gpuav, CommandBuffer &cb_state, c return; } - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); + if (cb_state.activeRenderPass->use_dynamic_rendering_inherited) { + // Unhandled for now + return; + } + + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); auto &shared_draw_validation_resources = gpuav.shared_resources_manager.Get(gpuav, loc); if (!shared_draw_validation_resources.valid) return; @@ -1150,7 +1190,7 @@ struct DrawIndexedIndirectVertexBufferShader { void DrawIndexedIndirectVertexBuffer(Validator &gpuav, CommandBuffer &cb_state, const Location &loc, VkBuffer draw_buffer, VkDeviceSize draw_buffer_offset, uint32_t draw_cmds_byte_stride, uint32_t draw_count, VkBuffer count_buffer, VkDeviceSize count_buffer_offset, const char *vuid_oob_vertex) { - if (!gpuav.gpuav_settings.validate_indirect_draws_buffers) { + if (!gpuav.gpuav_settings.validate_index_buffers) { return; } @@ -1162,7 +1202,12 @@ void DrawIndexedIndirectVertexBuffer(Validator &gpuav, CommandBuffer &cb_state, return; } - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); + if (cb_state.activeRenderPass->use_dynamic_rendering_inherited) { + // Unhandled for now + return; + } + + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS); auto &shared_draw_validation_resources = gpuav.shared_resources_manager.Get(gpuav, loc); if (!shared_draw_validation_resources.valid) return; diff --git a/layers/gpu/cmd_validation/gpuav_trace_rays.cpp b/layers/gpu/cmd_validation/gpuav_trace_rays.cpp index eca58670821..32166484369 100644 --- a/layers/gpu/cmd_validation/gpuav_trace_rays.cpp +++ b/layers/gpu/cmd_validation/gpuav_trace_rays.cpp @@ -215,7 +215,7 @@ void InsertIndirectTraceRaysValidation(Validator &gpuav, const Location &loc, Co } // Save current ray tracing pipeline state - RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR); + RestorablePipelineState restorable_state(gpuav, cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR); // Push info needed for validation: // - the device address indirect data is read from diff --git a/layers/gpu/core/gpu_settings.h b/layers/gpu/core/gpu_settings.h index 978264ab06d..cdb7fb6ad4e 100644 --- a/layers/gpu/core/gpu_settings.h +++ b/layers/gpu/core/gpu_settings.h @@ -30,6 +30,7 @@ struct GpuAVSettings { bool validate_indirect_dispatches_buffers = true; bool validate_indirect_trace_rays_buffers = true; bool validate_buffer_copies = true; + bool validate_index_buffers = true; bool vma_linear_output = true; @@ -62,13 +63,14 @@ struct GpuAVSettings { } bool IsBufferValidationEnabled() const { return validate_indirect_draws_buffers || validate_indirect_dispatches_buffers || validate_indirect_trace_rays_buffers || - validate_buffer_copies; + validate_buffer_copies || validate_index_buffers; } void SetBufferValidationEnabled(bool enabled) { validate_indirect_draws_buffers = enabled; validate_indirect_dispatches_buffers = enabled; validate_indirect_trace_rays_buffers = enabled; validate_buffer_copies = enabled; + validate_index_buffers = enabled; } }; diff --git a/layers/gpu/resources/gpuav_subclasses.cpp b/layers/gpu/resources/gpuav_subclasses.cpp index 29937fe2552..8f1b26cc3a3 100644 --- a/layers/gpu/resources/gpuav_subclasses.cpp +++ b/layers/gpu/resources/gpuav_subclasses.cpp @@ -438,6 +438,124 @@ void CommandBuffer::ClearCmdErrorsCountsBuffer(const Location &loc) const { vmaUnmapMemory(gpuav->vma_allocator_, cmd_errors_counts_buffer_.allocation); } +void CommandBuffer::RestoreDynamicStates(const Validator &gpuav_) { + for (int dynamic_state = 0; dynamic_state < CB_DYNAMIC_STATE_STATUS_NUM; ++dynamic_state) { + if (!dynamic_state_status.cb[dynamic_state]) { + continue; + } + + switch (dynamic_state) { + case CB_DYNAMIC_STATE_VIEWPORT: { + DispatchCmdSetViewport(VkHandle(), dynamic_state_value.first_viewport, + uint32_t(dynamic_state_value.viewports.size()), dynamic_state_value.viewports.data()); + } break; + case CB_DYNAMIC_STATE_DEPTH_BIAS: { + DispatchCmdSetDepthBias(VkHandle(), dynamic_state_value.depth_bias_constant_factor, + dynamic_state_value.depth_bias_clamp, dynamic_state_value.depth_bias_slope_factor); + } break; + case CB_DYNAMIC_STATE_BLEND_CONSTANTS: { + DispatchCmdSetBlendConstants(VkHandle(), dynamic_state_value.blend_constants.data()); + } break; + case CB_DYNAMIC_STATE_DEPTH_TEST_ENABLE: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state)) { + DispatchCmdSetDepthTestEnableEXT(VkHandle(), dynamic_state_value.depth_test_enable); + } else { + DispatchCmdSetDepthTestEnable(VkHandle(), dynamic_state_value.depth_test_enable); + } + } break; + case CB_DYNAMIC_STATE_DEPTH_WRITE_ENABLE: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state)) { + DispatchCmdSetDepthWriteEnableEXT(VkHandle(), dynamic_state_value.depth_write_enable); + } else { + DispatchCmdSetDepthWriteEnable(VkHandle(), dynamic_state_value.depth_write_enable); + } + } break; + case CB_DYNAMIC_STATE_DEPTH_BIAS_ENABLE: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state2)) { + DispatchCmdSetDepthBiasEnableEXT(VkHandle(), dynamic_state_value.depth_bias_enable); + } else { + DispatchCmdSetDepthBiasEnable(VkHandle(), dynamic_state_value.depth_bias_enable); + } + } break; + case CB_DYNAMIC_STATE_DEPTH_COMPARE_OP: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state)) { + DispatchCmdSetDepthCompareOpEXT(VkHandle(), dynamic_state_value.depth_compare_op); + } else { + DispatchCmdSetDepthCompareOp(VkHandle(), dynamic_state_value.depth_compare_op); + } + } break; + case CB_DYNAMIC_STATE_VERTEX_INPUT_EXT: { + std::vector vertex_binding_descs; + std::vector vertex_attribute_descs; + for (const auto &[binding_unused_, vertex_binding_state] : dynamic_state_value.vertex_bindings) { + // Given how dynamic_state_value.vertex_bindings is filled, no need to filter vertex binding descriptions before + // adding them to the list: + // they are not duplicated, and they are all here. + vertex_binding_descs.push_back(*vertex_binding_state.desc.ptr()); + + for (const auto &[location_unused_2, vertex_attribute_state] : vertex_binding_state.locations) { + auto has_same_vertex_attribute = + [lhs = vertex_attribute_state.desc.ptr()](const VkVertexInputAttributeDescription2EXT &rhs) { + return lhs->sType == rhs.sType && lhs->pNext == rhs.pNext && lhs->location == rhs.location && + lhs->binding == rhs.binding && lhs->format == rhs.format && lhs->offset == rhs.offset; + }; + if (std::find_if(vertex_attribute_descs.begin(), vertex_attribute_descs.end(), has_same_vertex_attribute) == + vertex_attribute_descs.end()) { + vertex_attribute_descs.push_back(*vertex_attribute_state.desc.ptr()); + } + } + } + DispatchCmdSetVertexInputEXT(VkHandle(), uint32_t(vertex_attribute_descs.size()), vertex_binding_descs.data(), + uint32_t(vertex_attribute_descs.size()), vertex_attribute_descs.data()); + } break; + + case CB_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state)) { + DispatchCmdSetPrimitiveRestartEnableEXT(VkHandle(), dynamic_state_value.primitive_restart_enable); + } else { + DispatchCmdSetPrimitiveRestartEnable(VkHandle(), dynamic_state_value.primitive_restart_enable); + } + } break; + case CB_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state)) { + DispatchCmdSetPrimitiveTopologyEXT(VkHandle(), dynamic_state_value.primitive_topology); + } else { + DispatchCmdSetPrimitiveTopology(VkHandle(), dynamic_state_value.primitive_topology); + } + } break; + case CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT: { + DispatchCmdSetDepthClampEnableEXT(VkHandle(), dynamic_state_value.depth_clamp_enable); + } break; + case CB_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state2)) { + DispatchCmdSetRasterizerDiscardEnableEXT(VkHandle(), dynamic_state_value.rasterizer_discard_enable); + } else { + DispatchCmdSetRasterizerDiscardEnable(VkHandle(), dynamic_state_value.rasterizer_discard_enable); + } + } break; + case CB_DYNAMIC_STATE_POLYGON_MODE_EXT: { + DispatchCmdSetPolygonModeEXT(VkHandle(), dynamic_state_value.polygon_mode); + } break; + case CB_DYNAMIC_STATE_CULL_MODE: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state)) { + DispatchCmdSetCullModeEXT(VkHandle(), dynamic_state_value.cull_mode); + } else { + DispatchCmdSetCullMode(VkHandle(), dynamic_state_value.cull_mode); + } + } break; + case CB_DYNAMIC_STATE_FRONT_FACE: { + if (IsExtEnabledByCreateinfo(gpuav_.device_extensions.vk_ext_extended_dynamic_state)) { + DispatchCmdSetFrontFaceEXT(VkHandle(), dynamic_state_value.front_face); + } else { + DispatchCmdSetFrontFace(VkHandle(), dynamic_state_value.front_face); + } + } break; + default: + break; + } + } +} + bool CommandBuffer::PreProcess(const Location &loc) { auto gpuav = static_cast(&dev_data); diff --git a/layers/gpu/resources/gpuav_subclasses.h b/layers/gpu/resources/gpuav_subclasses.h index 2fdfc321058..2fe56859b40 100644 --- a/layers/gpu/resources/gpuav_subclasses.h +++ b/layers/gpu/resources/gpuav_subclasses.h @@ -88,13 +88,16 @@ class CommandBuffer : public gpu_tracker::CommandBuffer { void ClearCmdErrorsCountsBuffer(const Location &loc) const; + void RestoreDynamicStates(const Validator &gpuav); + void Destroy() final; void Reset(const Location &loc) final; gpu::GpuResourcesManager gpu_resources_manager; // Using stdext::inplace_function over std::function to allocate memory in place using ErrorLoggerFunc = - stdext::inplace_function; + stdext::inplace_function; std::vector per_command_error_loggers; private: diff --git a/layers/layer_options.cpp b/layers/layer_options.cpp index 6f52b7fce9b..bdb8ecc5424 100644 --- a/layers/layer_options.cpp +++ b/layers/layer_options.cpp @@ -186,6 +186,7 @@ const char *VK_LAYER_GPUAV_INDIRECT_DRAWS_BUFFERS = "gpuav_indirect_draws_buffer const char *VK_LAYER_GPUAV_INDIRECT_DISPATCHES_BUFFERS = "gpuav_indirect_dispatches_buffers"; const char *VK_LAYER_GPUAV_INDIRECT_TRACE_RAYS_BUFFERS = "gpuav_indirect_trace_rays_buffers"; const char *VK_LAYER_GPUAV_BUFFER_COPIES = "gpuav_buffer_copies"; +const char *VK_LAYER_GPUAV_INDEX_BUFFERS = "gpuav_index_buffers"; const char *VK_LAYER_GPUAV_RESERVE_BINDING_SLOT = "gpuav_reserve_binding_slot"; const char *VK_LAYER_GPUAV_VMA_LINEAR_OUTPUT = "gpuav_vma_linear_output"; @@ -695,6 +696,9 @@ void ProcessConfigAndEnvSettings(ConfigAndEnvSettings *settings_data) { printf("Validation Setting Warning - %s was set, this is deprecated, please use %s\n", DEPRECATED_VK_LAYER_GPUAV_VALIDATE_COPIES, VK_LAYER_GPUAV_BUFFER_COPIES); } + if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_INDEX_BUFFERS)) { + vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_INDEX_BUFFERS, gpuav_settings.validate_index_buffers); + } } if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_RESERVE_BINDING_SLOT)) { diff --git a/layers/state_tracker/cmd_buffer_state.cpp b/layers/state_tracker/cmd_buffer_state.cpp index 16655af2a4f..9489474f421 100644 --- a/layers/state_tracker/cmd_buffer_state.cpp +++ b/layers/state_tracker/cmd_buffer_state.cpp @@ -301,6 +301,10 @@ void CommandBuffer::ResetCBState() { label_stack_depth_ = 0; label_commands_.clear(); + push_constant_data_chunks.clear(); + push_constant_latest_used_layout.fill(VK_NULL_HANDLE); + push_constant_ranges_layout.reset(); + nesting_level = 0; transform_feedback_active = false; @@ -341,8 +345,9 @@ void CommandBuffer::ResetPushConstantRangesLayoutIfIncompatible(const vvl::Pipel return; } - push_constant_ranges_layout = pipeline_layout_state.push_constant_ranges_layout; push_constant_data_chunks.clear(); + push_constant_latest_used_layout.fill(VK_NULL_HANDLE); + push_constant_ranges_layout = pipeline_layout_state.push_constant_ranges_layout; } void CommandBuffer::Destroy() { @@ -1723,6 +1728,7 @@ void CommandBuffer::UnbindResources() { // Push constants push_constant_data_chunks.clear(); + push_constant_latest_used_layout.fill(VK_NULL_HANDLE); push_constant_ranges_layout.reset(); // Reset status of cb to force rebinding of all resources diff --git a/layers/state_tracker/cmd_buffer_state.h b/layers/state_tracker/cmd_buffer_state.h index 30530ece7b1..5f2c2164b24 100644 --- a/layers/state_tracker/cmd_buffer_state.h +++ b/layers/state_tracker/cmd_buffer_state.h @@ -216,6 +216,10 @@ class CommandBuffer : public RefcountedStateObject { bool depth_test_enable; // VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE bool depth_bounds_test_enable; + // VK_DYNAMIC_STATE_DEPTH_COMPARE_OP + VkCompareOp depth_compare_op; + // VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT + bool depth_clamp_enable; // VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE bool stencil_test_enable; // VK_DYNAMIC_STATE_STENCIL_OP @@ -227,6 +231,8 @@ class CommandBuffer : public RefcountedStateObject { VkStencilOp depth_fail_op_back; // VK_DYNAMIC_STATE_CULL_MODE VkCullModeFlags cull_mode; + // VK_DYNAMIC_STATE_FRONT_FACE + VkFrontFace front_face; // VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY VkPrimitiveTopology primitive_topology; // VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT @@ -271,6 +277,11 @@ class CommandBuffer : public RefcountedStateObject { // VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE bool primitive_restart_enable; + // VK_DYNAMIC_STATE_DEPTH_BIAS + float depth_bias_constant_factor; + float depth_bias_clamp; + float depth_bias_slope_factor; + uint32_t color_write_enable_attachment_count; // maxColorAttachments is at max 8 on all known implementations currently @@ -283,6 +294,9 @@ class CommandBuffer : public RefcountedStateObject { std::vector color_blend_equations; // VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT std::vector color_write_masks; // VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT + // VK_DYNAMIC_STATE_BLEND_CONSTANTS + std::array blend_constants; + // VK_DYNAMIC_STATE_VERTEX_INPUT_EXT, key is binding number vvl::unordered_map vertex_bindings; @@ -294,6 +308,7 @@ class CommandBuffer : public RefcountedStateObject { VkImageAspectFlags attachment_feedback_loop_enable; // VK_DYNAMIC_STATE_VIEWPORT + uint32_t first_viewport; std::vector viewports; // and VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT uint32_t viewport_count; diff --git a/layers/state_tracker/state_tracker.cpp b/layers/state_tracker/state_tracker.cpp index 04053779d97..70c386ed39e 100644 --- a/layers/state_tracker/state_tracker.cpp +++ b/layers/state_tracker/state_tracker.cpp @@ -2371,7 +2371,7 @@ void ValidationStateTracker::PostCallRecordCmdSetViewport(VkCommandBuffer comman uint32_t bits = ((1u << viewportCount) - 1u) << firstViewport; cb_state->viewportMask |= bits; cb_state->trashedViewportMask &= ~bits; - + cb_state->dynamic_state_value.first_viewport = firstViewport; if (cb_state->dynamic_state_value.viewports.size() < firstViewport + viewportCount) { cb_state->dynamic_state_value.viewports.resize(firstViewport + viewportCount); } @@ -2688,13 +2688,16 @@ void ValidationStateTracker::PostCallRecordCmdSetDepthBias(VkCommandBuffer comma const RecordObject &record_obj) { auto cb_state = GetWrite(commandBuffer); cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_DEPTH_BIAS); + cb_state->dynamic_state_value.depth_bias_constant_factor = depthBiasConstantFactor; + cb_state->dynamic_state_value.depth_bias_clamp = depthBiasClamp; + cb_state->dynamic_state_value.depth_bias_slope_factor = depthBiasSlopeFactor; } void ValidationStateTracker::PostCallRecordCmdSetDepthBias2EXT(VkCommandBuffer commandBuffer, const VkDepthBiasInfoEXT *pDepthBiasInfo, const RecordObject &record_obj) { - auto cb_state = GetWrite(commandBuffer); - cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_DEPTH_BIAS); + PostCallRecordCmdSetDepthBias(commandBuffer, pDepthBiasInfo->depthBiasConstantFactor, pDepthBiasInfo->depthBiasClamp, + pDepthBiasInfo->depthBiasSlopeFactor, record_obj); } void ValidationStateTracker::PostCallRecordCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, @@ -2711,6 +2714,9 @@ void ValidationStateTracker::PostCallRecordCmdSetBlendConstants(VkCommandBuffer const RecordObject &record_obj) { auto cb_state = GetWrite(commandBuffer); cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_BLEND_CONSTANTS); + for (int i = 0; i < 4; ++i) { + cb_state->dynamic_state_value.blend_constants[i] = blendConstants[i]; + } } void ValidationStateTracker::PostCallRecordCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, @@ -2877,22 +2883,20 @@ void ValidationStateTracker::PostCallRecordCmdPushConstants(VkCommandBuffer comm auto cb_state = GetWrite(commandBuffer); ASSERT_AND_RETURN(cb_state); - LvlBindPoint bind_point = BindPoint_Count; + cb_state->RecordCmd(record_obj.location.function); + auto layout_state = Get(layout); + cb_state->ResetPushConstantRangesLayoutIfIncompatible(*layout_state); + if (IsStageInPipelineBindPoint(stageFlags, VK_PIPELINE_BIND_POINT_GRAPHICS)) { - bind_point = BindPoint_Graphics; + cb_state->push_constant_latest_used_layout[BindPoint_Graphics] = layout; } else if (IsStageInPipelineBindPoint(stageFlags, VK_PIPELINE_BIND_POINT_COMPUTE)) { - bind_point = BindPoint_Compute; + cb_state->push_constant_latest_used_layout[BindPoint_Compute] = layout; } else if (IsStageInPipelineBindPoint(stageFlags, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)) { - bind_point = BindPoint_Ray_Tracing; + cb_state->push_constant_latest_used_layout[BindPoint_Ray_Tracing] = layout; } else { // Need to handle new binding point assert(false); } - cb_state->push_constant_latest_used_layout[bind_point] = layout; - - cb_state->RecordCmd(record_obj.location.function); - auto layout_state = Get(layout); - cb_state->ResetPushConstantRangesLayoutIfIncompatible(*layout_state); vvl::CommandBuffer::PushConstantData push_constant_data; push_constant_data.layout = layout; @@ -4917,6 +4921,7 @@ void ValidationStateTracker::PostCallRecordCmdSetFrontFace(VkCommandBuffer comma const RecordObject &record_obj) { auto cb_state = GetWrite(commandBuffer); cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_FRONT_FACE); + cb_state->dynamic_state_value.front_face = frontFace; } void ValidationStateTracker::PostCallRecordCmdSetPrimitiveTopologyEXT(VkCommandBuffer commandBuffer, @@ -5042,6 +5047,7 @@ void ValidationStateTracker::PostCallRecordCmdSetDepthCompareOp(VkCommandBuffer const RecordObject &record_obj) { auto cb_state = GetWrite(commandBuffer); cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_DEPTH_COMPARE_OP); + cb_state->dynamic_state_value.depth_compare_op = depthCompareOp; } void ValidationStateTracker::PostCallRecordCmdSetDepthBoundsTestEnableEXT(VkCommandBuffer commandBuffer, @@ -5311,6 +5317,7 @@ void ValidationStateTracker::PostCallRecordCmdSetDepthClampEnableEXT(VkCommandBu const RecordObject &record_obj) { auto cb_state = GetWrite(commandBuffer); cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT); + cb_state->dynamic_state_value.depth_clamp_enable = depthClampEnable; } void ValidationStateTracker::PostCallRecordCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode, diff --git a/tests/framework/buffer_helper.h b/tests/framework/buffer_helper.h index 23be3ef5ad5..61d022bbe85 100644 --- a/tests/framework/buffer_helper.h +++ b/tests/framework/buffer_helper.h @@ -42,4 +42,15 @@ Buffer IndexBuffer(const Device &dev, const std::vector &indices) { return index_buffer; } +// stride == sizeof(IndirectCmdT) +template +Buffer IndirectBuffer(const Device &dev, const std::vector &indirect_cmds) { + vkt::Buffer indirect_buffer(dev, indirect_cmds.size() * sizeof(IndirectCmdT), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + auto *indirect_buffer_ptr = static_cast(indirect_buffer.memory().map()); + std::copy(indirect_cmds.data(), indirect_cmds.data() + indirect_cmds.size(), indirect_buffer_ptr); + indirect_buffer.memory().unmap(); + return indirect_buffer; +} + } // namespace vkt diff --git a/tests/unit/gpu_av_index_buffer_positive.cpp b/tests/unit/gpu_av_index_buffer_positive.cpp index e5e59a7ac1b..4738892dd14 100644 --- a/tests/unit/gpu_av_index_buffer_positive.cpp +++ b/tests/unit/gpu_av_index_buffer_positive.cpp @@ -33,17 +33,13 @@ TEST_F(PositiveGpuAVIndexBuffer, BadVertexIndex) { pipe.gp_ci_.layout = pipeline_layout.handle(); pipe.CreateGraphicsPipeline(); - vkt::Buffer indexed_draw_buffer(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - { - auto indexed_draw_ptr = reinterpret_cast(indexed_draw_buffer.memory().map()); - indexed_draw_ptr->indexCount = 3; - indexed_draw_ptr->instanceCount = 1; - indexed_draw_ptr->firstIndex = 0; - indexed_draw_ptr->vertexOffset = 0; - indexed_draw_ptr->firstInstance = 0; - indexed_draw_buffer.memory().unmap(); - } + 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(*m_device, {draw_params}); VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); @@ -52,7 +48,7 @@ TEST_F(PositiveGpuAVIndexBuffer, BadVertexIndex) { vkt::Buffer index_buffer = vkt::IndexBuffer(*m_device, {0, std::numeric_limits::max(), 42}); vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32); - vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), indexed_draw_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); + vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); m_default_queue->Submit(*m_commandBuffer); @@ -75,36 +71,110 @@ TEST_F(PositiveGpuAVIndexBuffer, VertexIndex) { pipe.gp_ci_.layout = pipeline_layout.handle(); pipe.CreateGraphicsPipeline(); - // Now with an offset and indexed draw - vkt::Buffer indexed_draw_buffer(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - { - VkDrawIndexedIndirectCommand *indexed_draw_ptr = (VkDrawIndexedIndirectCommand *)indexed_draw_buffer.memory().map(); - indexed_draw_ptr->indexCount = 3; - indexed_draw_ptr->instanceCount = 1; - indexed_draw_ptr->firstIndex = 0; - indexed_draw_ptr->vertexOffset = 0; - indexed_draw_ptr->firstInstance = 0; - indexed_draw_buffer.memory().unmap(); + constexpr uint32_t num_vertices = 12; + std::vector indicies(num_vertices); + for (uint32_t i = 0; i < num_vertices; i++) { + indicies[i] = num_vertices - 1 - i; } + vkt::Buffer index_buffer = vkt::IndexBuffer(*m_device, std::move(indicies)); + + 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(*m_device, {draw_params}); VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); - const uint32_t kNumVertices = 12; - vkt::Buffer index_buffer(*m_device, kNumVertices * sizeof(uint32_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - auto *indicies = static_cast(index_buffer.memory().map()); - for (uint32_t i = 0; i < kNumVertices; i++) { - indicies[i] = kNumVertices - 1 - i; - } - index_buffer.memory().unmap(); vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32); - vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), indexed_draw_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); + vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); m_default_queue->Submit(*m_commandBuffer); m_default_queue->Wait(); } + +TEST_F(PositiveGpuAVIndexBuffer, DrawIndexedDynamicStates) { + TEST_DESCRIPTION("vkCmdDrawIndexed - Set dynamic states"); + AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + 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); + RETURN_IF_SKIP(InitGpuAvFramework()); + + AddRequiredFeature(vkt::Feature::extendedDynamicState); + AddRequiredFeature(vkt::Feature::extendedDynamicState2); + AddRequiredFeature(vkt::Feature::extendedDynamicState3PolygonMode); + AddDisabledFeature(vkt::Feature::robustBufferAccess); + RETURN_IF_SKIP(InitState()); + InitRenderTarget(); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vku::InitStructHelper(); + vkt::PipelineLayout pipeline_layout(*m_device, pipelineLayoutCreateInfo); + + char const *vsSource = R"glsl( + #version 450 + + layout(location=0) in vec3 pos; + + void main() { + gl_Position = vec4(pos, 1.0); + } + )glsl"; + VkShaderObj vs(this, 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.gp_ci_.layout = pipeline_layout.handle(); + pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; + pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE); + pipe.AddDynamicState(VK_DYNAMIC_STATE_CULL_MODE); + pipe.AddDynamicState(VK_DYNAMIC_STATE_FRONT_FACE); + pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE); + pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS); + pipe.AddDynamicState(VK_DYNAMIC_STATE_LINE_WIDTH); + pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE); + pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY); + pipe.CreateGraphicsPipeline(); + + vkt::Buffer index_buffer = vkt::IndexBuffer(*m_device, {0, 1, 2}); + vkt::Buffer vertex_buffer = vkt::VertexBuffer(*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; + + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); + m_commandBuffer->begin(&begin_info); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + + vk::CmdSetRasterizerDiscardEnableEXT(m_commandBuffer->handle(), VK_FALSE); + vk::CmdSetCullModeEXT(m_commandBuffer->handle(), VK_CULL_MODE_NONE); + vk::CmdSetFrontFaceEXT(m_commandBuffer->handle(), VK_FRONT_FACE_CLOCKWISE); + vk::CmdSetDepthBiasEnableEXT(m_commandBuffer->handle(), VK_TRUE); + vk::CmdSetDepthBias(m_commandBuffer->handle(), 0.0f, 1.0f, 1.0f); + vk::CmdSetLineWidth(m_commandBuffer->handle(), 1.0f); + vk::CmdSetPrimitiveRestartEnableEXT(m_commandBuffer->handle(), VK_FALSE); + vk::CmdSetPrimitiveTopologyEXT(m_commandBuffer->handle(), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + + vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32); + vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); + + vk::CmdDrawIndexed(m_commandBuffer->handle(), 3, 1, 0, 0, 0); + + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); + + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); + m_errorMonitor->VerifyFound(); +} diff --git a/tests/unit/gpu_av_indirect_buffer.cpp b/tests/unit/gpu_av_indirect_buffer.cpp index eceeeeaf687..880c09d9137 100644 --- a/tests/unit/gpu_av_indirect_buffer.cpp +++ b/tests/unit/gpu_av_indirect_buffer.cpp @@ -588,27 +588,30 @@ TEST_F(NegativeGpuAVIndirectBuffer, FirstInstance) { pipe.gp_ci_.layout = pipeline_layout.handle(); pipe.CreateGraphicsPipeline(); - VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); - vkt::Buffer draw_buffer(*m_device, 4 * sizeof(VkDrawIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VkDrawIndirectCommand *draw_ptr = static_cast(draw_buffer.memory().map()); - for (uint32_t i = 0; i < 4; i++) { - draw_ptr->vertexCount = 3; - draw_ptr->instanceCount = 1; - draw_ptr->firstVertex = 0; - draw_ptr->firstInstance = (i == 1) ? 1 : (i == 3) ? 42 : 0; - draw_ptr++; - } - draw_buffer.memory().unmap(); + VkDrawIndirectCommand draw_params{}; + draw_params.vertexCount = 3; + draw_params.instanceCount = 1; + draw_params.firstVertex = 0; + draw_params.firstInstance = 0; + VkDrawIndirectCommand draw_params_invalid_first_instance_1 = draw_params; + draw_params_invalid_first_instance_1.firstInstance = 1; + VkDrawIndirectCommand draw_params_invalid_first_instance_42 = draw_params; + draw_params_invalid_first_instance_42.firstInstance = 42; + vkt::Buffer draw_params_buffer = vkt::IndirectBuffer( + *m_device, {draw_params, draw_params_invalid_first_instance_1, draw_params, draw_params_invalid_first_instance_42}); - m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndirectCommand-firstInstance-00501", "at index 1 is 1"); - m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndirectCommand-firstInstance-00501", "at index 3 is 42"); + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); - vk::CmdDrawIndirect(m_commandBuffer->handle(), draw_buffer.handle(), 0, 4, sizeof(VkDrawIndirectCommand)); + + m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndirectCommand-firstInstance-00501", "at index 1 is 1"); + m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndirectCommand-firstInstance-00501", "at index 3 is 42"); + vk::CmdDrawIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), 0, 4, sizeof(VkDrawIndirectCommand)); + m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); + m_default_queue->Submit(*m_commandBuffer); m_default_queue->Wait(); m_errorMonitor->VerifyFound(); @@ -630,35 +633,27 @@ TEST_F(NegativeGpuAVIndirectBuffer, FirstInstanceIndexed) { pipe.gp_ci_.layout = pipeline_layout.handle(); pipe.CreateGraphicsPipeline(); - VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); - // Now with an offset and indexed draw - m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndexedIndirectCommand-firstInstance-00554", "at index 2 is 1"); - vkt::Buffer indexed_draw_buffer(*m_device, 4 * sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VkDrawIndexedIndirectCommand *indexed_draw_ptr = (VkDrawIndexedIndirectCommand *)indexed_draw_buffer.memory().map(); - for (uint32_t i = 0; i < 4; i++) { - indexed_draw_ptr->indexCount = 3; - indexed_draw_ptr->instanceCount = 1; - indexed_draw_ptr->firstIndex = 0; - indexed_draw_ptr->vertexOffset = 0; - indexed_draw_ptr->firstInstance = (i == 3) ? 1 : 0; - indexed_draw_ptr++; - } - indexed_draw_buffer.memory().unmap(); + VkDrawIndexedIndirectCommand draw_params{}; + draw_params.indexCount = 3; + draw_params.instanceCount = 1; + draw_params.firstIndex = 0; + draw_params.vertexOffset = 0; + draw_params.firstInstance = 0; + VkDrawIndexedIndirectCommand draw_params_invalid_first_instance = draw_params; + draw_params_invalid_first_instance.firstInstance = 1; + vkt::Buffer draw_params_buffer = vkt::IndirectBuffer( + *m_device, {draw_params, draw_params, draw_params, draw_params_invalid_first_instance}); + + vkt::Buffer index_buffer = vkt::IndexBuffer(*m_device, {1, 2, 3}); + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); - vkt::Buffer index_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - uint32_t *index_ptr = (uint32_t *)index_buffer.memory().map(); - index_ptr[0] = 0; - index_ptr[1] = 1; - index_ptr[2] = 2; - index_buffer.memory().unmap(); vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32); - vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), indexed_draw_buffer.handle(), sizeof(VkDrawIndexedIndirectCommand), 3, + m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndexedIndirectCommand-firstInstance-00554", "at index 2 is 1"); + vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), sizeof(VkDrawIndexedIndirectCommand), 3, sizeof(VkDrawIndexedIndirectCommand)); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); @@ -684,37 +679,26 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndexBufferOOB) { pipe.gp_ci_.layout = pipeline_layout.handle(); pipe.CreateGraphicsPipeline(); - // Now with an offset and indexed draw - vkt::Buffer indexed_draw_buffer(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - { - VkDrawIndexedIndirectCommand *indexed_draw_ptr = (VkDrawIndexedIndirectCommand *)indexed_draw_buffer.memory().map(); - indexed_draw_ptr->indexCount = 3; - indexed_draw_ptr->instanceCount = 1; - indexed_draw_ptr->firstIndex = 1; - indexed_draw_ptr->vertexOffset = 0; - indexed_draw_ptr->firstInstance = 0; - indexed_draw_buffer.memory().unmap(); - } + 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(*m_device, {draw_params}); + + vkt::Buffer index_buffer = vkt::IndexBuffer(*m_device, {1, 2, 3}); VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); - vkt::Buffer index_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - auto *indicies = static_cast(index_buffer.memory().map()); - indicies[0] = 0u; - indicies[1] = 1u; - indicies[2] = 2u; - index_buffer.memory().unmap(); m_errorMonitor->SetDesiredErrorRegex( "VUID-VkDrawIndexedIndirectCommand-robustBufferAccess2-08798", "Index 4 is not within the bound index buffer. Computed from VkDrawIndexedIndirectCommand\\[0\\]"); - vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32); - vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), indexed_draw_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); + vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); m_default_queue->Submit(*m_commandBuffer); @@ -758,18 +742,13 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex32) { pipe.CreateGraphicsPipeline(); - // Now with an offset and indexed draw - vkt::Buffer indexed_draw_buffer(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - { - VkDrawIndexedIndirectCommand *indexed_draw_ptr = (VkDrawIndexedIndirectCommand *)indexed_draw_buffer.memory().map(); - indexed_draw_ptr->indexCount = 3; - indexed_draw_ptr->instanceCount = 1; - indexed_draw_ptr->firstIndex = 0; - indexed_draw_ptr->vertexOffset = 0; - indexed_draw_ptr->firstInstance = 0; - indexed_draw_buffer.memory().unmap(); - } + 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(*m_device, {draw_params}); VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); @@ -785,7 +764,7 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex32) { m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); - vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), indexed_draw_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); + vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); @@ -814,10 +793,10 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex16) { layout(location=0) in vec3 pos; - void main() { - gl_Position = vec4(pos, 1.0); + void main() { + gl_Position = vec4(pos, 1.0); } - )glsl"; + )glsl"; VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT); CreatePipelineHelper pipe(*this); @@ -832,18 +811,13 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex16) { pipe.CreateGraphicsPipeline(); - // Now with an offset and indexed draw - vkt::Buffer indexed_draw_buffer(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - { - VkDrawIndexedIndirectCommand *indexed_draw_ptr = (VkDrawIndexedIndirectCommand *)indexed_draw_buffer.memory().map(); - indexed_draw_ptr->indexCount = 3; - indexed_draw_ptr->instanceCount = 1; - indexed_draw_ptr->firstIndex = 0; - indexed_draw_ptr->vertexOffset = 0; - indexed_draw_ptr->firstInstance = 0; - indexed_draw_buffer.memory().unmap(); - } + 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(*m_device, {draw_params}); VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); @@ -859,7 +833,7 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex16) { m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 128"); m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); - vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), indexed_draw_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); + vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); @@ -890,10 +864,10 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex8) { layout(location=0) in vec3 pos; - void main() { - gl_Position = vec4(pos, 1.0); + void main() { + gl_Position = vec4(pos, 1.0); } - )glsl"; + )glsl"; VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT); CreatePipelineHelper pipe(*this); @@ -908,18 +882,13 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex8) { pipe.CreateGraphicsPipeline(); - // Now with an offset and indexed draw - vkt::Buffer indexed_draw_buffer(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - { - VkDrawIndexedIndirectCommand *indexed_draw_ptr = (VkDrawIndexedIndirectCommand *)indexed_draw_buffer.memory().map(); - indexed_draw_ptr->indexCount = 3; - indexed_draw_ptr->instanceCount = 1; - indexed_draw_ptr->firstIndex = 0; - indexed_draw_ptr->vertexOffset = 0; - indexed_draw_ptr->firstInstance = 0; - indexed_draw_buffer.memory().unmap(); - } + 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(*m_device, {draw_params}); VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); m_commandBuffer->begin(&begin_info); @@ -935,7 +904,7 @@ TEST_F(NegativeGpuAVIndirectBuffer, IndirectDrawBadVertexIndex8) { m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 128"); m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); - vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), indexed_draw_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); + vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), draw_params_buffer.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand)); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); @@ -962,10 +931,10 @@ TEST_F(NegativeGpuAVIndirectBuffer, DrawBadVertexIndex32) { layout(location=0) in vec3 pos; - void main() { - gl_Position = vec4(pos, 1.0); + void main() { + gl_Position = vec4(pos, 1.0); } - )glsl"; + )glsl"; VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT); CreatePipelineHelper pipe(*this); @@ -1015,6 +984,101 @@ TEST_F(NegativeGpuAVIndirectBuffer, DrawBadVertexIndex32) { m_errorMonitor->VerifyFound(); } +TEST_F(NegativeGpuAVIndirectBuffer, DrawInSecondaryCmdBufferBadVertexIndex32) { + TEST_DESCRIPTION("Validate illegal index buffer values - uint32_t index. Draw recorded in secondary command buffer."); + AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + RETURN_IF_SKIP(InitGpuAvFramework()); + + AddDisabledFeature(vkt::Feature::robustBufferAccess); + RETURN_IF_SKIP(InitState()); + InitRenderTarget(); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vku::InitStructHelper(); + vkt::PipelineLayout pipeline_layout(*m_device, pipelineLayoutCreateInfo); + + char const *vsSource = R"glsl( + #version 450 + + layout(location=0) in vec3 pos; + + void main() { + gl_Position = vec4(pos, 1.0); + } + )glsl"; + VkShaderObj vs(this, 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.gp_ci_.layout = pipeline_layout.handle(); + pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; + + pipe.CreateGraphicsPipeline(); + + vkt::Buffer index_buffer = vkt::IndexBuffer(*m_device, {0, 666, 42}); + vkt::Buffer vertex_buffer = vkt::VertexBuffer(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); + + std::vector secondary_cmd_buffers; + std::vector 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 = 3; + 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.handle()); + + secondary_cmd_buffer.begin(&secondary_begin_info); + vk::CmdBindPipeline(secondary_cmd_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + + VkDeviceSize vertex_buffer_offset = 0; + vk::CmdBindIndexBuffer(secondary_cmd_buffer.handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32); + vk::CmdBindVertexBuffers(secondary_cmd_buffer.handle(), 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); + + m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", + "index_buffer\\[1\\] \\(666\\) \\+ vertexOffset \\(0\\) = Vertex index 666"); + m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", + "index_buffer\\[2\\] \\(42\\) \\+ vertexOffset \\(0\\) = Vertex index 42"); + vk::CmdDrawIndexed(secondary_cmd_buffer.handle(), 3, 1, 0, 0, 0); + + // vertexOffset = 3 + m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", + "index_buffer\\[0\\] \\(0\\) \\+ vertexOffset \\(3\\) = Vertex index 3"); + m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", + "index_buffer\\[1\\] \\(666\\) \\+ vertexOffset \\(3\\) = Vertex index 669"); + m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexed-None-02721", + "index_buffer\\[2\\] \\(42\\) \\+ vertexOffset \\(3\\) = Vertex index 45"); + vk::CmdDrawIndexed(secondary_cmd_buffer.handle(), 3, 1, 0, 3, 0); + + secondary_cmd_buffer.end(); + } + + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); + m_commandBuffer->begin(&begin_info); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + + vk::CmdExecuteCommands(m_commandBuffer->handle(), size32(secondary_cmd_buffers_handles), secondary_cmd_buffers_handles.data()); + + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); + + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); + m_errorMonitor->VerifyFound(); +} + TEST_F(NegativeGpuAVIndirectBuffer, DrawBadVertexIndex16) { TEST_DESCRIPTION("Validate illegal index buffer values - uint16_t index"); AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); @@ -1032,10 +1096,10 @@ TEST_F(NegativeGpuAVIndirectBuffer, DrawBadVertexIndex16) { layout(location=0) in vec3 pos; - void main() { - gl_Position = vec4(pos, 1.0); + void main() { + gl_Position = vec4(pos, 1.0); } - )glsl"; + )glsl"; VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT); CreatePipelineHelper pipe(*this); @@ -1095,10 +1159,10 @@ TEST_F(NegativeGpuAVIndirectBuffer, DrawBadVertexIndex8) { layout(location=0) in vec3 pos; - void main() { - gl_Position = vec4(pos, 1.0); + void main() { + gl_Position = vec4(pos, 1.0); } - )glsl"; + )glsl"; VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT); CreatePipelineHelper pipe(*this);