Common/ObjectPool.c (C89) keeps objects of one class in chunks, the first
made at backend start: a freed object is pushed on a lock-free stack, an
allocation takes the stack whole (an exchange, so no ABA) and pushes the
rest back, or else takes the chunks' next slot. A pool destroyed with
objects still out is freed with the last of them. Classes take it with
OBJECT_POOL_MEMBERS / OBJECT_POOL_DEFINE: VKPipeline, VKShader,
VKTexture, VKFramebuffer and the vertex loaders, which are now their
own bucket list nodes. Vulkan's descriptor pool and cleanup lists get
their first room at boot.
Play allocations: 58 to 1 on the core's thread, 172 to 1 on the compile
workers (both a first use).
Nothing made a framebuffer with additional colour attachments, so they
go from AbstractFramebuffer, CreateFramebuffer and every backend, and
FramebufferState's additional_color_attachment_count (always 0) with
them: render passes, views, clears, RTVs and blending are for one
colour attachment, in fixed arrays rather than vectors.
Vulkan samplers are kept in an open-addressed table grown by doubling
and render passes in a fixed array, so looking one up never allocates.
Play allocations on the core's thread: 62 to 58.
ClearRegion and VKFramebuffer::SetAndClear list color, depth and the
additional color attachments (7 at most) in arrays on the stack, where
each built a vector at every clear. Allocations after boot over the
corpus fall from 6081 to 2720.
AbstractTexture::LendLoad lends the upload stream's memory for a level,
and CommitLoad uploads it: Vulkan for any rows, Direct3D 12 for rows at
its pitch alignment. The texture cache decodes textures and XFBs into
it; it decodes into its own buffer and Loads that where the backend
lends none, or when the arbitrary mipmap detection reads the levels
back. The detector keeps its levels in a fixed array.
A staging texture says whether its upload memory stays mapped, and
StagingTransferDone tells without waiting whether the GPU is done with
its last copy, from the Vulkan fence counter, the Direct3D 12 fence
value or the GL sync object. Direct3D 12 upload heaps stay mapped
through their copies.
VKHeap.c takes large blocks from the driver and hands out offsets in
them: the lowest free span that fits, spans kept sorted so a free is a
binary search and a merge. The handle is a small struct kept by value,
so nothing is allocated per allocation. Host-visible blocks are mapped
once and stay mapped; stream buffers and staging buffers write straight
into the memory the GPU reads. Buffers and linear images keep to blocks
of their own, apart from optimal images. What the driver requires or
prefers dedicated, and anything of half a block or more, gets memory of
its own sized to fit. Host blocks are 16 MiB, device blocks 64 MiB, and
neither more than an eighth of its driver heap; one empty block of each
kind is kept and the rest go back to the driver.
The Vulkan Memory Allocator is gone, and with it the memory budget
extension only it used.
A render target of one layer in a 2D array, which is what an XFB copy
is, gets a second view at creation, 2D, of that layer, and keeps it for
its life. Handing an XFB copy to the frontend in place uses it, so
presenting creates and destroys nothing: before, every new picture made
a view and queued the last one for destruction.
This very much isn't a build configuration that we're going to ship,
but I want to be able to tell people that they can build it on their
own if they really want to see how terribly it performs :)
Just like before, you'll need to edit two lines in app/build.gradle to
define ENABLE_GENERIC=ON and actually enable armeabi-v7a if you want an
armeabi-v7a build. This commit just fixes some compilations errors that
crop up if you do so.
SPDX standardizes how source code conveys its copyright and licensing
information. See https://spdx.github.io/spdx-spec/1-rationale/ . SPDX
tags are adopted in many large projects, including things like the Linux
kernel.