- Font:getLines/Pass:text use temp memory for strings/vertices.
- Due to the recent morgue fix, resizing the atlas will now do a GPU
submit to flush the transfers before destroying the atlas.
- This GPU submit also rewinds the temp allocator, invalidating the
temp memory used for the lines/vertices, causing a use-after-free.
There are 2 changes here:
- Only flush transfers if the destroyed resource actually has pending
work (we're already tracking this w/ lastTransferRead/Write).
- Restore the allocator cursor after doing the submit.
Having to restore the allocator offset is kinda tricky/complicated,
which sucks. Other solutions might be:
- Avoid using temp memory in those Font methods. More generally, adopt
a rule where you can't use temp memory if it's possible that there
will be a submit while you're using the temp memory.
- Find some way to stop destroying the old font atlas during a resize?
- Don't rewind the temp allocator on every GPU submit. Instead only
rewind it at the end of a frame, or only when Lua does the submit.
We were conflating "parent struct of Sync pointer" and "object to be
refcounted", which isn't the case for texture views.
To fix it, add both pointers to the Access struct. This sucks because
it increases the size from 16 bytes to 24 bytes.
There might be other solutions like a "texture view mask" or having
buffers/textures store a pointer to their sync or something. But these
have some drawbacks as well. May revisit in future.
The morgue is a fixed-size queue for GPU resources that are waiting to
be destroyed. There's been an annoying issue with it for a while where
destroying too many objects at once will trigger a "Morgue overflow!"
error. Even innocuous projects that create more than 1024 textures will
see this during a normal quit.
One way to solve this problem is to make the queue unbounded instead of
bounded. However, this can hide problems and lead to more catastrophic
failure modes.
A better solution is to add "backpressure", where we avoid putting
things in the queue if it's full, or find some way to deal with them.
In this case it means finding a way to destroy stuff in the morgue when
it's full, to make space for more victims.
We weren't able to add backpressure reliably before, because command
buffers could have commands that reference the condemned resources.
This was mostly a problem for texture transfers -- if you create
thousands of textures in a loop, we'd have a giant command buffer with
commands to transfer pixels to the textures. If these textures were
destroyed before submitting anything, the morgue would fill up, and we
wouldn't have any way to clear space because there was still a pending
command buffer that needs to act on the textures!
A simple change is to flush all pending transfers whenever a buffer or
texture is destroyed. This lets us add backpressure to the morgue
because we can guarantee that there are no pending command buffers that
refer to an object in the morgue.
For backpressure, we try to destroy the oldest object in the morgue if
the GPU is done using it. If that doesn't work, we'll wait on the fence
for its tick and destroy it. This *should* always work, although in an
extreme case you could vkDeviceWaitIdle and clear out the entire morgue.
It should also be noted that in general command buffers need to be
flushed when destroying objects that they refer to. However, for our
particular usage patterns, we only need to flush state.stream when a
buffer or texture is destroyed. Pass objects already refcount their
buffers and textures and their commands are software command buffers, so
they don't require any special handling. Other objects like shaders,
pipelines, descriptor set layouts, etc. all survive until shutdown, so
those don't impact anything either.
There were numerous problems with the previous effort to add support for
linear views of sRGB storage textures. Here's another attempt:
- Images are always created with the linear version of their format.
- The default texture view uses the sRGB format if the parent is sRGB.
- Use ImageViewUsageCreateInfo to specify the usage for render/storage views.
- sRGB image views always have their storage bit forcibly cleared.
The storage view now behaves more like the existing renderView -- if we
detect that you couldn't use the default texture view for storage, we'll
create one that is guaranteed to be usable for storage bindings (by
clearing the sRGB flag on it).
Previously this would include multiple descriptors with the same
binding, which isn't allowed. Instead, just reuse the inter-stage
tracking/merging for intra-stage resources as well.
This allows them to be initialized/destroyed from multiple threads in
any order. Previously, the first thread to require a module had to be
the last thread to use the module, otherwise it would be destroyed too
early.
There are still a few issues. If the main thread doesn't require a
module, it won't pick up the conf.lua settings. Also graphics isn't
handling the shader cache writing properly. And I think this breaks the
headset-graphics refcounting. But these will be fixed in future
commits.
- Archive is now an object that has a refcount
- Archives are stored in linked list instead of array
- Not exposed to Lua yet, but could be in the future
- core/zip was merged into the filesystem module
- Mountpoints are handled centrally instead of per-archive
- Zip doesn't pre-hash with the mountpoint anymore
- mtime is truly only computed on request for zips
Mountpoints don't work properly yet.
- Cubemaps can have any layer count that is a multiple of 6.
- A cubemap with more than 6 layers will be a cubemap array image view.
- This isn't perfect because it conflates regular cubemaps with
6-layer cubemap arrays.
- Enable the vk feature, handle the spv feature, add getPixel helper.
- 'sample' now implies both sample and linear filtering (practically always
true for all formats lovr supports)
- 'render' now includes 'blend' for color formats (also practically
always true except for r32f on some old mobile GPUs)
- 'blit' now includes 'blitsrc'/'blitdst' because lovr doesn't support
blitting between textures with different formats
- 'atomic' is removed because lovr doesn't really support atomic images yet