* Historically we always expected a live resource, but with descriptors that can
be stale we can have a lot of queries where it's fine to just get NULL back if
the resource doesn't exist.
* The crash handler gets destroyed and recreated when we need to change creation
parameters, and this races against anything else trying to use it to register
or unregister memory regions.
* In partcular when initialising the replay we recreated the crash handler right
after kicking off the GPU enumeration.
* We add a read/write lock so there's no significant added contention on most
paths (even though it's not really high traffic in any case) to prevent this
kind of problem in future.
* In principle descriptors should be updated less often than they are
referenced, so we used to cache tracking of them at update time to improve the
speed that references can be processed at submit time during capture.
* Some applications though update a *lot* of descriptors *very* often,
effectively writing all their descriptors for a frame every frame. That means
that this background tracking is wasteful and has a big performance impact, so
instead it's a better balance to do more work at submit time during capture.
* If chunks come from an allocator they can't be safely deleted because the
allocator may have been reset and recorded over where these chunks were with
other data. Fortunately we don't need to do anything to delete them, so
storing the allocator status up front is sufficient.
* While active capturing we might do significant work to flush coherent mapped
memory regions and prepare initial contents for postponed resources that are
about to be write-referenced. We need to do that before submitting the actual
work to the queue or else the contents may be corrupted.
* Resources which aren't referenced in the frame don't need initial states
unless we have 'Ref All Resources' enabled. These initial states can be
stripped on replay as they aren't needed.
* We also renamed the WrittenRecords to more explicitly list that this is the
list of resources needing initial contents, whether because they were dirty
(and so had initial contents) or because they were written mid-frame and so
need to be reset.
* We only care about tracking two things:
1. Resources that have been written very recently. These should not be
postponed as there's a high chance they'll be written mid-frame and so we'd
need their initial contents.
2. Resources that have their last non-complete-write reference was a while ago
However in the second case we can acceptably ignore any resources that haven't
been written recently either, since if the resource hasn't been written and
also hasn't been complete-written then it hasn't been used at all.
* So when updating the non-complete-write time we only do this if the resource
has had a write reference, and intermittently we remove any resources that
haven't had a write at all.
* Postponed resources will be exactly the same set, because we treat a resource
as postponable if we have no write time for it at all so it's fine to remove
old resources from the list. Fewer resources will be skipped, as we now treat
resources that have no known age as non-skippable. However in the majority of
these cases we expect either for the resource to not be used at all (thus the
postpone will never be forced to prepare and we won't serialise anything), or
else if it is used the chances are high it will be used read-only so the
postpone will still be enough.
* This means we don't have to iterate the whole bindrefs array every time we
want to propagate references in the background, but we can submit them in
batch.
* Almost all dirty-able resources (memory and images) become dirty almost
immediately, so spending time tracking dirty state is wasted. Instead we treat
these resources as dirty at creation and rely on the postponing logic to avoid
preparing initial states for newly created resources that are not used in the
frame.
* This may cause more 'last-minute' postponed prepares for newly created
resources, which would previously.
* If we return back (accurate) replaced IDs in current pipeline state, the UI
won't recognise them since the list of resources is cached and fixed at load
time.
* The replaced ID is still present in the shader reflection info as we return
the replaced shader's reflection and not the original's.
* We also change how we replace a programshader (glCreateShaderProgramv) on GL.
Instead of creating a program and a shader - resulting in two objects
replacing one - we instead replace the shader that got built with a program.
We can do this safely since we know the shader won't be used as an actual real
shader (since it was a program in the original capture too).
* Using a 32-bit integer, signed, gives only 2 billion chunks before it wraps.
With Vulkan/D3D12 creating new chunks even while in the background for
recording commands this is feasible to hit.
`ImageState` tracks the state of images and their subresources.
This functionality was previously split between the `ImageLayouts` and
`ImgRefs` classes.
Change-Id: I3242417dacf73fe07765f9bcfd449599e373e10d
This represents a (sub)resource for which no usage info is available.
It should be conservatively assumed that such a resource needs to be
re-initialized before each replay (and this behaviour is reflected in
`InitReq()`).
Change-Id: I12235a6cb1c4b2e3e21bed8834653ec6a3aea009
* Mostly moving includes from common headers to cpp where possible, and removing
includes of the whole thing where only enums or rdcstr etc are needed.
* If the write was recorded only to the frame, our background tracking may no
longer be up to date so if the resource isn't dirty already it should be
marked dirty so that we fetch its state properly on any subsequent captures.
This is most relevant for GL where many objects have mutable state which may
only be recorded mid-frame.
This allows finer control of the initialization/reset behaviour of
resources based on their ref type.
Currently, these policies only apply to the initialization/reseting of
VkDeviceMemory and VkImage resources.
Change-Id: Ib647cbaf99b650e8da40d07944400ace7dde504d
`WriteBeforeRead` is used to signify that a resource is partially
written, and then later read. For the purpose of correct replay,
`WriteBeforeRead` can be treated as `Read`--the resource needs to be
initialized once (so that the non-overwritten data is correct), but does
not need to be reset for later replays (since performing the same write
again will not change the data).
However, it is useful to track this state separately from `Read`,
because the user may inspect the resource at a point in time before the
write, and it might be confusing to see the result of the future write
(which would be visible if `WriteBeforeRead` was treated as `Read`).
Change-Id: I7df58bacb4444f7e8d7e26a5532a55b0ff8f128d
Previously, the ref type of the a VkDeviceMemory or VkImage resource
was calculated as the max of the ref types of the subresources. This
reliance on the ordering of the `FrameRefType` enum values is fragile--
in particular, this makes it more difficult to add new `FrameRefType`
alternatives.
Now, the ref type of composite resources are calculated using
`ComposeFrameRefsDisjoint` instead of `max`.
Change-Id: Id5db68b6756555cdc6b068d28f1b72cb827f3d1e
* Now that the dirty list is only read once at the start of the frame we can
mark resources dirty mid-frame freely and don't have to defer that. The
internal resource manager locking prevents us from adding to the list while it
is being modified.
* Instead of passing the resource handle itself to GetSize_InitialState or
Serialise_InitialState, we pass the Id, ResourceRecord, and prepared initial
contents. All of these can survive past the destruction of the resource.
* Removes the need for AllowDeletedResource_InitialState() - it's always allowed
now.
* Need_InitialStateChunk is also refactored but it's only used on D3D11
currently and potentially will be removed in future.
* This was used for two things:
- UAVs on D3D11, which we can just mark dirty at creation as we do
with things on D3D12/Vulkan where we know we'll always want initial
states.
- Texture views/Texture buffers on GL, where we check if the texture
was referenced and force initial states for the underlying data
store. This requires a bit more work but can still be achieved by a
GL-specific force-inclusion pass on the frame references.
* The problem with trying to keep the list of dirty resources identical at the
start and the end of the capture is that resources being deleted or dirtied
mid-frame causes problems. For the latter we have 'pending dirty' ugliness,
for the former we weren't properly handling it in all cases. Instead just
prepare initial contents from dirty resources, then use the list of resources
that had initial contents prepared to determine which should be saved.
* This means resources freed mid frame are fine, as long as we hold onto their
resource records and initial contents which we do. It also means the pending
dirty handling can be removed and we can just dirty resources as soon as we
want - it will be ignored mid-frame and apply to subsequent frames.
Added a special chunk flag indicating that chunk size is a 64 bit value.
This allows to handle larger chunks (which heppens quite rarely) while
still maintaining backward compatibility with the majority of traces.
Bumped RDC file version of 0x101 (1.1) to make sure older version cannot
read the new file format.