A render to a texture is put into video memory only when something
touches it there (rend/rtt_watch.h): until then its pages are closed. The
frame dump for the reference renderer (REFSW_DUMP_DIR) writes video memory
with fwrite(), a system call, which fails on such a page instead of
faulting, and every frame after the first render to a texture came out
cut short ("not written"). Virtua Fighter 4's stages with reflections
render to a texture every frame, so none of their frames could be dumped.
rtt_watch_touch() puts what is waiting into video memory first, as the
state saver does.
ComputeFrame::Pack(), which makes the kernels' frame words from the
render context, was the Vulkan drawer's, built on its BaseDrawer for the
transform, the base scissor, the tile clip and the fragment constants.
It is now rend/tile/compute_frame.cpp, built in every configuration,
with a renderer giving only what is its own: its matrices made for the
frame (Begin()), its base scissor and its flat shading's colours. The
tile clip is ::GetTileClip() against that scissor and the fragment
constants are the formulas both raster renderers have, as they were.
VulkanComputeFrame is the Vulkan renderers' (and tile_dump's).
The words are the same: the new and the old Pack() compared word for word
on ten frames of five Jet Grind Radio states (tile_dump with both).
Every render to a texture was left to the raster renderer when Rendering
Method is Compute. Now the kernels draw it, with the same frame words as
a screen frame, into the very texture the per-pixel renderer would have
drawn it in:
- The texture is OITTextureDrawer's: the frame from its first pixel to
the pixel clip's last, in powers of two, times Render To Texture
Upscaling, taken from the texture cache the same way (the code that
takes it is now one function both use, ComputeBegin() and NewFrame()).
After the render it is locked in video memory and watched the same way
(rtt_read.h), so the texture cache, the copy to video memory when the
game first touches it, and what a later CPU write over the render does
(the texture is made again from video memory, as with the raster
renderer) are unchanged. Nothing is read back otherwise.
- It is drawn at one sample a pixel, as the per-pixel renderer draws
renders to a texture whatever SSAA is. With SSAA on, the kernels for one
sample are made at Init() as well; nothing is compiled while a game runs.
- The frame's words for such a render: only the pixel clip is drawn
(times the upscaling, as the raster renderer's scissor), the rest of
the texture is the clear colour as the raster renderer's render pass
leaves it, and the transform is the raster renderer's viewport's, that
many times larger.
- The bins are made at Init() for the largest texture rendered to there
can be (1024 x 1024 at 8x), a few words a coarse tile; each frame clears
only the part its own tiles use, so a screen frame clears what it did.
- The images rendered to are made with storage usage as well when the
compute renderer is on (the pool's, TexturePool::SetTargetStorage(), and
those the drawer makes outside it), so the kernels write them in place:
no copy. When the device cannot write that format from a compute shader
such renders still go to the raster renderer, counted under that reason.
- The texture leaves the walk in the layout textures are sampled in, made
ready for fragment and compute shaders and for the copy to video memory.
The log says how many of the frames drawn were renders to a texture.
tools/rend/tile_dump.cpp writes renders to a texture too (rtt_NNNNN.bin,
TILE_DUMP_RTT, TILE_DUMP_RTT_EVERY), packed as the renderer packs them at
the size of their texture, and tools/rend/tile_test.sh draws and compares
them with the reference like the screen's frames.
Each frame Rendering Method: Compute leaves to the raster renderer is now
counted with its reason, and logged at the end with the frames drawn and
how many of them were the GPU's TA decode's: renders to a texture, the
VMUs or crosshairs drawn over the picture, more render passes than the
kernels take, more textures than their slots, a frame too large for the
ring or the setup. So a run says how many frames fell back and why.
One of them goes: a frame that draws over part of the screen right after
the context was made again starts from the picture kept from the context
before, which can be of another size, and the raster renderer drew it.
The walk now starts such a frame from that picture filtered over the
screen (PVRC_FF_LAST_SCALED: textureLod at the pixel's centre with a
linear sampler, as the per-pixel renderer's quad samples it); the picture
before of the same size is still read texel for texel.
The setup also counts the triangles it clipped at the eye (PVRC_ST_CLIPPED,
read when the frame's slot comes round, as the other counts are), which
the log gives and tools/rend/tile_test compares with the reference's.
libswirl's refsw (skmp's reference software model of the PowerVR2 CORE,
BSD 3-clause) brought in under tools/rend/refsw as a checker: a frame of
this core's, as the TA parse leaves it, drawn the way the chip draws it -
32x32 tiles, 1/w interpolated by plane equation in 32-bit float and
compared as the chip compares it, a tag buffer shaded after the list,
modifier volumes through the stencil, translucency peeled a layer a pass
with equal depths ordered by submission. The rasterizer and the pixel
pipeline are libswirl's text; the changes to its files are listed in
tools/rend/refsw/README (the include of its frontend's header, a vertex
field's name, the renderer registration replaced by a factory, and one
correction: the modifier volumes' result applied only to objects whose
shadow bit is set, as the chip does).
refsw_frame.cpp walks the parse's lists per tile in the sequence libswirl's
refrend_base.cpp walked the chip's object lists, makes the textures with
this core's texture cache, and writes the picture. With pixels to probe
it prints every triangle covering them with its interpolated 1/w and the
tile buffers after each list; REFSW_GAPS prints the frame's closest depth
comparisons.
tile_dump.cpp writes the frame (REFSW_DUMP_DIR: the lists, the registers
and video memory, refsw_dump.h). tools/rend/refsw_test.sh builds the
programs, runs a game to a frame from a save state and draws it.
tile_ref.c draws a frame of the compute renderer's words sample by
sample in C89, with every translucent fragment sorted at once; tile_test
draws the same frames with the kernels on a Vulkan device (lavapipe
where it is installed) in test mode, at each count of samples and with
K of 1 and the device's, and compares the pictures bit for bit.
tile_dump.cpp writes the frames a game draws, through headless.c;
tile_test.sh puts it together.