Files
parallel-dc/core/rend/sorter.cpp
T
LibretroAdmin 85fc7c39f3 settings that only ever had one value are that value
A number of settings are given a value once, in LoadSettings(), and
never another: there is no core option behind them and nothing else
writes them. Each is replaced by its value where it was read, and the
branch that value never took is removed.

- dynarec.idleskip, always on: the idle loop detection in the block
  decoder is unconditional, and the branch for it being off is gone.
- dynarec.unstable_opt, always off: the store queue shortcut in the
  ARM recompiler that it guarded is removed.
- pvr.MaxThreads, always 3: a constant in the texture upscaler.
- pvr.subdivide_transp, always off, and only read inside an #if 0
  block of the triangle sorter, which goes with it.
- rend.Clipping, always on: tile clipping no longer asks.
- rend.AutoExtraDepthScale, always on.
- debug.SerialConsole, always off: the serial port's echo to stdout.
- imgread.PatchRegion, never set: the two functions that would have
  rewritten a disc's region strings returned at once, and are removed
  with the calls to them.
- validate.OpenGlChecks and pvr.Emulation.zMin/zMax were written and
  never read.

LoadSettings() also loses a block for builds that are not libretro,
which this core is not, and which set a field that no longer exists.

core/rend/soft/softrend.cpp, a software renderer that used one of
these settings, was not in any makefile. It is deleted, and its
declaration with it.
2026-10-06 12:08:50 +02:00

383 lines
7.6 KiB
C++

