-
Notifications
You must be signed in to change notification settings - Fork 136
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
Indirect Drawcall args #356
Comments
Normally I think you would just use a dedicated buffer and pass an offset of 0, unless you have a single buffer containing multiple sets of arguments or are tacking the arguments at the end of another buffer. Definitely start with the simple case using offset 0 and get that working before adding more complexity though.
Ok, I see you are passing in several sets of draw calls in the one buffer, so you would need an offset for the 2nd (offset = number of arguments * sizeof(UINT) = 20) and 3rd (offset = 30) draw calls (or split this into several buffers). Normally if you are using indirect draw calls you would be writing these values from a compute shader on the GPU though - are these just initial values / for testing / to get the buffer the size you want (which you could do with format= and array= instead)? You haven't specified the format= of the data in the buffer - that will prevent this from being assigned as a UAV to the computer shader as that needs to be typed (or structured). Passing the format inline with the initial data as you have done is not quite the same thing (it's kind of a hack to work around cases like structured buffers where there may be multiple formats in the same buffer, or otherwise where you want to pass raw data in a different format to the buffer format for whatever reason). Something like this: [ResourceIndirectArgs]
type = Buffer
format = R32_UINT
array = 5 or if you do want initial data you can omit array= since that is calculated from the length of the initial data: [ResourceIndirectArgsWithInitialData]
type = Buffer
format = R32_UINT
data = 30 1 0 0 0
If you're just dumping the one you created you can refer to it by name, e.g.
You would use that if you were dumping an indirect draw call argument buffer that the game had created, e.g. to dump this in DOA6: [ShaderOverrideIndirect]
hash = fb9cfb6310b8de1f
dump = this Note that the .txt version of the buffer will probably try to decode the data as floats, which will be wrong so it may be better to examine the .buf version with a hex editor.
Only resources created by the game should be hashed at the moment. (There have been some edge cases where a resource created by 3DMigoto could inadvertently get a hash under some circumstances, but that has been a bug or side-effect of certain hooking scenarios / interactions with 3rd party libraries and not something that should be relied upon. There is some debate that perhaps we should intentionally hash our own resources, but since hashes are not guaranteed to be unique I think it's probably better to refer to them by resource name if possible and save hashes for matching game resources).
Hmm, that shouldn't have crashed - may need to dig into that.
If you get an incomplete log like that you can enable unbuffered=1 under [Logging], though this will make everything run extremely slowly. If it's a game that allows a debugger to be attached then doing so will be very useful, or it's pretty common for games to write crash dumps somewhere that we can potentially use (but I don't think we kept 3DMigoto's pdb files for released builds, so it would need to be a fresh build from source). Complete example with all the above, tested in DOA6: ; This shader is used e.g. in the pirate ship level for the coins in the hold
[ShaderOverrideIndirectParticles]
hash = fb9cfb6310b8de1f
; Demo dumping indirect argument buffer from the game with Frame Analysis:
dump = this
; Disable original draw call:
handling = skip
; Zeroing our custom indirect buffer first (for demo only):
clear = ResourceIndirectArgs
; Dump out our buffer to confirm it is zeroed:
dump = ResourceIndirectArgs
; Run a compute shader to write to the buffer:
run = CustomShaderSetupIndirectArgs
; Dump it again to verify that the compute shader has written the values we expect:
dump = ResourceIndirectArgs
; Our injected draw call using the arguments written by the compute shader:
DrawIndexedInstancedIndirect = ResourceIndirectArgs, 0
[ResourceIndirectArgs]
type = Buffer
; DrawIndexedInstanced all arguments are UINT or INT:
format = R32_UINT
; DrawIndexedInstanced takes 5 arguments:
array = 5
[ResourceIndirectArgsAlternateDemo]
type = Buffer
; This demo sets the initial data in the buffer rather than using a compute
; shader. Still need format= here otherwise there will be issues binding it as
; a UAV, but this time array= is automatically determined from the initial
; data. Note that passing the format inline in the data= is not the same as
; setting the resource format.
format = R32_UINT
data = 30 1 0 0 0
[CustomShaderSetupIndirectArgs]
cs = test.hlsl
cs-u0 = ResourceIndirectArgs
dispatch = 1,1,1
cs-u0 = null test.hlsl: Texture1D<float4> IniParams : register(t120);
RWBuffer<uint> indirect_args_buffer : register(u0);
[numthreads(1, 1, 1)]
void main(uint3 tid: SV_DispatchThreadID)
{
indirect_args_buffer[0] = 30; // IndexCountPerInstance
indirect_args_buffer[1] = 1; // InstanceCount
indirect_args_buffer[2] = 0; // StartIndexLocation
indirect_args_buffer[3] = 0; // BaseVertexLocation
indirect_args_buffer[4] = 0; // StartInstanceLocation
} |
Thanks for the in-depth breakdown. When I said it was hashed, I was referring to the one created by the game, but it seemed like there wasn't an obvious way to
These were for testing, I knew I could do it with format, but then I saw the I can also just dump them from the shader context using I've just finished with some follow-up tests, and it seems like using [ShaderOverride_HasIndirect]
hash = 5039c33fa941355c
; safe and functional
this = this
checktextureoverride = this
[TextureOverride_IndirectBuffer]
hash = 5c38bf06
; crashes
this = this I had one last idea as a test case, and in a surprising twist, even this failed. [ShaderOverride_HasIndirect]
hash = 5039c33fa941355c
if draw_type == 6
handling = skip
checktextureoverride = this
endif
[TextureOverride_IndirectBuffer]
hash = 5c38bf06
x101 = 1
drawindexedinstancedindirect = this, indirect_offset There isn't any issue entering the block mind you. I used an There probably isn't any advantage to using a Thanks for your awesome responses as always @DarkStarSword. I'm satisfied with my investigation. If I had to make a recommendation for resolving this behavior, it would either be to patch it so it is functional, or just warn instead. I honestly don't know which solution would take less effort, usually I would say warning is easier, but I think it might just need some minor adjustments to be able to function properly as well. Likely less than emitting a warning. But it's also an non-issue. It's not something that will be used anyways. Feel free to close if applicable. |
I have a idea and tested,it may help more people so i post it here ,hope you don't mind, if i miss something or wrong please correct my comment, thanks. I tested in game MechaBreak and implemented a way to dump the DrawIndexedInstancedIndirect's pBufferArgs in 3DMigoto source code, by modify and add a new method same usage as dump_on_unmap:
then call it on FrameAnalysisContext::DrawIndexedInstancedIndirect this will get the pBufferForArgs buffer easily and elegant, and without need to write everysingle possible Vertex Shader that related with the call, in MechaBreak there is over 5 different VS Hash but do the same thing, ShaderOverride make things complex so i make this. by the way, if you have implemented dump_on_map feature in your 3DMigoto fork, you can also call FrameAnalysisContext::Map in FrameAnalysisContext::DrawIndexedInstancedIndirect to get the same result as FrameAnalysisAfterDrawIndexedInstancedIndirect, may save a new method by reuse dump_on_map method. |
I've been experimenting with 3dmigoto's extended use cases, I created this block to get a better understanding of replacing less common cases after we ran into some things using Indirect draws, I wanted to get a more formal understanding.
I learned that Indirect calls use a buffer to pass their draw parameters, which is pretty powerful, because you can generate them. I was able to successfully use drawindexedinstancedindirect in 3dm, but I won't lie, the offset did give me a bit of trouble when it wasn't using the
Stride
property of the resource directly.https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-drawindexedinstancedindirect
Do you know if it's even possible to dump the
Indirect Args
buffers used in the Indirect draw calls? The only place I can find where we can even access the originals is with thethis
keyword during an indirect draw instruction. I believe they are hashed, they are referenced in the dumps. I thought maybe something akin to this block, but I don't imagine it would do what I want.Here is a line from the dump, so maybe I should find a hash I can dump.
000114 DrawIndexedInstancedIndirect(pBufferForArgs:0x000001B3D58C44B0, AlignedByteOffsetForArgs:420) hash=5c38bf06
Edit: dumping
this
from the shader did somehow work, the second example didn't work, likely because there is nochecktextureoverride
. I don't think 3dmigoto has a resource name for it.I could try the shotgun approach and just list
ib, vb0, vb1, ... vb-t0 etc
but I don't think that would work.I tried going even further down, but dumping on these conditions crashed my game.
Here is a comparison of the log.txt, I think something bad must have happened.

The text was updated successfully, but these errors were encountered: