2019-10-04 10:22:18 +00:00
|
|
|
/*
|
|
|
|
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 "sorter.h"
|
2021-05-31 17:44:55 +00:00
|
|
|
#include "hw/pvr/Renderer_if.h"
|
2020-03-28 16:58:01 +00:00
|
|
|
#include <algorithm>
|
2022-01-25 14:37:04 +00:00
|
|
|
#include <glm/glm.hpp>
|
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
2019-10-04 10:22:18 +00:00
|
|
|
|
|
|
|
struct IndexTrig
|
|
|
|
{
|
|
|
|
u32 id[3];
|
|
|
|
u16 pid;
|
|
|
|
f32 z;
|
|
|
|
};
|
|
|
|
|
2019-10-25 20:47:20 +00:00
|
|
|
static float minZ(const Vertex *v, const u32 *mod)
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2020-03-29 17:29:14 +00:00
|
|
|
return std::min(std::min(v[mod[0]].z, v[mod[1]].z), v[mod[2]].z);
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
|
2019-10-25 20:47:20 +00:00
|
|
|
static bool operator<(const IndexTrig& left, const IndexTrig& right)
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2022-01-29 17:39:38 +00:00
|
|
|
return left.z < right.z;
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
|
2019-10-25 20:47:20 +00:00
|
|
|
static bool operator<(const PolyParam& left, const PolyParam& right)
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2022-01-29 17:39:38 +00:00
|
|
|
return left.zvZ < right.zvZ;
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
|
2022-02-13 20:01:45 +00:00
|
|
|
static float getProjectedZ(const Vertex *v, const float *mat)
|
2022-01-25 14:37:04 +00:00
|
|
|
{
|
2022-02-13 20:01:45 +00:00
|
|
|
// -1 / z
|
|
|
|
return -1 / (mat[2] * v->x + mat[1 * 4 + 2] * v->y + mat[2 * 4 + 2] * v->z + mat[3 * 4 + 2]);
|
2022-01-25 14:37:04 +00:00
|
|
|
}
|
|
|
|
|
2019-10-04 10:22:18 +00:00
|
|
|
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;
|
|
|
|
|
2022-01-29 17:39:38 +00:00
|
|
|
if (pp->isNaomi2())
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2022-01-26 21:15:10 +00:00
|
|
|
glm::mat4 mvMat = pp->mvMatrix != nullptr ? glm::make_mat4(pp->mvMatrix) : glm::mat4(1);
|
2022-02-11 14:54:18 +00:00
|
|
|
glm::vec3 min{ 1e38f, 1e38f, 1e38f };
|
|
|
|
glm::vec3 max{ -1e38f, -1e38f, -1e38f };
|
2022-01-25 14:37:04 +00:00
|
|
|
while (vtx != vtx_end)
|
|
|
|
{
|
2022-02-11 14:54:18 +00:00
|
|
|
glm::vec3 pos{ vtx->x, vtx->y, vtx->z };
|
2022-01-25 14:37:04 +00:00
|
|
|
min = glm::min(min, pos);
|
|
|
|
max = glm::max(max, pos);
|
|
|
|
vtx++;
|
|
|
|
}
|
2022-02-11 14:54:18 +00:00
|
|
|
glm::vec4 center((min + max) / 2.f, 1);
|
|
|
|
glm::vec4 extents(max - glm::vec3(center), 0);
|
2022-01-25 14:37:04 +00:00
|
|
|
// transform
|
|
|
|
center = mvMat * center;
|
|
|
|
glm::vec3 extentX = mvMat * glm::vec4(extents.x, 0, 0, 0);
|
|
|
|
glm::vec3 extentY = mvMat * glm::vec4(0, extents.y, 0, 0);
|
|
|
|
glm::vec3 extentZ = mvMat * glm::vec4(0, 0, extents.z, 0);
|
|
|
|
// new AA extents
|
2022-02-11 14:54:18 +00:00
|
|
|
glm::vec3 newExtent = glm::abs(extentX) + glm::abs(extentY) + glm::abs(extentZ);
|
|
|
|
|
|
|
|
min = glm::vec3(center) - newExtent;
|
|
|
|
max = glm::vec3(center) + newExtent;
|
2022-01-25 14:37:04 +00:00
|
|
|
|
2022-02-11 14:54:18 +00:00
|
|
|
// project
|
|
|
|
pp->zvZ = -1 / std::min(min.z, max.z);
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
2022-01-25 14:37:04 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
u32 zv=0xFFFFFFFF;
|
|
|
|
while(vtx!=vtx_end)
|
|
|
|
{
|
|
|
|
zv = std::min(zv, (u32&)vtx->z);
|
|
|
|
vtx++;
|
|
|
|
}
|
2019-10-04 10:22:18 +00:00
|
|
|
|
2022-01-25 14:37:04 +00:00
|
|
|
pp->zvZ=(f32&)zv;
|
|
|
|
}
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
pp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::stable_sort(pvrrc.global_param_tr.head() + first, pvrrc.global_param_tr.head() + first + count);
|
|
|
|
}
|
|
|
|
|
2019-10-25 20:47:20 +00:00
|
|
|
const static Vertex *vtx_sort_base;
|
2019-10-04 10:22:18 +00:00
|
|
|
|
2019-10-25 20:47:20 +00:00
|
|
|
static void fill_id(u32 *d, const Vertex *v0, const Vertex *v1, const Vertex *v2, const Vertex *vb)
|
2020-03-27 12:03:49 +00:00
|
|
|
{
|
|
|
|
d[0] = (u32)(v0 - vb);
|
|
|
|
d[1] = (u32)(v1 - vb);
|
|
|
|
d[2] = (u32)(v2 - vb);
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
|
2020-03-29 17:29:14 +00:00
|
|
|
void GenSorted(int first, int count, std::vector<SortTrigDrawParam>& pidx_sort, std::vector<u32>& vidx_sort)
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
|
|
|
u32 tess_gen=0;
|
|
|
|
|
|
|
|
pidx_sort.clear();
|
|
|
|
|
2020-03-31 19:09:42 +00:00
|
|
|
if (pvrrc.verts.used() == 0 || count == 0)
|
2019-10-04 10:22:18 +00:00
|
|
|
return;
|
|
|
|
|
2020-07-11 15:38:41 +00:00
|
|
|
const Vertex * const vtx_base = pvrrc.verts.head();
|
|
|
|
const u32 * const idx_base = pvrrc.idx.head();
|
2019-10-04 10:22:18 +00:00
|
|
|
|
2020-07-11 15:38:41 +00:00
|
|
|
const PolyParam * const pp_base = &pvrrc.global_param_tr.head()[first];
|
2019-10-25 20:47:20 +00:00
|
|
|
const PolyParam *pp = pp_base;
|
2020-07-11 15:38:41 +00:00
|
|
|
const PolyParam * const pp_end = pp + count;
|
|
|
|
while (pp->count == 0 && pp < pp_end)
|
|
|
|
pp++;
|
|
|
|
if (pp == pp_end)
|
|
|
|
return;
|
2019-10-04 10:22:18 +00:00
|
|
|
|
|
|
|
vtx_sort_base=vtx_base;
|
|
|
|
|
|
|
|
static u32 vtx_cnt;
|
|
|
|
|
2020-03-27 12:03:49 +00:00
|
|
|
int vtx_count = pvrrc.verts.used() - idx_base[pp->first];
|
2020-07-11 15:38:41 +00:00
|
|
|
if ((u32)vtx_count > vtx_cnt)
|
|
|
|
vtx_cnt = vtx_count;
|
2019-10-04 10:22:18 +00:00
|
|
|
|
|
|
|
#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
|
2020-03-29 17:29:14 +00:00
|
|
|
static std::vector<IndexTrig> lst;
|
2019-10-04 10:22:18 +00:00
|
|
|
|
|
|
|
lst.resize(vtx_count*4);
|
|
|
|
|
|
|
|
|
|
|
|
int pfsti=0;
|
|
|
|
|
2022-01-25 14:37:04 +00:00
|
|
|
while (pp != pp_end)
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2020-03-27 12:03:49 +00:00
|
|
|
u32 ppid = (u32)(pp - pp_base);
|
2019-10-04 10:22:18 +00:00
|
|
|
|
2022-01-25 14:37:04 +00:00
|
|
|
if (pp->count > 2)
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2019-10-25 20:47:20 +00:00
|
|
|
const u32 *idx = idx_base + pp->first;
|
2020-03-27 12:03:49 +00:00
|
|
|
u32 flip = 0;
|
2022-02-13 20:01:45 +00:00
|
|
|
float z0 = 0, z1 = 0;
|
2019-10-04 10:22:18 +00:00
|
|
|
|
2022-01-29 17:39:38 +00:00
|
|
|
if (pp->isNaomi2())
|
2022-01-25 14:37:04 +00:00
|
|
|
{
|
2022-02-13 20:01:45 +00:00
|
|
|
z0 = getProjectedZ(vtx_base + idx[0], pp->mvMatrix);
|
|
|
|
z1 = getProjectedZ(vtx_base + idx[1], pp->mvMatrix);
|
2022-01-25 14:37:04 +00:00
|
|
|
}
|
2020-03-29 18:58:49 +00:00
|
|
|
for (u32 i = 0; i < pp->count - 2; i++)
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2020-03-27 12:03:49 +00:00
|
|
|
const Vertex *v0, *v1;
|
2019-10-04 10:22:18 +00:00
|
|
|
if (flip)
|
|
|
|
{
|
2020-03-27 12:03:49 +00:00
|
|
|
v0 = vtx_base + idx[i + 1];
|
|
|
|
v1 = vtx_base + idx[i];
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-27 12:03:49 +00:00
|
|
|
v0 = vtx_base + idx[i];
|
|
|
|
v1 = vtx_base + idx[i + 1];
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
2020-03-27 12:03:49 +00:00
|
|
|
const Vertex *v2 = vtx_base + idx[i + 2];
|
2022-01-25 14:37:04 +00:00
|
|
|
fill_id(lst[pfsti].id, v0, v1, v2, vtx_base);
|
|
|
|
lst[pfsti].pid = ppid;
|
2022-01-29 17:39:38 +00:00
|
|
|
if (pp->isNaomi2())
|
2019-10-04 10:22:18 +00:00
|
|
|
{
|
2022-02-13 20:01:45 +00:00
|
|
|
float z2 = getProjectedZ(v2, pp->mvMatrix);
|
2022-01-25 14:37:04 +00:00
|
|
|
lst[pfsti].z = std::min(z0, std::min(z1, z2));
|
|
|
|
z0 = z1;
|
|
|
|
z1 = z2;
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-25 14:37:04 +00:00
|
|
|
lst[pfsti].z = minZ(vtx_base, lst[pfsti].id);
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
2022-01-25 14:37:04 +00:00
|
|
|
pfsti++;
|
2019-10-04 10:22:18 +00:00
|
|
|
|
|
|
|
flip ^= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 aused=pfsti;
|
|
|
|
|
|
|
|
lst.resize(aused);
|
|
|
|
|
|
|
|
//sort them
|
|
|
|
std::stable_sort(lst.begin(),lst.end());
|
|
|
|
|
|
|
|
//Merge pids/draw cmds if two different pids are actually equal
|
2022-01-29 17:39:38 +00:00
|
|
|
for (u32 k = 1; k < aused; k++)
|
|
|
|
if (lst[k].pid != lst[k - 1].pid)
|
2022-02-11 14:54:18 +00:00
|
|
|
{
|
|
|
|
const PolyParam& curPoly = pp_base[lst[k].pid];
|
|
|
|
const PolyParam& prevPoly = pp_base[lst[k - 1].pid];
|
|
|
|
if (curPoly.equivalentIgnoreCullingDirection(prevPoly)
|
|
|
|
&& (curPoly.isp.CullMode < 2 || curPoly.isp.CullMode == prevPoly.isp.CullMode))
|
2022-01-29 17:39:38 +00:00
|
|
|
lst[k].pid = lst[k - 1].pid;
|
2022-02-11 14:54:18 +00:00
|
|
|
}
|
2019-10-04 10:22:18 +00:00
|
|
|
|
|
|
|
//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)
|
|
|
|
{
|
2020-03-31 19:09:42 +00:00
|
|
|
SortTrigDrawParam& last = pidx_sort.back();
|
|
|
|
last.count = stdp.first - last.first;
|
2019-10-04 10:22:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pidx_sort.push_back(stdp);
|
|
|
|
idx=pid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:09:42 +00:00
|
|
|
if (!pidx_sort.empty())
|
|
|
|
{
|
|
|
|
SortTrigDrawParam& last = pidx_sort.back();
|
|
|
|
last.count = aused * 3 - last.first;
|
|
|
|
}
|
2019-10-04 10:22:18 +00:00
|
|
|
|
|
|
|
#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);
|
|
|
|
}
|
2021-12-15 08:36:22 +00:00
|
|
|
|
|
|
|
// Vulkan and DirectX use the color values of the first vertex for flat shaded triangle strips.
|
|
|
|
// On Dreamcast the last vertex is the provoking one so we must copy it onto the first.
|
|
|
|
void setFirstProvokingVertex(rend_context& rendContext)
|
|
|
|
{
|
|
|
|
auto setProvokingVertex = [&rendContext](const List<PolyParam>& list) {
|
|
|
|
u32 *idx_base = rendContext.idx.head();
|
|
|
|
Vertex *vtx_base = rendContext.verts.head();
|
|
|
|
for (const PolyParam& pp : list)
|
|
|
|
{
|
|
|
|
if (pp.pcw.Gouraud)
|
|
|
|
continue;
|
|
|
|
for (u32 i = 0; i + 2 < pp.count; i++)
|
|
|
|
{
|
|
|
|
Vertex& vertex = vtx_base[idx_base[pp.first + i]];
|
|
|
|
Vertex& lastVertex = vtx_base[idx_base[pp.first + i + 2]];
|
|
|
|
memcpy(vertex.col, lastVertex.col, sizeof(vertex.col));
|
|
|
|
memcpy(vertex.spc, lastVertex.spc, sizeof(vertex.spc));
|
|
|
|
memcpy(vertex.col1, lastVertex.col1, sizeof(vertex.col1));
|
|
|
|
memcpy(vertex.spc1, lastVertex.spc1, sizeof(vertex.spc1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
setProvokingVertex(rendContext.global_param_op);
|
|
|
|
setProvokingVertex(rendContext.global_param_pt);
|
|
|
|
setProvokingVertex(rendContext.global_param_tr);
|
|
|
|
}
|