-
Notifications
You must be signed in to change notification settings - Fork 31
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
implemented indirect dispatch #66
Conversation
implemented indirect dispatch
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.
Need a unit test for new api:
gapi_test_common.h
is a template for api-tests.
resourcestate_test.cpp
is also important for sync testing.
Currently there is api-tests for indirect, so it's fine to skip those, but sync test is must-have, given how complex resource tracking is here.
|
||
curUniforms->ssboBarriers(resState, PipelineStage::S_Compute); | ||
// block future writers | ||
resState.onUavUsage(ind.nonUniqId, NonUniqResId::I_None, PipelineStage::S_Compute); |
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 should not be enough, for vulkan.
Basically you need a RaW barrier [WR] -> Indirect
, where WR - any stage that might been writing into this buffer. And then you need to mark this buffer as in read-state (S_Compute
mean the shader, not indirect command).
I'm assuming you looked into mesh-shader code, as example. Draw-calls are a bit hacky today, as they assume full barrier between compute and graphics, so no need to emit RaW.
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.
Do you mean that there might be the case that after indirect dispatch
resState.onUavUsage(NonUniqResId::I_None, %indirectBufferId%, %anyStage%) won't be called before any write access to the indirect buffer?
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 mean, resState
wont be enough today to produce strong enough barrier.
Code that you added, resState.onUavUsage(ind.nonUniqId, NonUniqResId::I_None, PipelineStage::S_Compute)
will mark buffer as 'read', for compute stage. If you have had another compute job before that wrote to indirect-buffer, then it wall cause only CS -> CS
barrier, but you need a stronger one: CS -> Indirect
.
For vulkan only correct solution, would be to introduce indirect as a stage, such as PipelineStage::S_Indirect
.
For DX, unfortunately same idea wont work at all, as it requires precise tracking of indirect-buffers, and has to use solution similar to one used for render-targets.
This is why CS-indirect was long delayed :)
-added tests for indirect barriers -added explicit state transition to and from indirect on dx12 -added indirect pipeline stage in ResourceState for placing stronger barriers on vulkan when using indirect
redundant 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.
Given how problematic DX12 is, should we merge PR without DX support (just throw exception in dispacthIndirect)?
This will unblock you on MLAA work, and in mean time I'll take care of DX12.
PS
[x] eb74d55
It was my bad - master is fixed now.
resState.onUavUsage(ind.nonUniqId, NonUniqResId::I_None, PipelineStage::S_Indirect); | ||
resState.flush(*this); | ||
|
||
issueExplicitCommonToIndirectStateTransition(ind.impl.get()); |
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 2 issues with this code:
- you do both explicit synchronization and implicit (via
onUavUsage
) - resource barrier is quite expensive, and calling it per-draw is not a good call
curUniforms->ssboBarriers(resState, PipelineStage::S_Compute); | ||
// block future writers | ||
resState.onUavUsage(ind.nonUniqId, NonUniqResId::I_None, PipelineStage::S_Indirect); | ||
resState.flush(*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.
What barrier will be emitted, if buffer is in used by both shader and indirect argument?
Should be SRC -> CS|indirect
, plus buffer has to be in read-state.
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.
Created test that simulates this situation:
barrier {UavReadComp | UavWriteComp -> UavReadComp | UavWriteComp | Indirect}
Propably stupid question :) but does read-state here refer to the condition that previous memory accesses for the buffer are available and visible for reading (i.e. that required barrier exists)? My first thought was about some internal state in the engine but couldn't find it.
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 mean ResourceState::uavRead
. Need to make sure that subsequent command are aware that indirect-buffer is in use.
What I'm worry about, that resState.flush
might reset tracking preemptively.
Basically in scenario
dispath( write to buf )
--- barrier {UavReadComp | UavWriteComp -> UavReadComp | UavWriteComp | Indirect}
dispathIndirect(buf)
--- should be execution barrier indirect -> CS
dispath( write to buf )
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.
added subsequent write access to the test, works fine:
barrier {TransferSrc | UavReadComp | UavReadGr | RtAsRead | Indirect -> UavWriteComp}
barrier {UavReadComp | UavWriteComp -> UavReadComp | UavWriteComp | Indirect}
barrier {UavReadComp | Indirect -> UavWriteComp}
Despite clearing uavSrcBarrier
and uavDstBarrier
in flush()
, there is a dependency on previous reads in uavRead
which was written in the end of onUavUsage(read, none, compute | indirect)
calls. uavRead
and uavWrite
are cleared only for dependencies that were added to uavSrcBarrier
and uavDstBarrier
-added notImplemeted runtime exception in indirectDispatch on dx12 -added indirect resource access in barrier test output -adeed test for a situation when a buffer is binded as a UAV and Indirect simultaneously
@@ -360,6 +360,11 @@ void MtCommandBuffer::dispatch(size_t x, size_t y, size_t z) { | |||
encComp->dispatchThreadgroups(MTL::Size(x,y,z), localSize); | |||
} | |||
|
|||
void MtCommandBuffer::dispatchIndirect(const AbstractGraphicsApi::Buffer& indirect, size_t offset) { | |||
auto& ind = reinterpret_cast<const MtBuffer&>(indirect); | |||
encDraw->dispatchThreadgroups(ind.impl.get(), offset, localSize); |
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.
encComp
Merged, thanks! |
implemented indirect dispatch