/*
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include "sorter.h"
struct IndexTrig
{
u32 id[3];
u16 pid;
f32 z;
};
#if 0
static float min3(float v0, float v1, float v2)
{
return std::min(std::min(v0,v1),v2);
}
static float max3(float v0, float v1, float v2)
{
return std::max(std::max(v0,v1),v2);
}
#endif
static float minZ(const Vertex *v, const u32 *mod)
{
return std::min(std::min(v[mod[0]].z, v[mod[1]].z), v[mod[2]].z);
}
static bool operator<(const IndexTrig& left, const IndexTrig& right)
{
return left.z<right.z;
}
static bool operator<(const PolyParam& left, const PolyParam& right)
{
/* put any condition you want to sort on here */
return left.zvZ<right.zvZ;
//return left.zMin<right.zMax;
}
void SortPParams(int first, int count)
{
if (pvrrc.verts.used() == 0 || count <= 1)
return;
Vertex* vtx_base=pvrrc.verts.head();
u32* idx_base = pvrrc.idx.head();
PolyParam* pp = &pvrrc.global_param_tr.head()[first];
PolyParam* pp_end = pp + count;
while(pp!=pp_end)
{
if (pp->count<2)
{
pp->zvZ=0;
}
else
{
u32* idx = idx_base + pp->first;
Vertex* vtx=vtx_base+idx[0];
Vertex* vtx_end=vtx_base + idx[pp->count-1]+1;
u32 zv=0xFFFFFFFF;
while(vtx!=vtx_end)
{
zv = std::min(zv,(u32&)vtx->z);
vtx++;
}
pp->zvZ=(f32&)zv;
}
pp++;
}
std::stable_sort(pvrrc.global_param_tr.head() + first, pvrrc.global_param_tr.head() + first + count);
}
const static Vertex *vtx_sort_base;
#if 0
/*
Per triangle sorting experiments
*/
//approximate the triangle area
float area_x2(Vertex* v)
{
return 2/3*fabs( (v[0].x-v[2].x)*(v[1].y-v[0].y) - (v[0].x-v[1].x)*(v[2].y-v[0].y)) ;
}
//approximate the distance ^2
float distance_apprx(Vertex* a, Vertex* b)
{
float xd=a->x-b->x;
float yd=a->y-b->y;
return xd*xd+yd*yd;
}
//was good idea, but not really working ..
bool Intersect(Vertex* a, Vertex* b)
{
float a1=area_x2(a);
float a2=area_x2(b);
float d = distance_apprx(a,b);
return (a1+a1)>d;
}
//root for quick-union
u16 rid(std::vector<u16>& v, u16 id)
{
while(id!=v[id]) id=v[id];
return id;
}
struct TrigBounds
{
float xs,xe;
float ys,ye;
float zs,ze;
};
//find 3d bounding box for triangle
TrigBounds bound(Vertex* v)
{
TrigBounds rv = { std::min(std::min(v[0].x,v[1].x),v[2].x), std::max(std::max(v[0].x,v[1].x),v[2].x),
std::min(std::min(v[0].y,v[1].y),v[2].y), std::max(std::max(v[0].y,v[1].y),v[2].y),
std::min(std::min(v[0].z,v[1].z),v[2].z), std::max(std::max(v[0].z,v[1].z),v[2].z),
};
return rv;
}
//bounding box 2d intersection
bool Intersect(TrigBounds& a, TrigBounds& b)
{
return ( !(a.xe<b.xs || a.xs>b.xe) && !(a.ye<b.ys || a.ys>b.ye) /*&& !(a.ze<b.zs || a.zs>b.ze)*/ );
}
bool operator<(const IndexTrig &left, const IndexTrig &right)
{
/*
TrigBounds l=bound(vtx_sort_base+left.id);
TrigBounds r=bound(vtx_sort_base+right.id);
if (!Intersect(l,r))
{
return true;
}
else
{
return (l.zs + l.ze) < (r.zs + r.ze);
}*/
return minZ(&vtx_sort_base[left.id])<minZ(&vtx_sort_base[right.id]);
}
//Not really working cuz of broken intersect
bool Intersect(const IndexTrig &left, const IndexTrig &right)
{
TrigBounds l=bound(vtx_sort_base+left.id);
TrigBounds r=bound(vtx_sort_base+right.id);
return Intersect(l,r);
}
#endif
//are two poly params the same?
static bool PP_EQ(const PolyParam *pp0, const PolyParam *pp1)
{
return (pp0->pcw.full & PCW_DRAW_MASK) == (pp1->pcw.full & PCW_DRAW_MASK) && pp0->isp.full == pp1->isp.full
&& pp0->tcw.full == pp1->tcw.full && pp0->tsp.full == pp1->tsp.full && pp0->tileclip == pp1->tileclip;
}
static void fill_id(u32 *d, const Vertex *v0, const Vertex *v1, const Vertex *v2, const Vertex *vb)
{
d[0] = (u32)(v0 - vb);
d[1] = (u32)(v1 - vb);
d[2] = (u32)(v2 - vb);
}
void GenSorted(int first, int count, std::vector<SortTrigDrawParam>& pidx_sort, std::vector<u32>& vidx_sort)
{
u32 tess_gen=0;
pidx_sort.clear();
if (pvrrc.verts.used() == 0 || count == 0)
return;
const Vertex * const vtx_base = pvrrc.verts.head();
const u32 * const idx_base = pvrrc.idx.head();
const PolyParam * const pp_base = &pvrrc.global_param_tr.head()[first];
const PolyParam *pp = pp_base;
const PolyParam * const pp_end = pp + count;
while (pp->count == 0 && pp < pp_end)
pp++;
if (pp == pp_end)
return;
vtx_sort_base=vtx_base;
static u32 vtx_cnt;
int vtx_count = pvrrc.verts.used() - idx_base[pp->first];
if ((u32)vtx_count > vtx_cnt)
vtx_cnt=vtx_count;
#if PRINT_SORT_STATS
printf("TVTX: %d || %d\n",vtx_cnt,vtx_count);
#endif
if (vtx_count<=0)
return;
//make lists of all triangles, with their pid and vid
static std::vector<IndexTrig> lst;
lst.resize(vtx_count*4);
int pfsti=0;
while(pp!=pp_end)
{
u32 ppid = (u32)(pp - pp_base);
if (pp->count>2)
{
const u32 *idx = idx_base + pp->first;
u32 flip = 0;
for (u32 i = 0; i < pp->count - 2; i++)
{
const Vertex *v0, *v1;
if (flip)
{
v0 = vtx_base + idx[i + 1];
v1 = vtx_base + idx[i];
}
else
{
v0 = vtx_base + idx[i];
v1 = vtx_base + idx[i + 1];
}
const Vertex *v2 = vtx_base + idx[i + 2];
{
fill_id(lst[pfsti].id,v0,v1,v2,vtx_base);
lst[pfsti].pid= ppid ;
lst[pfsti].z = minZ(vtx_base,lst[pfsti].id);
pfsti++;
}
flip ^= 1;
}
}
pp++;
}
u32 aused=pfsti;
lst.resize(aused);
//sort them
#if 1
std::stable_sort(lst.begin(),lst.end());
//Merge pids/draw cmds if two different pids are actually equal
if (true)
{
for (u32 k=1;k<aused;k++)
{
if (lst[k].pid!=lst[k-1].pid)
{
if (PP_EQ(&pp_base[lst[k].pid],&pp_base[lst[k-1].pid]))
{
lst[k].pid=lst[k-1].pid;
}
}
}
}
#endif
#if 0
//tries to optimise draw calls by reordering non-intersecting polygons
//uber slow and not very effective
{
int opid=lst[0].pid;
for (int k=1;k<aused;k++)
{
if (lst[k].pid!=opid)
{
if (opid>lst[k].pid)
{
//MOVE UP
for (int j=k;j>0 && lst[j].pid!=lst[j-1].pid && !Intersect(lst[j],lst[j-1]);j--)
{
swap(lst[j],lst[j-1]);
}
}
else
{
//move down
for (int j=k+1;j<aused && lst[j].pid!=lst[j-1].pid && !Intersect(lst[j],lst[j-1]);j++)
{
swap(lst[j],lst[j-1]);
}
}
}
opid=lst[k].pid;
}
}
#endif
//re-assemble them into drawing commands
vidx_sort.resize(aused*3);
int idx=-1;
for (u32 i=0; i<aused; i++)
{
int pid=lst[i].pid;
u32* midx = lst[i].id;
vidx_sort[i*3 + 0]=midx[0];
vidx_sort[i*3 + 1]=midx[1];
vidx_sort[i*3 + 2]=midx[2];
if (idx!=pid /* && !PP_EQ(&pp_base[pid],&pp_base[idx]) */ )
{
SortTrigDrawParam stdp = { pp_base + pid, i * 3, 0 };
if (idx!=-1)
{
SortTrigDrawParam& last = pidx_sort.back();
last.count = stdp.first - last.first;
}
pidx_sort.push_back(stdp);
idx=pid;
}
}
if (!pidx_sort.empty())
{
SortTrigDrawParam& last = pidx_sort.back();
last.count = aused * 3 - last.first;
}
#if PRINT_SORT_STATS
printf("Reassembled into %d from %d\n",pidx_sort.size(),pp_end-pp_base);
#endif
if (tess_gen) DEBUG_LOG(RENDERER, "Generated %.2fK Triangles !", tess_gen / 1000.0);
}