Vulkan, OpenGL: modifier volumes and sorted indices from where they are parsed

The parse's arena has a part for each list the card draws from: the
vertices, the indices (with the sorted passes' room after them), and the
modifier volumes' triangles and those cut (rend/modvol_clip.h); a frame's
lists are moved into a slice together (parse_arena_attach()). The volumes'
triangles a frame draws are drawn from there with Vulkan and OpenGL, not
copied into the main buffer or uploaded each frame. With OpenGL the
per-triangle sorted passes' indices are written after the frame's, in its
index buffer, not uploaded to a buffer of their own; the per-pixel
renderer's volume array is set again when its buffer changes.

The heavy disc has a shadow volume a billion pixels off the screen,
first in its list, over a polygon that takes shadows: the volumes' cut
triangles, and those after it, drawn from their part (vk_parse_arena.sh,
gl_parse_arena.sh), which also take the disc with volumes of each cull
mode now.
This commit is contained in:
libretroadmin committed 2026-11-02 16:01:46 +01:00
1 parent 5035a1e711
commit bc87a9a59d
22 files changed
+480 -320

No files matched your search

+27 -1
View File
@@ -3,6 +3,7 @@
#include "pvr_regs.h"
#include "helper_classes.h"
#include "ta_index.h"
#include "../../rend/parse_arena.h"
// helper for 32 byte aligned memory allocation
void* OS_aligned_malloc(size_t align, size_t size);
@@ -338,6 +339,31 @@ struct TA_context
{
return (size_t)120 * 1024 * (ta_data_size() / TA_DATA_SIZE) * sizeof(u32); // (indices have the strips' joins)
}
// the modifier volumes' triangles', and those cut's (a third of them as fans of three more)
static size_t ModTrigRoom()
{
return (size_t)16384 * (ta_data_size() / TA_DATA_SIZE) * sizeof(ModTriangle);
}
static size_t MvClipRoom()
{
return ModTrigRoom() + ModTrigRoom() / sizeof(ModTriangle) / 2 * sizeof(ModTriangle);
}
/* The lists a frame's parse can write where the card reads them
* (rend/parse_arena.h's parts), their rooms and the lists themselves */
static void ArenaRooms(size_t *room)
{
room[PARSE_ARENA_VERTS] = VertRoom();
room[PARSE_ARENA_IDX] = IdxRoom();
room[PARSE_ARENA_MODTRIG] = ModTrigRoom();
room[PARSE_ARENA_MV_CLIP] = MvClipRoom();
}
void ArenaLists(ta_list_t **lists)
{
lists[PARSE_ARENA_VERTS] = &rend.verts.l;
lists[PARSE_ARENA_IDX] = &rend.idx.l;
lists[PARSE_ARENA_MODTRIG] = &rend.modtrig.l;
lists[PARSE_ARENA_MV_CLIP] = &rend.mv_clip.l;
}
/* false: there was not the memory for it, and it holds nothing (a
* NAOMI 2's frame takes about 60 megabytes). @data: the data goes
* there, a slice of ta_data_size() bytes of the GPU pool's (@slot),
@@ -346,7 +372,7 @@ struct TA_context
{
data_size = ta_data_size();
const unsigned scale = data_size / TA_DATA_SIZE;
unsigned modtrig_size = 16384 * scale;
const unsigned modtrig_size = (unsigned)(ModTrigRoom() / sizeof(ModTriangle));
pool = data != NULL ? slot : -1;
gpu_serial = 0;
tad.Reset(data != NULL ? data : (u8*)OS_aligned_malloc(32, data_size));
+2 -1
View File
@@ -328,7 +328,8 @@ bool isTwoVolumes(const PolyParam pp) \n\
// (the vertex and index buffers: 0, the renderer's own)
void gl4SetupMainVBO(GLuint geometry = 0, GLuint idxs = 0);
void gl4SetupModvolVBO();
// (the volumes' triangles' buffer: 0, the renderer's own)
void gl4SetupModvolVBO(GLuint modvols = 0);
/* A frame decoded on the GPU (pvrrc.gpu, rend/gles/ta_decoder_gl.h): its
* vertices, indices, modifier volume triangles and translucent polygons'
* words bound in their places (the vertex arrays' and binding 1), and each
+10 -7
View File
@@ -539,10 +539,11 @@ void gl4SetupMainVBO(GLuint geometry, GLuint idxs)
glVertexAttribPointer(VERTEX_UV1_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, u1)); glCheck();
}
/* What the vertex arrays and storage binding 1 have: -1 not known, -2 the
* GPU decode's, or the vertex buffer of the renderer's own or of the
* frame's they have */
/* What the vertex arrays and storage binding 1 have: frame_buffers -1 not
* known, -2 the GPU decode's, or the vertex buffer of the renderer's own
* or of the frame's they have; and the volumes' triangles' buffer */
static long frame_buffers = -1;
static GLuint frame_modvols;
void gl4ForgetFrameBuffers()
{
@@ -552,17 +553,19 @@ void gl4ForgetFrameBuffers()
void gl4BindFrameBuffers(bool gpu, bool own)
{
const GLuint geometry = own ? gl4.vbo.geometry : gl_frame_vertex_buffer(gl4.vbo.geometry);
const GLuint modvols = own ? gl4.vbo.modvols : gl_frame_modvol_buffer(gl4.vbo.modvols);
const long want = gpu ? -2 : (long)geometry;
if (frame_buffers == want)
if (frame_buffers == want && (gpu || frame_modvols == modvols))
return;
frame_buffers = want;
frame_modvols = modvols;
if (!gpu)
{
gl4SetupMainVBO(geometry, own ? gl4.vbo.idxs : gl_frame_index_buffer(gl4.vbo.idxs));
glDisableVertexAttribArray(VERTEX_PP_ARRAY);
// (an attribute without its array: the number is 0)
gl4.vertexAttribI4ui(VERTEX_PP_ARRAY, 0, 0, 0, 0);
gl4SetupModvolVBO();
gl4SetupModvolVBO(modvols);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, gl4.vbo.tr_poly_params);
glBindVertexArray(gl4.vbo.main_vao);
return;
@@ -589,11 +592,11 @@ void gl4BindFrameBuffers(bool gpu, bool own)
glBindVertexArray(gl4.vbo.main_vao);
}
void gl4SetupModvolVBO()
void gl4SetupModvolVBO(GLuint modvols)
{
glBindVertexArray(gl4.vbo.modvol_vao);
glBindBuffer(GL_ARRAY_BUFFER, gl4.vbo.modvols);
glBindBuffer(GL_ARRAY_BUFFER, modvols != 0 ? modvols : gl4.vbo.modvols);
//setup vertex buffers attrib pointers
glEnableVertexAttribArray(VERTEX_POS_ARRAY); glCheck();
+3 -3
View File
@@ -882,8 +882,8 @@ static bool RenderFrame()
glBufferData(GL_ELEMENT_ARRAY_BUFFER,pvrrc.idx.bytes(),pvrrc.idx.head(),GL_STREAM_DRAW); glCheck();
}
//Modvol VBO
if (pvrrc.modtrig.used() && !pvrrc.mv_clip.used())
//Modvol VBO (but where they were parsed into the buffers the card reads)
if (pvrrc.modtrig.used() && !pvrrc.mv_clip.used() && gl_frame_modvol_buffer(0) == 0)
{
glBindVertexArray(gl4.vbo.modvol_vao);
glBindBuffer(GL_ARRAY_BUFFER, gl4.vbo.modvols); glCheck();
@@ -916,7 +916,7 @@ static bool RenderFrame()
/* The volumes' triangles with those far off the screen cut
* (rend/modvol_clip.h), however the frame was decoded: the volumes'
* array then draws them, and is set again for the next frame */
if (!pvrrc.isRenderFramebuffer && pvrrc.mv_clip.used())
if (!pvrrc.isRenderFramebuffer && pvrrc.mv_clip.used() && gl_frame_modvol_buffer(0) == 0)
{
gl4SetupModvolVBO();
glBufferData(GL_ARRAY_BUFFER, pvrrc.mv_clip.bytes(), pvrrc.mv_clip.head(), GL_STREAM_DRAW); glCheck();
+24 -12
View File
@@ -339,8 +339,11 @@ static bool PrepassSupported()
}
/* The sorted triangles of the render pass's translucent list, when they
* are drawn by triangle, and its depth prepass's: both uploaded */
static void SortTriangles(int first, int count, bool sortTriangles, bool lastPass)
* are drawn by triangle, and its depth prepass's: written after the
* frame's indices where the frame was parsed into the buffers the card
* reads, and bound, or uploaded to a buffer of their own. Where they start
* in the buffer bound, in bytes. */
static uintptr_t SortTriangles(int first, int count, bool sortTriangles, bool lastPass)
{
/* (kept from one frame to the next: grown, never made again) */
static grow_buf_t indices;
@@ -348,18 +351,26 @@ static void SortTriangles(int first, int count, bool sortTriangles, bool lastPas
prepassDraws.count = 0;
const bool prepass = PrepassSupported();
if (!sortTriangles && !prepass)
return;
return 0;
/* room for both, made u16 in place if the indices are */
u32 *out = (u32 *)grow_buf_reserve(&indices, (size_t)(6 * SortedTriangles(first, count) + 1) * sizeof(u32));
const size_t room = (size_t)(6 * SortedTriangles(first, count) + 1) * sizeof(u32);
size_t at = 0;
u32 *here = gl_frame_sorted(room, &at);
u32 *out = here != nullptr ? here : (u32 *)grow_buf_reserve(&indices, room);
if (out == nullptr)
return;
return 0;
u32 n = 0;
if (sortTriangles)
n = GenSortedTo(first, count, &sortedDraws, out, false);
if (prepass)
n += GenPrepassTo(first, count, lastPass, &prepassDraws, out + n, n, false);
if (n == 0)
return;
return 0;
if (here != nullptr)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_frame_index_buffer(gl.vbo.idxs)); glCheck();
return at;
}
//Bind and upload sorted index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl.vbo.idxs2); glCheck();
@@ -373,6 +384,7 @@ static void SortTriangles(int first, int count, bool sortTriangles, bool lastPas
}
else
glBufferData(GL_ELEMENT_ARRAY_BUFFER, n * sizeof(u32), out, GL_STREAM_DRAW);
return 0;
}
/* The depth prepass of a sorted list: rend/sorter.h (with the sorted
@@ -599,7 +611,7 @@ static void SetupModvolVBO(bool gpu)
if (gpu)
glTaDecoder.BindModVols();
else
glBindBuffer(GL_ARRAY_BUFFER, gl.vbo.modvols);
glBindBuffer(GL_ARRAY_BUFFER, gl_frame_modvol_buffer(gl.vbo.modvols));
//setup vertex buffers attrib pointers
glEnableVertexAttribArray(VERTEX_POS_ARRAY);
@@ -867,19 +879,19 @@ void DrawStrips()
}
else if (settings.pvr.Emulation.AlphaSortMode == 0)
{
SortTriangles(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count, true, lastPass);
DrawPrepass(SortDraws(&prepassDraws), prepassDraws.count, 0);
DrawSorted(SortDraws(&sortedDraws), sortedDraws.count, !lastPass, 0);
const uintptr_t base = SortTriangles(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count, true, lastPass);
DrawPrepass(SortDraws(&prepassDraws), prepassDraws.count, base);
DrawSorted(SortDraws(&sortedDraws), sortedDraws.count, !lastPass, base);
// (the main indices again, after sorted triangles or a prepass)
if (sortedDraws.count != 0 || prepassDraws.count != 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_frame_index_buffer(gl.vbo.idxs));
}
else
{
SortTriangles(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count, false, lastPass);
const uintptr_t base = SortTriangles(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count, false, lastPass);
if (prepassDraws.count != 0)
{
DrawPrepass(SortDraws(&prepassDraws), prepassDraws.count, 0);
DrawPrepass(SortDraws(&prepassDraws), prepassDraws.count, base);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_frame_index_buffer(gl.vbo.idxs));
}
SortPParams(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count);
+30 -12
View File
@@ -1563,15 +1563,15 @@ static bool RenderFrame(void)
upload_vertex_indices();
}
//Modvol VBO
if (pvrrc.modtrig.used() && !pvrrc.mv_clip.used())
//Modvol VBO (but where they were parsed into the buffers the card reads)
if (pvrrc.modtrig.used() && !pvrrc.mv_clip.used() && gl_frame_modvol_buffer(0) == 0)
{
glBindBuffer(GL_ARRAY_BUFFER, gl.vbo.modvols); glCheck();
glBufferData(GL_ARRAY_BUFFER,pvrrc.modtrig.bytes(),pvrrc.modtrig.head(),GL_STREAM_DRAW); glCheck();
}
}
// the volumes' triangles with those far off the screen cut (rend/modvol_clip.h), however the frame was decoded
if (pvrrc.mv_clip.used())
if (pvrrc.mv_clip.used() && gl_frame_modvol_buffer(0) == 0)
{
glBindBuffer(GL_ARRAY_BUFFER, gl.vbo.modvols); glCheck();
glBufferData(GL_ARRAY_BUFFER, pvrrc.mv_clip.bytes(), pvrrc.mv_clip.head(), GL_STREAM_DRAW); glCheck();
@@ -1698,24 +1698,39 @@ static parse_arena_gl_t parse_arena;
static bool parse_arena_tried;
#endif
GLuint gl_frame_vertex_buffer(GLuint own)
// (the buffer of part @part of the arena's the frame was parsed into, or @own)
static GLuint frame_buffer(unsigned part, GLuint own)
{
#ifdef HAVE_GL4
const GLuint b = parse_arena_gl_vertex_buffer(&parse_arena);
const GLuint b = parse_arena_gl_buffer(&parse_arena, part);
if (b != 0)
return b;
#endif
return own;
}
GLuint gl_frame_vertex_buffer(GLuint own)
{
return frame_buffer(PARSE_ARENA_VERTS, own);
}
GLuint gl_frame_index_buffer(GLuint own)
{
return frame_buffer(PARSE_ARENA_IDX, own);
}
GLuint gl_frame_modvol_buffer(GLuint own)
{
return frame_buffer(pvrrc.mv_clip.used() != 0 ? PARSE_ARENA_MV_CLIP : PARSE_ARENA_MODTRIG, own);
}
u32 *gl_frame_sorted(size_t bytes, size_t *offset)
{
#ifdef HAVE_GL4
const GLuint b = parse_arena_gl_index_buffer(&parse_arena);
if (b != 0)
return b;
return (u32 *)parse_arena_gl_sorted(&parse_arena, bytes, offset);
#else
return nullptr;
#endif
return own;
}
void gl_frame_drawn()
@@ -1743,15 +1758,18 @@ static void parse_where_drawn(TA_context* ctx)
if (!parse_arena_tried)
{
parse_arena_tried = true;
if (parse_arena_gl_init(&parse_arena, TA_context::VertRoom(), TA_context::IdxRoom(), 3))
size_t room[PARSE_ARENA_PARTS];
TA_context::ArenaRooms(room);
if (parse_arena_gl_init(&parse_arena, room, 3))
NOTICE_LOG(RENDERER, "OpenGL: renders parsed where the card reads them, not copied there");
else
INFO_LOG(RENDERER, "OpenGL: renders copied to the card (the buffers for them could not be had, or read slowly)");
}
/* (four vertices at the head the parse keeps: the background's, FillBGP()'s) */
static bool copied;
if (!parse_arena_gl_attach(&parse_arena, &ctx->rend.verts.l, 4 * sizeof(Vertex), &ctx->rend.idx.l)
&& parse_arena.ready && !copied)
ta_list_t *lists[PARSE_ARENA_PARTS];
ctx->ArenaLists(lists);
if (!parse_arena_gl_attach(&parse_arena, lists, 4 * sizeof(Vertex)) && parse_arena.ready && !copied)
{
copied = true;
NOTICE_LOG(RENDERER, "OpenGL: a render copied to the card, no slot of the parse's free");
+6
View File
@@ -223,6 +223,12 @@ bool ProcessFrame(TA_context* ctx, u32 taFlags = 0);
* @own, which the lists are copied into */
GLuint gl_frame_vertex_buffer(GLuint own);
GLuint gl_frame_index_buffer(GLuint own);
// ...the volumes' triangles drawn (those cut where there are: rend/modvol_clip.h)
GLuint gl_frame_modvol_buffer(GLuint own);
/* Room for @bytes of a sorted pass's indices after the frame's in its index
* buffer (gl_frame_index_buffer()), and their @offset there; nullptr: none,
* and they go to a buffer of their own */
u32 *gl_frame_sorted(size_t bytes, size_t *offset);
// ...and the frame's draws issued: the buffers the card's until they are done
void gl_frame_drawn();
// (the context going)
+31 -24
View File
@@ -71,26 +71,27 @@ static int reads_fast(unsigned char *map, size_t bytes)
return (t2 - t1) <= 4 * (t1 - t0) + 200;
}
int parse_arena_gl_init(parse_arena_gl_t *a, size_t vert_room, size_t idx_room, unsigned slots)
int parse_arena_gl_init(parse_arena_gl_t *a, const size_t *room, unsigned slots)
{
unsigned i;
const size_t probe = room[PARSE_ARENA_VERTS] < ((size_t)1 << 20) ? room[PARSE_ARENA_VERTS] : (size_t)1 << 20;
unsigned i, p;
memset(a, 0, sizeof(*a));
if (parse_arena_layout(&a->arena, vert_room, idx_room, slots, 1) == 0)
if (parse_arena_layout(&a->arena, room, slots, 1) == 0)
return 0;
for (i = 0; i < slots; i++)
{
void *v = NULL, *x = NULL;
a->verts[i] = make_buffer(vert_room, &v);
a->idx[i] = make_buffer(idx_room, &x);
if (v == NULL || x == NULL)
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
parse_arena_gl_term(a);
return 0;
void *m = NULL;
a->buffer[i][p] = make_buffer(a->arena.space[p], &m);
if (m == NULL)
{
parse_arena_gl_term(a);
return 0;
}
parse_arena_bind_slot(&a->arena, i, p, m);
}
parse_arena_bind_slot(&a->arena, i, v, x);
}
if (!reads_fast(a->arena.slot_verts[0], vert_room < ((size_t)1 << 20) ? vert_room : (size_t)1 << 20))
if (!reads_fast(a->arena.part_mem[0][PARSE_ARENA_VERTS], probe))
{
parse_arena_gl_term(a);
return 0;
@@ -101,7 +102,7 @@ int parse_arena_gl_init(parse_arena_gl_t *a, size_t vert_room, size_t idx_room,
void parse_arena_gl_term(parse_arena_gl_t *a)
{
unsigned i;
unsigned i, p;
if (a->ready)
parse_arena_detach(&a->arena);
@@ -110,10 +111,9 @@ void parse_arena_gl_term(parse_arena_gl_t *a)
if (a->fence[i] != NULL)
glDeleteSync(a->fence[i]);
/* (deleting a buffer unmaps it) */
if (a->verts[i] != 0)
glDeleteBuffers(1, &a->verts[i]);
if (a->idx[i] != 0)
glDeleteBuffers(1, &a->idx[i]);
for (p = 0; p < PARSE_ARENA_PARTS; p++)
if (a->buffer[i][p] != 0)
glDeleteBuffers(1, &a->buffer[i][p]);
}
memset(a, 0, sizeof(*a));
}
@@ -134,7 +134,7 @@ static int slot_free(parse_arena_gl_t *a, unsigned s)
return 1;
}
int parse_arena_gl_attach(parse_arena_gl_t *a, ta_list_t *verts, size_t vert_head, ta_list_t *idx)
int parse_arena_gl_attach(parse_arena_gl_t *a, ta_list_t *const *lists, size_t vert_head)
{
unsigned i;
@@ -145,9 +145,10 @@ int parse_arena_gl_attach(parse_arena_gl_t *a, ta_list_t *verts, size_t vert_hea
const unsigned s = (a->next + i) % a->arena.slices;
if (!slot_free(a, s))
continue;
if (!parse_arena_attach(&a->arena, s, verts, vert_head, idx))
if (!parse_arena_attach(&a->arena, s, lists, vert_head))
return 0;
a->next = (s + 1) % a->arena.slices;
a->sorted = 0;
return 1;
}
return 0;
@@ -169,12 +170,18 @@ void parse_arena_gl_cancel(parse_arena_gl_t *a)
parse_arena_detach(&a->arena);
}
GLuint parse_arena_gl_vertex_buffer(const parse_arena_gl_t *a)
GLuint parse_arena_gl_buffer(const parse_arena_gl_t *a, unsigned part)
{
return a->ready && a->arena.slot >= 0 ? a->verts[a->arena.slot] : 0;
return a->ready && a->arena.slot >= 0 && part < PARSE_ARENA_PARTS ? a->buffer[a->arena.slot][part] : 0;
}
GLuint parse_arena_gl_index_buffer(const parse_arena_gl_t *a)
void *parse_arena_gl_sorted(parse_arena_gl_t *a, size_t bytes, size_t *offset)
{
return a->ready && a->arena.slot >= 0 ? a->idx[a->arena.slot] : 0;
const size_t at = a->arena.room[PARSE_ARENA_IDX] + a->sorted;
if (!a->ready || a->arena.slot < 0 || bytes > a->arena.sort_room - a->sorted)
return NULL;
a->sorted += bytes;
*offset = at;
return a->arena.part_mem[a->arena.slot][PARSE_ARENA_IDX] + at;
}
+15 -10
View File
@@ -1,7 +1,9 @@
#ifndef PARSE_ARENA_GL_H
#define PARSE_ARENA_GL_H
/* The parse's arena (rend/parse_arena.h) with OpenGL: a vertex and an
* index buffer for each of a few frames in flight, of immutable storage
/* The parse's arena (rend/parse_arena.h) with OpenGL: a buffer for each of
* its parts (the vertices, the indices with the sorted passes' after them,
* the volumes' triangles and those cut) for each of a few frames in
* flight, of immutable storage
* mapped persistently and coherently in the client's memory (OpenGL 4.4
* or ARB_buffer_storage), where the frame is parsed and then drawn from:
* no copy into a buffer for the card.
@@ -21,30 +23,33 @@ extern "C" {
typedef struct parse_arena_gl
{
parse_arena_t arena;
GLuint verts[PARSE_ARENA_SLOTS];
GLuint idx[PARSE_ARENA_SLOTS];
GLuint buffer[PARSE_ARENA_SLOTS][PARSE_ARENA_PARTS];
GLsync fence[PARSE_ARENA_SLOTS];
size_t sorted; /* the sorted passes' bytes so far this frame */
unsigned next; /* the slot looked at first */
int ready; /* (all zero, as a static one is before it is made: none) */
} parse_arena_gl_t;
/* Made for @slots frames of lists of @vert_room and @idx_room bytes, in
/* Made for @slots frames of lists of the rooms @room (by PARSE_ARENA_*), in
* the context that is current; false, and nothing kept, where the buffers
* cannot be made and mapped, or read back slowly */
int parse_arena_gl_init(parse_arena_gl_t *a, size_t vert_room, size_t idx_room, unsigned slots);
int parse_arena_gl_init(parse_arena_gl_t *a, const size_t *room, unsigned slots);
void parse_arena_gl_term(parse_arena_gl_t *a);
/* The frame whose lists these are parsed into a free slot, from now till
* parse_arena_gl_done() (its draws issued) or parse_arena_gl_cancel() (it
* is not drawn); false where no slot is free, or the lists are not of the
* arena's size (parse_arena_attach(), @vert_head as there) */
int parse_arena_gl_attach(parse_arena_gl_t *a, ta_list_t *verts, size_t vert_head, ta_list_t *idx);
int parse_arena_gl_attach(parse_arena_gl_t *a, ta_list_t *const *lists, size_t vert_head);
void parse_arena_gl_done(parse_arena_gl_t *a);
void parse_arena_gl_cancel(parse_arena_gl_t *a);
/* The frame's buffers while it is attached, 0 otherwise */
GLuint parse_arena_gl_vertex_buffer(const parse_arena_gl_t *a);
GLuint parse_arena_gl_index_buffer(const parse_arena_gl_t *a);
/* The frame's buffer of part @part while it is attached, 0 otherwise */
GLuint parse_arena_gl_buffer(const parse_arena_gl_t *a, unsigned part);
/* Room for @bytes of a sorted pass's indices after the frame's, in its
* index buffer: where to write them, and (@offset) where they are in the
* buffer; NULL where the frame is not attached or the room is used up */
void *parse_arena_gl_sorted(parse_arena_gl_t *a, size_t bytes, size_t *offset);
#ifdef __cplusplus
}
+41 -37
View File
@@ -7,44 +7,46 @@ static size_t round_up(size_t n, size_t align)
return (n + align - 1) / align * align;
}
size_t parse_arena_layout(parse_arena_t *a, size_t vert_room, size_t idx_room, unsigned slices, size_t align)
size_t parse_arena_layout(parse_arena_t *a, const size_t *room, unsigned slices, size_t align)
{
size_t at = 0;
unsigned p;
memset(a, 0, sizeof(*a));
a->slot = -1;
if (slices > PARSE_ARENA_SLOTS)
return 0;
if (align == 0)
align = 1;
a->vert_room = vert_room;
a->idx_room = idx_room;
/* (the sorted passes': as much again as the indices, which is room for
* more translucent triangles than a frame has; more, and that frame is
* drawn from a copy) */
a->sort_room = idx_room;
a->idx_at = round_up(vert_room, align);
a->slice = round_up(a->idx_at + idx_room + a->sort_room, align);
a->sort_room = room[PARSE_ARENA_IDX];
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
a->room[p] = room[p];
a->space[p] = room[p] + (p == PARSE_ARENA_IDX ? a->sort_room : 0);
a->at[p] = at;
at = round_up(at + a->space[p], align);
}
a->slice = at;
a->slices = slices;
a->slot = -1;
return a->slice * slices;
}
void parse_arena_bind(parse_arena_t *a, void *mem)
{
unsigned i;
unsigned i, p;
a->mem = (unsigned char *)mem;
for (i = 0; i < a->slices; i++)
{
a->slot_verts[i] = mem != NULL ? a->mem + a->slice * i : NULL;
a->slot_idx[i] = mem != NULL ? a->mem + a->slice * i + a->idx_at : NULL;
}
for (p = 0; p < PARSE_ARENA_PARTS; p++)
a->part_mem[i][p] = mem != NULL ? a->mem + a->slice * i + a->at[p] : NULL;
}
void parse_arena_bind_slot(parse_arena_t *a, unsigned slot, void *verts, void *idx)
void parse_arena_bind_slot(parse_arena_t *a, unsigned slot, unsigned part, void *mem)
{
if (slot >= a->slices)
return;
a->slot_verts[slot] = (unsigned char *)verts;
a->slot_idx[slot] = (unsigned char *)idx;
if (slot < a->slices && part < PARSE_ARENA_PARTS)
a->part_mem[slot][part] = (unsigned char *)mem;
}
/* @l pointed at @room bytes at @at, with what it holds - and at least its
@@ -58,38 +60,40 @@ static void move_into(ta_list_t *l, unsigned char *at, size_t room, size_t head)
l->end = at + room;
}
int parse_arena_attach(parse_arena_t *a, unsigned slot, ta_list_t *verts, size_t vert_head, ta_list_t *idx)
int parse_arena_attach(parse_arena_t *a, unsigned slot, ta_list_t *const *lists, size_t vert_head)
{
if (slot >= a->slices || a->slot_verts[slot] == NULL || a->slot_idx[slot] == NULL || a->slot >= 0
|| (size_t)(verts->end - verts->base) != a->vert_room || (size_t)(idx->end - idx->base) != a->idx_room
|| vert_head > a->vert_room)
unsigned p;
if (slot >= a->slices || a->slot >= 0 || vert_head > a->room[PARSE_ARENA_VERTS])
return 0;
a->own_verts = *verts;
a->own_idx = *idx;
a->verts = verts;
a->idx = idx;
for (p = 0; p < PARSE_ARENA_PARTS; p++)
if (a->part_mem[slot][p] == NULL || (size_t)(lists[p]->end - lists[p]->base) != a->room[p])
return 0;
a->slot = (int)slot;
move_into(verts, a->slot_verts[slot], a->vert_room, vert_head);
move_into(idx, a->slot_idx[slot], a->idx_room, 0);
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
a->own[p] = *lists[p];
a->lists[p] = lists[p];
move_into(lists[p], a->part_mem[slot][p], a->room[p], p == PARSE_ARENA_VERTS ? vert_head : 0);
}
return 1;
}
void parse_arena_detach(parse_arena_t *a)
{
unsigned p;
if (a->slot < 0)
return;
*a->verts = a->own_verts;
*a->idx = a->own_idx;
a->verts = a->idx = NULL;
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
*a->lists[p] = a->own[p];
a->lists[p] = NULL;
}
a->slot = -1;
}
size_t parse_arena_vert_offset(const parse_arena_t *a, unsigned slot)
size_t parse_arena_offset(const parse_arena_t *a, unsigned slot, unsigned part)
{
return a->slice * slot;
}
size_t parse_arena_idx_offset(const parse_arena_t *a, unsigned slot)
{
return a->slice * slot + a->idx_at;
return a->slice * slot + a->at[part];
}
+49 -39
View File
@@ -1,17 +1,20 @@
#ifndef PARSE_ARENA_H
#define PARSE_ARENA_H
/* Where a frame's parse writes its vertices and indices when the card
* draws them from there: memory of the renderer's, which the card reads
* and the processor has in its cache (a device whose memory is the
* host's), in slices, one for each of the renderer's frames in flight.
/* Where a frame's parse writes what the card draws when the card draws it
* from there: memory of the renderer's, which the card reads and the
* processor has in its cache (a device whose memory is the host's, or the
* client's memory a buffer is mapped in), in slices, one for each of the
* renderer's frames in flight.
*
* A render's frame is parsed into the slice of its frame in flight (the
* renderer's command pool's slot, which is free when the frame before in
* that slot is done on the card: nothing here waits), and drawn from there.
* The vertices are not copied into a buffer for the card: they are in one.
* A slice is the room a frame's lists have (ta_ctx.h), so a frame never
* runs out of it here where it would not have in its own; and the sorted
* passes' indices go after the frame's, in room of their own.
* renderer's slot, which is free when the frame before in that slot is
* done on the card: nothing here waits), and drawn from there. Its lists -
* the vertices, the indices, the modifier volumes' triangles and those of
* them cut (rend/modvol_clip.h) - are not copied into a buffer for the
* card: they are in one. A slice has the room a frame's lists have
* (ta_ctx.h), so a frame never runs out of it here where it would not have
* in its own; and the sorted passes' indices go after the frame's, in room
* of their own.
*
* The frame's own lists are put back when it has been drawn: they are the
* frame's, and go with it. C89. */
@@ -25,50 +28,57 @@ extern "C" {
/* (most slices an arena has) */
#define PARSE_ARENA_SLOTS 8
/* A slice's parts: a list of the frame's each */
enum
{
PARSE_ARENA_VERTS = 0,
PARSE_ARENA_IDX,
PARSE_ARENA_MODTRIG,
PARSE_ARENA_MV_CLIP,
PARSE_ARENA_PARTS
};
typedef struct parse_arena
{
unsigned char *mem; /* mapped: the slices one after another */
/* ...or a slice's vertices and indices each where a buffer of their
* own is mapped (parse_arena_bind_slot()) */
unsigned char *slot_verts[PARSE_ARENA_SLOTS];
unsigned char *slot_idx[PARSE_ARENA_SLOTS];
size_t vert_room; /* a slice's vertices' bytes */
size_t idx_room; /* ...its indices' */
size_t sort_room; /* ...and the sorted passes', after them */
size_t idx_at; /* where in a slice the indices start */
size_t slice; /* a slice's bytes */
unsigned char *mem; /* mapped: the slices one after another */
/* each part of each slice, where it is: in mem, or in a buffer of its
* own mapped (parse_arena_bind_slot()) */
unsigned char *part_mem[PARSE_ARENA_SLOTS][PARSE_ARENA_PARTS];
size_t room[PARSE_ARENA_PARTS]; /* a list's bytes */
size_t space[PARSE_ARENA_PARTS]; /* ...and a part's: the indices' with the sorted passes' after */
size_t at[PARSE_ARENA_PARTS]; /* where in a slice a part starts */
size_t sort_room; /* (the sorted passes' bytes) */
size_t slice; /* a slice's bytes */
unsigned slices;
/* while a frame's lists are in a slice: which, and the lists as they
* were, to be put back */
int slot;
ta_list_t *verts, *idx;
ta_list_t own_verts, own_idx;
ta_list_t *lists[PARSE_ARENA_PARTS];
ta_list_t own[PARSE_ARENA_PARTS];
} parse_arena_t;
/* The layout for @slices (PARSE_ARENA_SLOTS at most) of rooms of
* @vert_room and @idx_room bytes (a frame's lists'), each part of a slice
/* The layout for @slices (PARSE_ARENA_SLOTS at most) of the rooms @room
* (a frame's lists', in bytes, by PARSE_ARENA_*), each part of a slice
* @align bytes aligned: the bytes it takes, 0 for too many slices. No
* memory yet (parse_arena_bind()). */
size_t parse_arena_layout(parse_arena_t *a, size_t vert_room, size_t idx_room, unsigned slices, size_t align);
size_t parse_arena_layout(parse_arena_t *a, const size_t *room, unsigned slices, size_t align);
void parse_arena_bind(parse_arena_t *a, void *mem);
/* ...or slice @slot's vertices at @verts (vert_room bytes) and its indices
* at @idx (idx_room bytes, and sort_room after them where the sorted
* passes go there), apart */
void parse_arena_bind_slot(parse_arena_t *a, unsigned slot, void *verts, void *idx);
/* ...or part @part of slice @slot at @mem (space[part] bytes), apart */
void parse_arena_bind_slot(parse_arena_t *a, unsigned slot, unsigned part, void *mem);
/* The frame whose lists these are parsed into slice @slot: what they hold
* already copied there - and of the vertices, at least the first
* @vert_head bytes, which the parse keeps though the list is empty (the
* background polygon's, FillBGP()'s) - and they point there, till
* parse_arena_detach(). False, and nothing done, where they are not of
* the room the slices are (a machine whose frames are another size). */
int parse_arena_attach(parse_arena_t *a, unsigned slot, ta_list_t *verts, size_t vert_head, ta_list_t *idx);
/* The frame whose lists these are (@lists, by PARSE_ARENA_*) parsed into
* slice @slot: what they hold already copied there - and of the vertices,
* at least the first @vert_head bytes, which the parse keeps though the
* list is empty (the background polygon's, FillBGP()'s) - and they point
* there, till parse_arena_detach(). False, and nothing done, where they
* are not of the rooms the parts are (a machine whose frames are another
* size). */
int parse_arena_attach(parse_arena_t *a, unsigned slot, ta_list_t *const *lists, size_t vert_head);
/* The frame's own lists back. What was parsed stays in the slice. */
void parse_arena_detach(parse_arena_t *a);
/* Where in the memory slice @slot's vertices and indices are */
size_t parse_arena_vert_offset(const parse_arena_t *a, unsigned slot);
size_t parse_arena_idx_offset(const parse_arena_t *a, unsigned slot);
/* Where in the memory part @part of slice @slot is */
size_t parse_arena_offset(const parse_arena_t *a, unsigned slot, unsigned part);
#ifdef __cplusplus
}
+2 -2
View File
@@ -429,7 +429,7 @@ BufferData *Drawer::SortIntoMainBuffer()
const u32 sortRoom = pvrrc.gpu ? 0 : SortPassesRoom() * sizeof(u32);
const bool here = UseParsed(sortRoom);
const u32 vertexBytes = pvrrc.gpu || here ? 0 : pvrrc.verts.bytes();
const u32 modVolBytes = ModVolsOnCpu() ? ModVolList().bytes() : 0;
const u32 modVolBytes = ModVolsOnCpu() && !here ? ModVolList().bytes() : 0;
const u32 indexBytes = pvrrc.gpu || here ? 0 : pvrrc.idx.bytes();
const u32 sortedBytes = here ? 0 : sortRoom;
@@ -462,7 +462,7 @@ void Drawer::UploadMainBuffer(BufferData *buffer, const FragmentShaderUniforms&
buffer->upload(pvrrc.verts.bytes(), pvrrc.verts.head(), 0);
buffer->upload(pvrrc.idx.bytes(), pvrrc.idx.head(), offsets.indexOffset);
}
if (ModVolsOnCpu())
if (ModVolsOnCpu() && !geometryParsed)
buffer->upload(ModVolList().bytes(), ModVolList().head(), offsets.modVolOffset);
buffer->upload(sizeof(fragmentUniforms), &fragmentUniforms, offsets.fragmentUniformOffset);
}
+4
View File
@@ -62,6 +62,7 @@ public:
{
vk::Buffer buffer;
vk::DeviceSize vertices = 0, indices = 0;
vk::DeviceSize modVols = 0; // the volumes' triangles drawn (ModVolList()'s)
u32 sortRoom = 0; // bytes
};
/* This render's frame was parsed there; none (a null buffer): it is
@@ -163,6 +164,9 @@ protected:
const vk::DeviceSize zero = 0;
if (!ModVolsOnCpu())
cmdBuffer.bindVertexBuffers(0, 1, &gpuDraw->modtrig, &zero);
// (where the parse wrote them, with the frame's geometry: geometryParsed)
else if (geometryParsed)
cmdBuffer.bindVertexBuffers(0, 1, &parsed.buffer, &parsed.modVols);
else
cmdBuffer.bindVertexBuffers(0, 1, &mainBuffer, &modVolOffset);
}
+1 -1
View File
@@ -305,7 +305,7 @@ void OITDrawer::UploadMainBuffer(const OITDescriptorSets::FragmentShaderUniforms
* geometry there) */
const bool here = UseParsed(0);
const u32 vertexBytes = pvrrc.gpu || here ? 0 : pvrrc.verts.bytes();
const u32 modVolBytes = ModVolsOnCpu() ? ModVolList().bytes() : 0;
const u32 modVolBytes = ModVolsOnCpu() && !here ? ModVolList().bytes() : 0;
const u32 indexBytes = pvrrc.gpu || here ? 0 : pvrrc.idx.bytes();
// Vertex
+5 -6
View File
@@ -9,18 +9,17 @@
#define PARSE_MEMORY (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT \
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
int parse_arena_vk_init(parse_arena_vk_t *a, VkDevice device, vk_heap_t *heap, size_t vert_room, size_t idx_room,
unsigned slices)
int parse_arena_vk_init(parse_arena_vk_t *a, VkDevice device, vk_heap_t *heap, const size_t *room, unsigned slices)
{
VkBufferCreateInfo info;
VkMemoryRequirements req;
size_t bytes;
memset(a, 0, sizeof(*a));
/* (a slice's indices 256 bytes aligned: more than an index buffer's
* offset needs, and the sorted passes' after them are as aligned as
* the frame's indices' end, 4 bytes) */
bytes = parse_arena_layout(&a->arena, vert_room, idx_room, slices, 256);
/* (a slice's parts 256 bytes aligned: more than a vertex or index
* buffer's offset needs, and the sorted passes' after the indices are
* as aligned as the frame's indices' end, 4 bytes) */
bytes = parse_arena_layout(&a->arena, room, slices, 256);
if (bytes == 0)
return 0;
memset(&info, 0, sizeof(info));
+3 -4
View File
@@ -23,10 +23,9 @@ typedef struct parse_arena_vk
vk_heap_alloc_t mem;
} parse_arena_vk_t;
/* Made for @slices frames in flight with lists of @vert_room and
* @idx_room bytes; false (and nothing kept) without the memory for it */
int parse_arena_vk_init(parse_arena_vk_t *a, VkDevice device, vk_heap_t *heap, size_t vert_room, size_t idx_room,
unsigned slices);
/* Made for @slices frames in flight with lists of the rooms @room (by
* PARSE_ARENA_*); false (and nothing kept) without the memory for it */
int parse_arena_vk_init(parse_arena_vk_t *a, VkDevice device, vk_heap_t *heap, const size_t *room, unsigned slices);
/* (the frames that used it done on the card) */
void parse_arena_vk_term(parse_arena_vk_t *a);
+13 -7
View File
@@ -174,8 +174,10 @@ public:
* there is one: the draws read it there, uncopied (with the
* background polygon's four vertices FillBGP() wrote, at the
* head of the list the parse empties and takes them back in) */
ta_list_t *lists[PARSE_ARENA_PARTS];
ctx->ArenaLists(lists);
if (parseArenaOk && parse_arena_attach(&parseArena.arena, (unsigned)texCommandPool.GetIndex(),
&ctx->rend.verts.l, 4 * sizeof(Vertex), &ctx->rend.idx.l))
lists, 4 * sizeof(Vertex)))
parsedSlot = texCommandPool.GetIndex();
result = ta_parse_vdrc(ctx);
if (!result)
@@ -222,9 +224,12 @@ protected:
{
const parse_arena_t& a = parseArena.arena;
parsed.buffer = vk::Buffer(parseArena.buffer);
parsed.vertices = parse_arena_vert_offset(&a, (unsigned)parsedSlot);
parsed.indices = parse_arena_idx_offset(&a, (unsigned)parsedSlot);
parsed.sortRoom = (u32)(a.idx_room + a.sort_room - pvrrc.idx.bytes());
parsed.vertices = parse_arena_offset(&a, (unsigned)parsedSlot, PARSE_ARENA_VERTS);
parsed.indices = parse_arena_offset(&a, (unsigned)parsedSlot, PARSE_ARENA_IDX);
parsed.sortRoom = (u32)(a.space[PARSE_ARENA_IDX] - pvrrc.idx.bytes());
// (the volumes' triangles drawn: those cut where there are, rend/modvol_clip.h)
parsed.modVols = parse_arena_offset(&a, (unsigned)parsedSlot,
pvrrc.mv_clip.used() != 0 ? PARSE_ARENA_MV_CLIP : PARSE_ARENA_MODTRIG);
if (parsedHere++ == 0)
NOTICE_LOG(RENDERER, "Vulkan: renders parsed where the card reads them, not copied there");
}
@@ -251,8 +256,10 @@ protected:
* (Made once: a change of size comes back here, the frames on the
* card done, and keeps it while it has as many slices as there are
* slots, of the machine's lists' room.) */
size_t room[PARSE_ARENA_PARTS];
TA_context::ArenaRooms(room);
if (parseArenaOk && (parseArena.arena.slices != (unsigned)texCommandPool.GetSize()
|| parseArena.arena.vert_room != TA_context::VertRoom() || parseArena.arena.idx_room != TA_context::IdxRoom()))
|| memcmp(parseArena.arena.room, room, sizeof(room)) != 0))
{
parse_arena_vk_term(&parseArena);
parseArenaOk = false;
@@ -260,8 +267,7 @@ protected:
if (!parseArenaOk)
{
parseArenaOk = parse_arena_vk_init(&parseArena, (VkDevice)GetContext()->GetDevice(),
GetContext()->GetHeap().Raw(), TA_context::VertRoom(), TA_context::IdxRoom(),
(unsigned)texCommandPool.GetSize()) != 0;
GetContext()->GetHeap().Raw(), room, (unsigned)texCommandPool.GetSize()) != 0;
parsedHere = parsedCopied = 0;
}
DetachParse();
+5 -3
View File
@@ -6,7 +6,9 @@
# drawn from where it was parsed, with no OpenGL error (MESA_DEBUG), and
# every frame is the one of the lists copied, as an OpenGL without
# ARB_buffer_storage has it (GLF_NO_STORAGE) - the test discs' plain one,
# heavy one and DMA one, with each renderer, threaded rendering on and off,
# heavy one, DMA one and the one with modifier volumes (--cull: their
# triangles drawn from there too), the sorted passes' indices written after
# the frame's, with each renderer, threaded rendering on and off,
# a VMU's screen drawn over them.
# And with OpenGL ES, which has no such buffers, the frames are drawn as
# ever.
@@ -22,7 +24,7 @@ mkdir -p "$WORK"
[ -n "${KEEP:-}" ] || trap 'rm -rf "$WORK"' EXIT
${CC:-cc} -O1 -g -Wall -o "$WORK/gl_frames" tools/gl/gl_frames.c -lEGL -lGL -ldl
# (a directory a disc: their tracks' names are the same)
for disc in plain heavy dma; do
for disc in plain heavy dma cull; do
mkdir -p "$WORK/$disc"
case $disc in
plain) python3 tools/threads/live_disc.py "$WORK/$disc/test.gdi" ;;
@@ -46,7 +48,7 @@ run() {
fi
}
for disc in plain heavy dma; do
for disc in plain heavy dma cull; do
for r in per-triangle per-pixel; do
case $r in
per-triangle) set -- "reicast_alpha_sorting=per-triangle (normal)" ;;
+118 -75
View File
@@ -1,9 +1,11 @@
/* The parse's arena (core/rend/parse_arena.c): the slices laid out apart
* and aligned; a frame's lists moved into a slice with what they hold -
* and the head the parse keeps though the list is empty (the background
/* The parse's arena (core/rend/parse_arena.c): the slices and their parts
* laid out apart and aligned, the indices' part with the sorted passes'
* room after; a frame's lists moved into a slice with what they hold - and
* the head the parse keeps though the list is empty (the background
* polygon's vertices: FillBGP()) - their own back after; lists of another
* size, a second attach, a slot out of range refused; a frame filling its
* slice's room overruns into its own slice, not the next. C89.
* size, a second attach, a slot out of range or with a part unbound
* refused; a frame filling its slice's room overruns into its own slice,
* not the next; parts bound apart (a buffer each, as OpenGL's). C89.
*
* sh tools/rend/parse_arena_test.sh */
#include <stdio.h>
@@ -15,123 +17,164 @@ static int fails;
#define CHECK(c) do { if (!(c)) { printf("FAIL line %d: %s\n", __LINE__, #c); fails++; } } while (0)
#define VERT_ROOM 4096
#define IDX_ROOM 1024
#define SLICES 3
#define ALIGN 256
#define HEAD 64 /* "four vertices" */
static const size_t room[PARSE_ARENA_PARTS] = { 4096, 1024, 360, 540 };
static const size_t elem[PARSE_ARENA_PARTS] = { 16, 4, 36, 36 };
/* the lists, each with its own memory, and how many bytes each holds */
static int make_lists(ta_list_t *l, ta_list_t **lp, unsigned char *overrun)
{
unsigned p;
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
if (!ta_list_init(&l[p], room[p], elem[p], overrun, "list"))
return 0;
lp[p] = &l[p];
}
return 1;
}
int main(void)
{
parse_arena_t a;
ta_list_t verts, idx, other;
ta_list_t l[PARSE_ARENA_PARTS], other;
ta_list_t *lp[PARSE_ARENA_PARTS];
unsigned char *own[PARSE_ARENA_PARTS];
unsigned char overrun = 0;
unsigned char *mem;
unsigned char *own_verts, *own_idx;
size_t bytes, i;
unsigned slot;
unsigned slot, p;
bytes = parse_arena_layout(&a, VERT_ROOM, IDX_ROOM, SLICES, ALIGN);
bytes = parse_arena_layout(&a, room, SLICES, ALIGN);
CHECK(bytes == a.slice * SLICES);
CHECK(a.slice % ALIGN == 0 && a.idx_at % ALIGN == 0);
CHECK(a.idx_at >= VERT_ROOM && a.slice >= a.idx_at + IDX_ROOM + a.sort_room);
CHECK(a.sort_room >= IDX_ROOM);
CHECK(a.slice % ALIGN == 0);
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
CHECK(a.at[p] % ALIGN == 0);
CHECK(a.room[p] == room[p]);
CHECK(a.space[p] == room[p] + (p == PARSE_ARENA_IDX ? a.sort_room : 0));
if (p > 0)
CHECK(a.at[p] >= a.at[p - 1] + a.space[p - 1]);
}
CHECK(a.slice >= a.at[PARSE_ARENA_PARTS - 1] + a.space[PARSE_ARENA_PARTS - 1]);
CHECK(a.sort_room >= room[PARSE_ARENA_IDX]);
mem = (unsigned char *)malloc(bytes);
CHECK(mem != NULL);
if (mem == NULL)
if (mem == NULL || !make_lists(l, lp, &overrun))
return 1;
memset(mem, 0xEE, bytes);
for (p = 0; p < PARSE_ARENA_PARTS; p++)
own[p] = l[p].base;
/* nothing to attach to before there is memory */
CHECK(ta_list_init(&verts, VERT_ROOM, 16, &overrun, "verts"));
CHECK(ta_list_init(&idx, IDX_ROOM, 4, &overrun, "idx"));
CHECK(!parse_arena_attach(&a, 0, &verts, HEAD, &idx));
CHECK(!parse_arena_attach(&a, 0, lp, HEAD));
parse_arena_bind(&a, mem);
own_verts = verts.base;
own_idx = idx.base;
for (slot = 0; slot < SLICES; slot++)
{
/* the head written, the list emptied after (as the TA's is) */
/* the vertices' head written, the list emptied after (as the TA's
* is); the other lists with one element each */
for (i = 0; i < HEAD; i++)
own_verts[i] = (unsigned char)(slot * 16 + i);
verts.cur = verts.base;
/* one index already there */
own_idx[0] = (unsigned char)(0x40 + slot);
own_idx[1] = own_idx[2] = own_idx[3] = 0;
idx.cur = idx.base + 4;
own[PARSE_ARENA_VERTS][i] = (unsigned char)(slot * 16 + i);
l[PARSE_ARENA_VERTS].cur = l[PARSE_ARENA_VERTS].base;
for (p = 1; p < PARSE_ARENA_PARTS; p++)
{
memset(own[p], (int)(0x40 + slot * 4 + p), elem[p]);
l[p].cur = l[p].base + elem[p];
}
CHECK(parse_arena_attach(&a, slot, &verts, HEAD, &idx));
CHECK(verts.base == mem + parse_arena_vert_offset(&a, slot));
CHECK(idx.base == mem + parse_arena_idx_offset(&a, slot));
CHECK(verts.cur == verts.base && (size_t)(verts.end - verts.base) == VERT_ROOM);
CHECK(idx.cur == idx.base + 4 && (size_t)(idx.end - idx.base) == IDX_ROOM);
CHECK(parse_arena_attach(&a, slot, lp, HEAD));
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
CHECK(l[p].base == mem + parse_arena_offset(&a, slot, p));
CHECK((size_t)(l[p].end - l[p].base) == room[p]);
}
CHECK(l[PARSE_ARENA_VERTS].cur == l[PARSE_ARENA_VERTS].base);
for (i = 0; i < HEAD; i++)
CHECK(verts.base[i] == (unsigned char)(slot * 16 + i));
CHECK(idx.base[0] == 0x40 + slot);
CHECK(l[PARSE_ARENA_VERTS].base[i] == (unsigned char)(slot * 16 + i));
for (p = 1; p < PARSE_ARENA_PARTS; p++)
{
CHECK(l[p].cur == l[p].base + elem[p]);
CHECK(l[p].base[0] == (unsigned char)(0x40 + slot * 4 + p) && l[p].base[elem[p] - 1] == l[p].base[0]);
}
/* (one frame at a time) */
CHECK(!parse_arena_attach(&a, slot, &verts, HEAD, &idx));
CHECK(!parse_arena_attach(&a, slot, lp, HEAD));
/* the parse fills its room: its slice's only, the others untouched */
memset(verts.base, 0x11 * (slot + 1), VERT_ROOM);
memset(idx.base, 0x22 * (slot + 1), IDX_ROOM + a.sort_room);
/* the parse fills its parts' space: its slice's only, the others untouched */
for (p = 0; p < PARSE_ARENA_PARTS; p++)
memset(l[p].base, (int)(0x11 * (slot + 1) + p), a.space[p]);
parse_arena_detach(&a);
CHECK(verts.base == own_verts && idx.base == own_idx);
CHECK((size_t)(verts.end - verts.base) == VERT_ROOM);
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
CHECK(l[p].base == own[p]);
CHECK((size_t)(l[p].end - l[p].base) == room[p]);
}
parse_arena_detach(&a); /* (twice: nothing) */
CHECK(verts.base == own_verts);
CHECK(l[PARSE_ARENA_VERTS].base == own[PARSE_ARENA_VERTS]);
}
for (slot = 0; slot < SLICES; slot++)
{
const unsigned char *v = mem + parse_arena_vert_offset(&a, slot);
const unsigned char *x = mem + parse_arena_idx_offset(&a, slot);
CHECK(v[0] == 0x11 * (slot + 1) && v[VERT_ROOM - 1] == 0x11 * (slot + 1));
CHECK(x[0] == 0x22 * (slot + 1) && x[IDX_ROOM + a.sort_room - 1] == 0x22 * (slot + 1));
}
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
const unsigned char *m = mem + parse_arena_offset(&a, slot, p);
CHECK(m[0] == (unsigned char)(0x11 * (slot + 1) + p) && m[a.space[p] - 1] == m[0]);
}
/* refused: a slot out of range, lists of another room, a head past it */
CHECK(!parse_arena_attach(&a, SLICES, &verts, HEAD, &idx));
CHECK(ta_list_init(&other, VERT_ROOM / 2, 16, &overrun, "verts"));
CHECK(!parse_arena_attach(&a, 0, &other, HEAD, &idx));
CHECK(!parse_arena_attach(&a, 0, &verts, VERT_ROOM + 1, &idx));
CHECK(verts.base == own_verts && idx.base == own_idx && other.base != NULL);
/* refused: a slot out of range, a list of another room, a head past it */
CHECK(!parse_arena_attach(&a, SLICES, lp, HEAD));
CHECK(ta_list_init(&other, room[PARSE_ARENA_MV_CLIP] / 2, 36, &overrun, "other"));
lp[PARSE_ARENA_MV_CLIP] = &other;
CHECK(!parse_arena_attach(&a, 0, lp, HEAD));
lp[PARSE_ARENA_MV_CLIP] = &l[PARSE_ARENA_MV_CLIP];
CHECK(!parse_arena_attach(&a, 0, lp, room[PARSE_ARENA_VERTS] + 1));
for (p = 0; p < PARSE_ARENA_PARTS; p++)
CHECK(l[p].base == own[p]);
ta_list_free(&other);
/* an overrun in the slice: the list's own flag, and its own slice */
CHECK(parse_arena_attach(&a, 1, &verts, 0, &idx));
CHECK(parse_arena_attach(&a, 1, lp, 0));
overrun = 0;
verts.cur = verts.end;
CHECK(ta_list_append(&verts, 16) == mem + parse_arena_vert_offset(&a, 1));
l[PARSE_ARENA_VERTS].cur = l[PARSE_ARENA_VERTS].end;
CHECK(ta_list_append(&l[PARSE_ARENA_VERTS], 16) == mem + parse_arena_offset(&a, 1, PARSE_ARENA_VERTS));
CHECK(overrun == 1);
parse_arena_detach(&a);
/* slices bound apart (a buffer of their own each, as OpenGL's): their
* memory, wherever it is */
/* parts bound apart: their memory, wherever it is; a part unbound,
* refused */
{
static unsigned char vmem[2][VERT_ROOM], imem[2][IDX_ROOM];
static unsigned char part[2][PARSE_ARENA_PARTS][8192];
parse_arena_t b;
CHECK(parse_arena_layout(&b, VERT_ROOM, IDX_ROOM, 2, 1) != 0);
CHECK(!parse_arena_attach(&b, 0, &verts, HEAD, &idx));
parse_arena_bind_slot(&b, 0, vmem[0], imem[0]);
parse_arena_bind_slot(&b, 1, vmem[1], imem[1]);
parse_arena_bind_slot(&b, 2, vmem[0], imem[0]); /* (no slot 2: nothing) */
CHECK(parse_arena_layout(&b, room, 2, 1) != 0);
CHECK(!parse_arena_attach(&b, 0, lp, HEAD));
for (p = 0; p < PARSE_ARENA_PARTS; p++)
{
parse_arena_bind_slot(&b, 0, p, part[0][p]);
if (p != PARSE_ARENA_MV_CLIP)
parse_arena_bind_slot(&b, 1, p, part[1][p]);
}
parse_arena_bind_slot(&b, 2, 0, part[0][0]); /* (no slot 2: nothing) */
parse_arena_bind_slot(&b, 0, PARSE_ARENA_PARTS, part[0][0]); /* (no such part: nothing) */
CHECK(!parse_arena_attach(&b, 1, lp, HEAD));
for (i = 0; i < HEAD; i++)
own_verts[i] = (unsigned char)(0x80 + i);
verts.cur = verts.base;
idx.cur = idx.base;
CHECK(parse_arena_attach(&b, 1, &verts, HEAD, &idx));
CHECK(verts.base == vmem[1] && idx.base == imem[1]);
CHECK(memcmp(vmem[1], own_verts, HEAD) == 0);
own[PARSE_ARENA_VERTS][i] = (unsigned char)(0x80 + i);
l[PARSE_ARENA_VERTS].cur = l[PARSE_ARENA_VERTS].base;
CHECK(parse_arena_attach(&b, 0, lp, HEAD));
for (p = 0; p < PARSE_ARENA_PARTS; p++)
CHECK(l[p].base == part[0][p]);
CHECK(memcmp(part[0][PARSE_ARENA_VERTS], own[PARSE_ARENA_VERTS], HEAD) == 0);
parse_arena_detach(&b);
CHECK(verts.base == own_verts && idx.base == own_idx);
CHECK(!parse_arena_attach(&b, 2, &verts, HEAD, &idx));
for (p = 0; p < PARSE_ARENA_PARTS; p++)
CHECK(l[p].base == own[p]);
CHECK(!parse_arena_attach(&b, 2, lp, HEAD));
/* more slices than there is room for: none */
CHECK(parse_arena_layout(&b, VERT_ROOM, IDX_ROOM, PARSE_ARENA_SLOTS + 1, 1) == 0);
CHECK(parse_arena_layout(&b, room, PARSE_ARENA_SLOTS + 1, 1) == 0);
CHECK(b.slot == -1);
}
ta_list_free(&verts);
ta_list_free(&idx);
for (p = 0; p < PARSE_ARENA_PARTS; p++)
ta_list_free(&l[p]);
free(mem);
if (fails)
{
+73 -71
View File
@@ -3768,7 +3768,7 @@ f38f027127d12892222127d227d1292127d33b2113662367e07726d518e35227
# The program built with -DLIVE_HEAVY (live_prog.c): a frame of many
# vertices, as a game's are, for the parse's speed
# (tools/pvr/ta_parse_bench.sh).
# (tools/pvr/ta_parse_bench.sh), and a shadow volume far off the screen.
PROGRAM_HEAVY = bytes.fromhex("""
01df02d02b40090000f0008cac0f018c020005d119206b200e40543402004227
01170b0009000900fefcffff020005d119205b200e4044340200422601160b00
@@ -3847,8 +3847,8 @@ f3620c7225840c63284326840c6118613b2127840c600b21b9931c33b8922633
f1af7362f06001882b8bf36001840288298b1fd22a21f362fa840c6213631943
3032228ff3622b840c621c611032ffe00a600840707f264ff66bf66af6690b00
f668f7af0900f5af0900f3af0900f1af0900efaf0900edaf0900ebaf0900e9af
09e0e7af04e0e5af04e0e3af04e0a8fd2b01800021100900e432018c2807018c
1480018cd832018ccc32018c00800000ffff00000ad142210471522101e109d2
09e0e7af04e0e5af04e0e3af04e0a8fd2b018000211009002433018c2807018c
1480018c1833018c0c33018c00800000ffff00000ad142210471522101e109d2
1222087212220472122207d1226001c8018d1041fa8b05d1126001c80b002900
04745fa00c745fa000093d0018745fa0626113671947014725922821ffe22a62
436300432903136001402444136019407a2001c8108943605c302a2306342907
@@ -3907,7 +3907,7 @@ c228b220b225722612238302f66ef66df66cf66bf66af6690b00f66800000080
22217bd27bd3ac9132221041fc8f047279d17ad77ad310e27221a3961c363226
1042f98f047177d177d2222104719a92222176d276d310e132221041fc8f0472
1fe174d2122274d2122274d100e002ea00e973d807e41fe58697869317e6d62f
019d230df66dd0201043058d017726657035f989f8af63616ad227536ad22033
019d230df66d10211043058d017726657035f989f8af63616ad227536ad22033
648d48e001e1160f10e168d212220472122267d267d30ce132221041fc8f0472
00e163d212220472122263d163d2222163d164d2222164d12e4164d1ffe700e3
08e2722131111042fb8f08715fd360d1122360d260d1292148977b2111135fd1
@@ -3917,14 +3917,14 @@ c228b220b225722612238302f66ef66df66cf66bf66af6690b00f66800000080
092454dcc36dc51fbda200ee52d2205335d22033978996af01e1007ce003ff7f
8001800000101f7ce00700f836010048846c5fa0f46c5fa0c0785fa00400d8ff
0800d8ff44805fa0000080003f7d1700000020000401150000007f020000df01
77df27000000100020805fa028815fa08c805fa0000000030c0010a55c33018c
77df27000000100020805fa028815fa08c805fa0000000030c0010a59c33018c
abaaaaaa88805fa017b7d138000010a500000002000080200000003004905fa0
001000a40303030374805fa000ff000000825fa080800000002006a405050505
0606060614905fa01ffc0000000006a4070707071c985fa01c9c5fa0004006a4
ffff0000c040018c11111111380000ff000018a500000080180018a54c0e00a0
2c805fa000001800a800018c0040018c000000100050018c00f0ff1f44332211
4040018c000000ff100000ff680a018c000023ac0000ffff0000feff0000fdff
5eb00000a806018c6600018cff7fffff6c00018c2433018c0041018cbd9562d4
5eb00000a806018c6600018cff7fffff6c00018c6433018c0041018cbd9562d4
62d00b4009000820028fe61f42af09005fd460d00b4005e50820018ba3a002ee
5dd8ab9b59da5dd9b3650b4a83640820018b9aa002eea1900c389038f58fb365
53d454d00b4008e50820018b8fa003ee959553d44dd00b4009000820028f10e1
@@ -3938,7 +3938,7 @@ ffff0000c040018c11111111380000ff000018a500000080180018a54c0e00a0
26d110611c6120315a8f07ee24d110611c612031568b23d110611c612031538b
00ee97aee61f95aee61f93aee61f91aee61f8faee61f8daee61f002800040040
00180010ee0009000000200cd409018c5eb00000a806018c0000210c0028210c
0000220c4c33018c000020ac000021ac0000ffff000022ac0000feff04745fa0
0000220c8c33018c000020ac000021ac0000ffff000022ac0000feff04745fa0
0000230c0c745fa0801a060018745fa0000023ac0000fdff001023ac002820ac
002821ac004022ac54aee61f52aee61f50aee61f4eaee61f4caee61f4aaee61f
48aee61f46aee61f44aee61f017993600888038f936800a1017e936807e00d48
@@ -3975,8 +3975,8 @@ fc322b51b031028d903ec7a006eee38b41d1181241d1191241d93dd80b489364
e51f2cd00b400aee0188278fe51f2ad483600b400bee20d428d00b40090028d1
10301b8fe51f27d424d00b4009000188148fe51f24d140e0fc30181000e11a10
f3656875f36421d10b41607440e3fc333a52385110320cee028de51f42ae0900
a36435a0836080004c33018c1c33018c4800018c0833018c6600018c5000018c
f2830070f38300708400018cf032018c7200018c7a00018c0000803f00000040
a36435a0836080008c33018c5c33018c4800018c4833018c6600018c5000018c
f2830070f38300708400018c3033018c7200018c7a00018c0000803f00000040
010004008005018c010024008605018c8a00018c9800018c01000c006805018c
000080bf01000080785634127605018c0b40090044d800e1122844d10b410900
82627e9110320dee088fe51ff36440d00b4068740788138f00eee51ff2ad0900
@@ -3989,7 +3989,7 @@ f0ade51feeade51fecade51feaade51fe8ade51fe6ade51fe4ade51fe2ade51f
10e3d6af081fd4af081fd2af081f1043248924666c6604677c677036f789f6af
871f8001115409004440018c2c05018c4005018cc8805fa00c06018c00695fa0
80841e003c06018c4000a0ff9040018c7040018c018200001000a0ff6ed22062
282203890192230209001a166bd2226210711032228df75ee82e018f03eee71f
282203890192230209005a166bd2226210711032228df75ee82e018f03eee71f
67d268d112220171111267d100e332213111321133113411351164d732275fd3
2223136504731223047304e66223a893322710715bd004e813a004e35cd11261
5031d98ff75e5bd112611821d48ff75e56d1126002c8d38fe82eceaf09001043
@@ -4009,7 +4009,7 @@ e61f314420010002000383001f0fff0077772c01a10f09008040018c1000a0ff
1a0013670837d59eec3771230172027361714632ec8f85315123017202736032
f78f617100e16cd21222047212220472c193322204721fe332220472bc933222
04721222047212220472122263d1b4922221047160e2222161d100e0ae9500e6
ad97ad935fd25630d62f019d230df66de413612101707030f58f027100e15ad2
ad97ad935fd25630d62f019d230df66d2414612101707030f58f027100e15ad2
12220472122204729993322204721fe332220472909332220472122204721222
0472122204728c933222047248e3322288924ed3222304732223047322230473
2223047322234ad212220472122249d17992222148d600e7769048d475987593
@@ -4017,14 +4017,14 @@ ad97ad935fd25630d62f019d230df66de413612101707030f58f027100e15ad2
87021a022831629eec31112601771043e68f027600e13ad21222047212220472
4d93322204721fe3322204724493322204724d933222047212220472122231d1
3b922221047160e22221d87141922221f65007e11d401fcb40e2fc32061200ee
eb1fee1fed1fffeeec1f00eee91f3ea700e8188d5a884d8f648823d12a922221
0190230083606c1220d10b4102e4ffa109001ed10b4103e4faa109001bd10b41
04e4f5a109001ad115922221019023008360401230f800011f3c1f0fff070010
eb1fee1fed1fffeeec1f00eee91f4ca700e8188d5a884d8f648823d12a922221
019023008360ac1220d10b4102e4ffa109001ed10b4103e4faa109001bd10b41
04e4f5a109001ad115922221019023008360801230f800011f3c1f0fff070010
70170f0f00190242ff0fcf07011019fc00780342e003e07f040070a0240070a0
000082a090e80000840070a0ac0070a0c00070a0800070a0000083a06b6f4606
040170a0240170a01c985fa0e405018c10905fa002890c911038138b06d107d2
222183606488178b05d10392222113a00900c8001f7c0900000070a001c20000
1c9c5fa0e791103803890190230083608c1173d173d2222173d174dc122c74d1
1c9c5fa0e79110380389019023008360cc1173d173d2222173d174dc122c74d1
126340e2fc32331272dee2644412c265551201e2222120e1122e6fd1122c6fd1
6fd612266fd712276fd170d0122070d1141f131f00e9921f911f6ed2222f6edd
ba9700e66dd50b4d00e46ddbb41fb31f921f911f6bd1122f6bd700e667d50b4d
@@ -4050,10 +4050,10 @@ c41f61d1131fb21f60d1111fa22f60d760d5b7940b4900e6c41f5fd1131fb21f
ffe700e65ad50b4900e45ad1141f5ad1131f5ad1121f5ad1111fa22fffe759d6
59d50b4908e459d159d2222159d25ad332220472e222047200e33222047257d3
3222047232220472322204723222830100e048dd52dc13634edb52da52d953d4
00e253d563a104e11638018b31a7836050d151d2222151d1ffe2222150d10b41
090050d110600fc90688018be0a409004dd1126118211f894cd1126118211b8f
0820028d09e191a501e240e2fc321e121f1247d1126004e700e600e5f3640b40
787478e0fe011821028d01e241d1222141d2226101711222bfa483603fd12cae
00e253d563a104e11638018b51a7836050d151d2222151d1ffe2222150d10b41
090050d110600fc90688018beea409004dd1126118211f894cd1126118211b8f
0820028d09e1b1a501e240e6fc361e161f1647d1126004e700e600e5f3640b40
787478e0fe011821028d01e241d1222141d2226101711222cda483603fd12cae
09003fd122213fd2222c32d132d22221b41fb31f921f911f2bd1122f3ad700e6
3ad50b4d00e4922a22d292220472922204729222047292220472922204729222
04729222830a25d1ffe2222187ae09002fd111611d612fd00031f7892ed101e2
@@ -4093,67 +4093,69 @@ b22a622d322be22c53d69226fc701220fc7422240c769226830ab22a5ad6622d
38d79227830a00e300e2c36b636affe9736421a004e5236740d141dc236641dd
db2725dd722d26de022e27d0c2201ad7722b29dc122c29d76227922a2224830d
122d622e9220222b222c2227222a2224830d10456c8d017302e1336002c8028d
3921aea401c801c801896ba403882ed01821d08f13672adcd1af13662ad027d1
3921cea401c801c801898ba403882ed01821d08f13672adcd1af13662ad027d1
2adcccaf1366800000006b430000f04100005743000020410000003f00c00034
00208020d40e018c00005c4200000c4200c0003600008020000000e008000080
040000e0000000c0080000e0002480200c0000e000c80088100000e0140000e0
180000e01c0000e00000f0420000e041000050420000004300002043080000f0
0004802000002443000040430000604300008042c8000080000200300000803f
00005643c80000e00000484300006c43f391122f30e77ad67ad57bde0b4e00e4
d36a00e9922d047d922df87c922c77d0922077d1922177d2922277d3922377d4
9224830a76d577dbb11f77d1122f77de77d753660b4e00e4b11f76d1122f76d7
76d677d50b4e00e476d1122a922d922c66d5922502e266d6222606e165d71227
65d0222065d21222830ab11f6cd36ed76ed66fd56fd40b4e322f922a922d922c
5ad492245ad592255ad692265ad792275ade922e830a68d0041f68d1131f68d1
121f68d2211f68dee22f68db68d669d569d40b4bffe760d3341f68d1131f60d4
421f67d1111fe22f66d662d562d40b4bffe7922a922d922c44d5922544d69226
44d7922744d0922044d19221830a5ed2241f54d3331f5dd4421f5dd5511f5dd6
622f5dd75dd55ed40b4b00e656d7741f5cd0031f55d1121f5bd2211f5bd3322f
5bd756d556d40b4b00e65794422f59d652d553d42cd00b4010e7922a922d922c
2ad192212ad292222ad392232ad492242ad59225830a50d150d2222150d1141f
50d1131f50d1121f50d1111f50d1122f50d700e61bd50b4b00e428d6641f4ed1
131f40d7721f4dd1111fe22f4cd74dd524940b4b00e6922a922d922c13de922e
13d0922013d1922113d2922213d39223830a45d4422f45de45d746d646d547d4
0b4e090040d5522f45d746d646d547d40b4e090011d68ba0641f000180000900
302010ff00008020f00b018c0c0000e0100000e0140000e0180000e01c0000e0
0000a0420000403f0000c842a40d018c0000704300006f430000744300005243
00005c43000000200000004300004443000080420000020000005c4200006843
0000f041000048430000003fd40e018c00c40030000090200800000400008d43
00007a4300c6003000002a430000024300000c439a99193fff00008000009094
00000002000034430000f0429a99993e0000ff801020308060815fa000000080
0000d84200008c420000be42000020423333333fffff00ff0000964300008043
ffffff80000090806666663f840e018c0000d442000082420000c24200003442
00004d4300009143000039430000874369d7731f69dee21f69d0011f69d1122f
69d76ad56ad40b4b00e66ad2241fe31fe21f69d3311f69d4422f69d763d564d4
0b4b00e6922a922d922c66d5922566d6922666d7922766de922e66d09220830a
65d1ffe22221a4911038018946ab090062d263d1226001c8018d1041fa8b61d1
61d2222161d162d22221047161d22221047161d2222104714dd2222104715fd2
22215fd35fd220e1222301721041fb8f04735dd15dd22221147101e222211362
4fd1226001c8018d1041fa8b19ab090057d222610171122283603c88028f4288
f6a00900048ffb5ee82e018bf5a0090050d10b41090050d10b4110e44fd11262
83639c7356911633028ff951f3a009002831fc5e163e008b1c1ffd5e123e0089
1d1ffe5e1c3eee1f291f00e148e0fe022822038d182101894fa10900028d3fe1
3fa1fd521638018befa08360017883603c88028f3ce1d1a809001638018bb8a8
46881e88028f2d88bea80900028f0f88bfa809000189e1a1836031d10b4101e4
836208422c3208428c32184209428c321191192283603fc9036108410c311841
28d33c3128d321211043fc8f0271a5aa090096009500ff7f0000484300003443
00000c439a99193fff0000800000909400000002000052430000f0429a99993e
0000ff800c0000e0100000e0140000e0180000e01c0000e014805fa0186c5fa0
00005643c80000e00000484300006c43f291122f30e779d679d57ade0b4e00e4
79d1141f79d0031f79d1121f79d1111f79d1122f79dbffe771d5de940b4b00e6
d36a00e9922d047d922df87c922c74d2922274d3922374d4922474d5922574d6
9226830a73dee11f73d7722f73d774d674d575d00b4000e4e11f6fd1122f73d7
6fd6636570d20b4200e4e11f70d1122f70d771d671d56cd30b4300e470d1122a
922d922c5ed4922402e25ed5222506e15dd612265dd722275dd01220830ae11f
66d168d768d669d569d45fd20b42122f922a922d922c52d3922352d4922452d5
922552d6922652d79227830a61dee41f61d1131f61dee21f61d0011f46d1122f
60d661d561d40b4bffe75ad2241f60d1131fe21f4bd3311f3fd4422f5dd65ad5
5ad40b4bffe7922a922d922c3cd592253cd692263cd792273cde922e3cd09220
830a55dee41f4ed1131f54d2221f54d3311f54d4422f54d754d555d40b4b00e6
e41f54dee31f4dd5521f53d6611f53d7722f53d74dd54ed40b4b00e63d90022f
50d64ad54ad41fd10b4110e7922a922d922c23d2922223d3922323d4922423d5
922523d69226830a47d148d2222148d1141f48d1131f48d1121f48d1111f48d1
122f48d700e60ed50b4b00e422d7741f45d1131fe21f45d1111f0fd0022f44d7
44d50a940b4b00e6922a922d922c0cd192210cd280a0090000018000302010ff
00008020f00b018c0000c042000091430000a842000066430000003fd40e018c
0c0000e0100000e0140000e0180000e01c0000e00000403f0000c842286b6e4e
0000a04200007a43a40d018c0000704300006f43000074430000524300005c43
000000200000004300004443000080420000020000005c42000068430000f041
0000484300c40030000090200800000400008d4300c6003000002a4300000243
00000c439a99193fff0000800000909400000002000034430000f0429a99993e
0000ff801020308060815fa0000000800000d84200008c420000be4200002042
3333333fffff00ff0000964300008043ffffff8000009080922276d3922376d4
922476d59225830a75d6622f75d776d676d577d477d00b40090071d176d777d6
77d578d473d20b42122f77d3341f77d4431fe21f76d5511f76d6622f76d777d5
77d40b4b00e670d7741fe31fe21f75dee11f75d0022f75d770d571d40b4b00e6
922a922d922c72d1922172d2922259d3922359d4922459d59225830a6ed1ffe2
2221a4911038018938ab09006bd26cd1226001c8018d1041fa8b6ad16ad22221
6ad16bd2222104716ad2222104716ad2222104715ad22221047168d2222168d3
68d220e1222301721041fb8f047366d166d22221147101e22221136258d12260
01c8018d1041fa8b0bab090060d222610171122283603c88028f428808a10900
048ffb5ee82e018b07a1090059d10b41090059d10b4110e458d1126283639c73
56911633028ff95105a109002831fc5e163e008b1c1ffd5e123e00891d1ffe5e
1c3eee1f291f00e148e0fe022822038d1821018961a10900028d3fe151a1fd52
1638018b01a18360017883603c88028f3ce1c3a809001638018baaa846881e88
028f2d88b0a80900028f0f88b1a809000189f3a183603ad10b4101e483620842
2c3208428c32184209428c321191192283603fc9036108410c31184131d33c31
31d321211043fc8f027197aa090096009500ff7f140000e0180000e01c0000e0
6666663f0000d442000082420000c24200003442840e018c00004d4300009143
0000394300008743000052430000484300000c439a99193fff00008000009094
000000020000f0429a99993e0000ff800c0000e0100000e014805fa0186c5fa0
80841e0000e100ac7856341200e000ac2200008000e1000c0c01002200000065
14e000ac0001dec0046c5fa000e0000c1080018c0c06018c4c06018c0c00d8ff
e405018c000000a500a0000083d1222100e183d210220c720ae3302204721022
80d1a0e2202180d280d1206008c8018f1041fa8b7cd1106008c8238d13e26871
212100e221210ae3312121212121212175d276d1206008c8018f1041fa8b72d1
106008c811896871116211601162116211616cd220620fc918401c610b216cd2
0aaf12226bd1faaf09006ad1f7af090069d00b4000e404a00b1f67d00b4001e4
0b1f66d10b41090065d10b4110e465d112621aaf291faa9110381f8ff55ee82e
f8ae12226bd1faaf09006ad1f7af090069d00b4000e404a00b1f67d00b4001e4
0b1f66d10b41090065d10b4110e465d1126208af291faa9110381f8ff55ee82e
1c8961d1a493322160d1ec31291f60d2122260d112611821078d836022625ed1
1032038f01c8d7a00ae201c8018bf6a009005ad15ad2122209af017887911038
1032038f01c8d7a00ae201c8018bf6a009005ad15ad21222f7ae017887911038
d78fce71fd53fc5ee8331633268dfe5e54d3ec337d911633268d44e0fe000820
278df65e48d175933221291ffe5e4dd2ec326e9116325e8d44e0fe0008205d8f
f65ee82e5d8f48e0fe0008205c8fff5ee82e278df85044d1b9afec313ad15a93
322142d1b3af291f37d155933221ddaf291fe82e0e8d58e033d1fe000221291f
fd52fc5ee8324491163238d19f8dfe5ecdaf0900291fa9ae01e12bd13d922221
fd52fc5ee8324491163238d19f8dfe5ecdaf0900291f97ae01e12bd13d922221
efaffd520820038df75e31d18faf0c31e82e02892fd18aafec31fa5ee82e0289
2dd184afec31fb5ee82e038d40e02bd17dafec3101e1fe021732038f40e028d1
75af2c31fe00018802891bd16faf090024d16caf090024d169af090023d166af
@@ -4164,15 +4166,15 @@ efaffd520820038df75e31d18faf0c31e82e02892fd18aafec31fa5ee82e0289
0007d0ba4d4d0d600300d0ba0400d0ba0500d0ba0600d0ba5bd11261c9712631
12895ad112611821138959d11262a9911032028957d108a0090057d112611821
0a8956d101a0090055d156d212220caf836055d1f9af090054d1f6af090054d1
08af090029071ce61821028d6d4795ab090050d050dc51d661ab090003c90388
0189d1a83fe13fe11638028d836018ae836201c8018b01a9090049d1019c230c
090058ee47d222621071203102ee068fe71f45d11261503102ee048de71f0192
23020900dce90191230109001aea3360038829071ce11d473cd038d136dc2eab
1366f48f182139d053ab09004121017002715630058f20c8d62f019d230df66d
12ecf38f2364f1af336401a093628362212101700271a630f78f0388f78d4630
08af090029071ce61821028d6d4775ab090050d050dc51d641ab090003c90388
0189b1a83fe13fe11638028d836006ae836201c8018be1a8090049d1019c230c
090018ee47d222621071203102ee068fe71f45d11261503102ee048de71f0192
230209009ce9019123010900dae93360038829071ce11d473cd038d136dc0eab
1366f48f182139d033ab09004121017002715630058f20c8d62f019d230df66d
d2ebf38f2364f1af336401a093628362212101700271a630f78f0388f78d4630
2c8f66302c8b312101705888f38f027127d12892222127d227d1292127d33b21
13662367e07726d518e352271043fc8f047724d30ce77223fc7310e7722322d7
08e3722101771043fb8f047183061ed700e101e60195230508e3d4dec8af5362
08e3722101771043fb8f047183061ed700e101e60195230508e394dec8af5362
c6af7362280680000c80018c0880018c0480018c030cd0ba0080018c040cd0ba
010cd0ba4840018c020cd0ba9d5a0d60000020000000484300006c430000803f
000040001000a0ff1400a0ff000070431c815fa0e040018ce0ffff03000000e0
+14 -2
View File
@@ -738,8 +738,9 @@ static u32 keep_done, keep_age;
#ifdef LIVE_HEAVY
/* With -DLIVE_HEAVY: a frame of many vertices, as a game's are, for the
* parse's speed (tools/pvr/ta_parse_bench.sh): Gouraud strips, tiny, in
* the bottom left corner. A whole number's float, made without the FPU
* the program has no code for. */
* the bottom left corner; and a shadow volume reaching far off the screen
* (below). A whole number's float, made without the FPU the program has
* no code for. */
static u32 int_float(u32 n)
{
u32 e = 0;
@@ -894,9 +895,20 @@ static void ta_scene(void)
#endif
#ifdef LIVE_HEAVY
ta_heavy(0, TSP_PLAIN, 0xFF102030, 48, 256);
/* a white polygon that takes shadows, half under the volume far off the
* screen (after the list) */
ta_quad(TA_SHADOW, TSP_PLAIN, 0, 0xFFFFFFFF, F(0.5f), F(230.0f), F(84.0f), F(290.0f), F(96.0f));
#endif
ta_send(0, 0, 0, 0, 0, 0, 0, 0); /* end of the opaque list */
#ifdef LIVE_HEAVY
/* A volume reaching a billion pixels off the screen to the right, as a
* game's shadow near the eye does: its triangles are cut to a square
* about the screen before they are drawn (core/rend/modvol_clip.h). The
* first, so that the triangles of the volumes after it are elsewhere in
* the list of those cut than in the volumes' own. */
ta_volume_part(0, F(250.0f), F(80.0f), F(1.0e9f), F(100.0f), F(0.75f));
#endif
#ifdef LIVE_CULL
ta_volume_culled(2, F(4.0f), F(146.0f), F(44.0f), F(174.0f), F(0.75f));
ta_volume_culled(3, F(4.0f), F(174.0f), F(44.0f), F(200.0f), F(0.75f));
+4 -3
View File
@@ -8,7 +8,8 @@
# copied; told that memory is slow to read (VKH_UNCACHED) the core copies
# them, as ever - and the pictures of the two are the same, byte for byte:
# the test discs' plain one, heavy one (more strips than the copy's first
# guess holds: tools/threads/live_disc.py --heavy) and DMA one, with each
# guess holds: tools/threads/live_disc.py --heavy), DMA one and the one with
# modifier volumes (--cull, whose triangles are drawn from there too), with each
# renderer, threaded rendering on and off, and with a temporal upscaler
# on the frontend (its motion vectors drawn from the same geometry).
#
@@ -30,7 +31,7 @@ ${CC:-cc} -O1 -g -Wall -I./core/libretro-common/include -I./core/deps/khronos \
core/rend/hdr/hdr_output.c core/rend/hdr/hdr_transform.c core/rend/hdr/hdr_aces2.c \
core/rend/hdr/hdr_libretro.c core/rend/hdr/hdr_display.c -ldl -lm -lpthread
# (a directory a disc: their tracks' names are the same)
for disc in plain heavy dma; do
for disc in plain heavy dma cull; do
mkdir -p "$WORK/$disc"
case $disc in
plain) python3 tools/threads/live_disc.py "$WORK/$disc/test.gdi" ;;
@@ -56,7 +57,7 @@ run() {
fi
}
for disc in plain heavy dma; do
for disc in plain heavy dma cull; do
for r in per-triangle per-pixel per-triangle-upscaler per-pixel-upscaler; do
unset VKH_UPSCALER
case $r in