-
Notifications
You must be signed in to change notification settings - Fork 407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gpu: Check index buffer contents in pre-draw validation #8489
base: main
Are you sure you want to change the base?
gpu: Check index buffer contents in pre-draw validation #8489
Conversation
CI Vulkan-ValidationLayers build queued with queue ID 248617. |
CI Vulkan-ValidationLayers build # 17366 running. |
b92946b
to
2a98b80
Compare
CI Vulkan-ValidationLayers build queued with queue ID 248652. |
CI Vulkan-ValidationLayers build # 17368 running. |
CI Vulkan-ValidationLayers build # 17368 failed. |
layers/gpu/core/gpuav_record.cpp
Outdated
} | ||
|
||
bufval::CountBuffer(*this, *cb_state, record_obj.location, buffer, offset, sizeof(VkDrawIndirectCommand), | ||
"VkDrawIndirectCommand", stride, countBuffer, countBufferOffset, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"VkDrawIndirectCommand", stride, countBuffer, countBufferOffset, | |
vvl::Struct::VkDrawIndirectCommand, stride, countBuffer, countBufferOffset, |
layers/gpu/shaders/cmd_validation/draw_indexed_indirect_index_buffer.vert
Show resolved
Hide resolved
m_errorMonitor->VerifyFound(); | ||
} | ||
|
||
#if 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use DISABLED_
with a comment on top
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way to measure the perf difference of the new multi-shader approach vs what was happening before?
// Flag values for all pre draw types | ||
|
||
// Set if the count buffer is bound | ||
const uint kPreDrawValidationFlags_CountBuffer = (1 << 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these flags still used now that you split up the shaders even further?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope they were not, got rid of them!
uint get_vertex_index(uint i) { | ||
if (pc.index_width == 32) { | ||
return index_buffer[i]; | ||
} else if (pc.index_width == 16) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation in all of these shaders is inconsistent. Looks like a mix of tabs and spaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes my editor was not correctly configured... will go by hand and change that
@@ -213,8 +213,18 @@ target_sources(vvl PRIVATE | |||
${API_TYPE}/generated/cmd_validation_copy_buffer_to_image_comp.cpp | |||
${API_TYPE}/generated/cmd_validation_dispatch_comp.h | |||
${API_TYPE}/generated/cmd_validation_dispatch_comp.cpp | |||
${API_TYPE}/generated/cmd_validation_draw_vert.h | |||
${API_TYPE}/generated/cmd_validation_draw_vert.cpp | |||
${API_TYPE}/generated/cmd_validation_count_buffer_vert.h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
${API_TYPE}/generated/cmd_validation_count_buffer_vert.h | |
${API_TYPE}/generated/cmd_validation_count_buffer_vert.h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arno-lunarg still need to fix this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a LOT going on here, overall really really happy how well this turned out, it is all well localized to gpuav_draw.cpp
(thanks to our work with the refactor for the last months!)
Some things to cleanup, but hopefully we can get this in soon and push from here as a new basepoint, this PR is really pushing things in a good direction for GPU-AV!
layers/gpu/core/gpuav_record.cpp
Outdated
@@ -507,7 +563,18 @@ void Validator::PreCallRecordCmdDrawMeshTasksIndirectEXT(VkCommandBuffer command | |||
InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); | |||
return; | |||
} | |||
InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, drawCount, VK_NULL_HANDLE, 0, stride); | |||
|
|||
bufval::DrawMeshIndirectVuids vuids; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setting these every PreCallRecordCmdDrawMeshTasksIndirectEXT
seems like a waste, but honestly also not highly motivated to fix this now, so maybe just a // TODO
for now to move this to something like the vuid_maps.h
files we have in the future
const uint32_t vertex_index = error_record[kPreActionParamOffset_3]; | ||
const uint32_t index_buffer_value = static_cast<uint32_t>(int32_t(vertex_index) - vertex_offset); | ||
|
||
gpuav.LogError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just want to leave a 💯 for these error messages, this is more of the quality I wish all messages were like, an extra 💯 for making the code here also readable!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for big printf we should try to pack parameters like this more often, it makes figuring the mapping a bit easier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
example number 1345 of why we need log message streams
|
||
struct CountBufferPushData { | ||
uint draw_cmds_byte_stride; | ||
uint64_t draw_buffer_offset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will get bad if they don't support shaderInt64
My advise is leave this, and look up if (!supported_features.shaderInt64) {
and just do that check and turn off validate_indirect_draws_buffers
if they don't support it
I am more inclined to just disable GPU-AV features then do crazy uvec2
hacks here in the short term
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added logic in Validator::PreCallRecordCreateDevice
to force feature on if available
I probably can come up with some small stress test to figure this out. And will also have a look at Doom Eternal and the lightweight VK sample |
2a98b80
to
a745204
Compare
CI Vulkan-ValidationLayers build queued with queue ID 249357. |
a745204
to
ec752ae
Compare
CI Vulkan-ValidationLayers build queued with queue ID 254123. |
ec752ae
to
3879aec
Compare
CI Vulkan-ValidationLayers build queued with queue ID 254136. |
CI Vulkan-ValidationLayers build # 17437 running. |
CI Vulkan-ValidationLayers build # 17437 passed. |
Running lightweight VK showed problems in handling of dynamic states. Since we bind our own pipelines, we have to restore them. I have yet to add testing in VVL, but at least lightweight VK is cleared now. I pushed my new changes to a separate commit. So @jeremyg-lunarg for some perf stats:
|
That's disturbing! But yeah since you've fixed it not worth figuring out what was happening in the old code. |
char const *vsSource = R"glsl( | ||
#version 450 | ||
|
||
layout(location=0) in vec3 pos; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually these are all the same shader. can it be factored out to a single string constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also want that, but then not having shader code inline makes it not obvious what location=0
is, and thus how to properly fill the corresponding Vulkan vertex binding description. And having a helper a function that would basically spit out a valid graphics pipeline based on this single shader seems overkill?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could always name is something that makes it obvious, like kVertexShaderVec3Location0
. But not a big deal either way
3879aec
to
217afab
Compare
CI Vulkan-ValidationLayers build queued with queue ID 254572. |
CI Vulkan-ValidationLayers build # 17445 running. |
CI Vulkan-ValidationLayers build # 17445 failed. |
217afab
to
af79e52
Compare
CI Vulkan-ValidationLayers build queued with queue ID 254858. |
CI Vulkan-ValidationLayers build # 17449 running. |
af79e52
to
95a8be8
Compare
CI Vulkan-ValidationLayers build queued with queue ID 254886. |
CI Vulkan-ValidationLayers build # 17451 running. |
Fixes KhronosGroup#2492 Completely rework gpuav_draw, to make it easier to add validation, and debug existing one. When adding validation for some VkBuffer, the 2 more importants parts are 1) creating the validation shader and 2) have an informative error message. gpuav_draw.cpp has been redesigned around that idea. Each shader is in charge of its small validation, no uber shader trying to cater to all needs. Doing that ends up being a mess, with the need to correctly pipe data to the validation shader. Validation shaders are now more fine grained. The C++ has been reworked around some template to streamline the process of adding validation. The general idea is the following: 1) Declase a new "shader" struct representing validation shader bindings and push contants 2) fill that struct 3) bind this struct and the validation pipeline 4) dispatch the appropriate number of draws About 4): we used to dispatch one draw, and do for loop in the shader to scan buffer elements. GPU are not good at that, instead a proper amount of draws should be dispatched, each in charge of doing it's small validation logic.
95a8be8
to
e566158
Compare
CI Vulkan-ValidationLayers build queued with queue ID 254915. |
CI Vulkan-ValidationLayers build # 17452 running. |
CI Vulkan-ValidationLayers build # 17452 passed. |
DispatchGetPhysicalDeviceFeatures(physicalDevice, &physical_device_features); | ||
if (physical_device_features.shaderInt64) { | ||
if (auto enabled_features = const_cast<VkPhysicalDeviceFeatures*>(modified_create_info->pEnabledFeatures)) { | ||
enabled_features->shaderInt64 = VK_TRUE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will mark as a TODO (For me) after, but we need to cleanup how we do this, like we are not warning users if we are setting things to true under them
DispatchCmdSetFrontFace(VkHandle(), dynamic_state_value.front_face); | ||
} | ||
} break; | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are a LOT of dynamic states missing here, like VK_DYNAMIC_STATE_STENCIL_OP
@@ -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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so CommandBuffer
is already by far the largest memory object we have, this is going to add a lot of memory overhead
I knowing we are still missing 50+ states for the RestoreDynamicState and my worry is we are going to really bloat this up
we either should
- Move these to the GPU-AV
CommandBuffer
state object - We just serialize the
vkCmdSet
calls and replay them back
... please note there is a LOT of nasty dynamic state you have not touched yet
} | ||
|
||
void RestorablePipelineState::Restore() const { | ||
if (rendering_info_) { | ||
DispatchCmdEndRendering(cb_state_.VkHandle()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
discussing with driver people
- This will trash runtime speed on some drivers if we are going
vkCmdBeginRendering();
vkCmdDrawIndexed();
vkCmdDrawIndexed();
vkCmdDrawIndexed();
vkCmdDrawIndexed();
vkCmdDrawIndexed();
vkCmdEndRendering():
too
vkCmdBeginRendering();
vkCmdDrawIndexed();
vkCmdEndRendering():
vkCmdBeginRendering();
vkCmdDrawIndexed();
vkCmdEndRendering():
vkCmdBeginRendering();
vkCmdDrawIndexed();
vkCmdEndRendering():
vkCmdBeginRendering();
vkCmdDrawIndexed();
vkCmdEndRendering():
vkCmdBeginRendering();
vkCmdDrawIndexed();
vkCmdEndRendering():
- There might be dependency (via
VK_KHR_dynamic_rendering_local_read
) that are going to just blow up if we don't chain it for them
Fixes #2492
Completely rework gpuav_draw, to make it easier to add validation, and debug existing one.
When adding validation for some VkBuffer, the 2 more importants parts are 1) creating the validation shader and 2) have an informative error message. gpuav_draw.cpp has been redesigned around that idea. Each shader is in charge of its small validation, no uber shader trying to cater to all needs. Doing that ends up being a mess, with the need to correctly pipe data to the validation shader.
Validation shaders are now more fine grained.
The C++ has been reworked around some template to streamline the process of adding validation. The general idea is the following: 1) Declase a new "shader" struct representing validation shader bindings and push contants
2) fill that struct
3) bind this struct and the validation pipeline
4) dispatch the appropriate number of draws
About 4): we used to dispatch one draw, and do for loop in the shader to scan buffer elements. GPU are not good at that, instead a proper amount of draws should be dispatched, each in charge of doing it's small validation logic.
Example of out of bounds Vertex Index error message:
Out of bounds index:
Still missing (planned for followup PRs):
DestroyRenderPassMappedResources