mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
SoftGPU: Implement CONTINUE prim type.
Matches tests (except 3D lines, which aren't implemented yet.)
This commit is contained in:
parent
ee68f09be5
commit
1666586869
3 changed files with 62 additions and 34 deletions
|
@ -364,7 +364,8 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) {
|
|||
case GE_CMD_PRIM:
|
||||
{
|
||||
u32 count = data & 0xFFFF;
|
||||
u32 type = data >> 16;
|
||||
// Upper bits are ignored.
|
||||
GEPrimitiveType type = static_cast<GEPrimitiveType>((data >> 16) & 7);
|
||||
|
||||
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
|
||||
ERROR_LOG_REPORT(G3D, "Software: Bad vertex address %08x!", gstate_c.vertexAddr);
|
||||
|
|
|
@ -212,7 +212,7 @@ struct SplinePatch {
|
|||
int pad[3];
|
||||
};
|
||||
|
||||
void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type, int *bytesRead)
|
||||
void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveType prim_type, int vertex_count, u32 vertex_type, int *bytesRead)
|
||||
{
|
||||
// TODO: Cache VertexDecoder objects
|
||||
VertexDecoder vdecoder;
|
||||
|
@ -239,17 +239,27 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
VertexReader vreader(buf, vtxfmt, vertex_type);
|
||||
|
||||
const int max_vtcs_per_prim = 3;
|
||||
int vtcs_per_prim = 0;
|
||||
static VertexData data[max_vtcs_per_prim]{};
|
||||
// This is the index of the next vert in data (or higher, may need modulus.)
|
||||
static int data_index = 0;
|
||||
|
||||
static GEPrimitiveType prev_prim = GE_PRIM_POINTS;
|
||||
if (prim_type != GE_PRIM_KEEP_PREVIOUS) {
|
||||
data_index = 0;
|
||||
prev_prim = prim_type;
|
||||
} else {
|
||||
prim_type = prev_prim;
|
||||
}
|
||||
|
||||
int vtcs_per_prim;
|
||||
switch (prim_type) {
|
||||
case GE_PRIM_POINTS: vtcs_per_prim = 1; break;
|
||||
case GE_PRIM_LINES: vtcs_per_prim = 2; break;
|
||||
case GE_PRIM_TRIANGLES: vtcs_per_prim = 3; break;
|
||||
case GE_PRIM_RECTANGLES: vtcs_per_prim = 2; break;
|
||||
default: vtcs_per_prim = 0; break;
|
||||
}
|
||||
|
||||
VertexData data[max_vtcs_per_prim];
|
||||
|
||||
// TODO: Do this in two passes - first process the vertices (before indexing/stripping),
|
||||
// then resolve the indices. This lets us avoid transforming shared vertices twice.
|
||||
|
||||
|
@ -259,19 +269,23 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
case GE_PRIM_TRIANGLES:
|
||||
case GE_PRIM_RECTANGLES:
|
||||
{
|
||||
for (int vtx = 0; vtx < vertex_count; vtx += vtcs_per_prim) {
|
||||
for (int i = 0; i < vtcs_per_prim; ++i) {
|
||||
if (indices) {
|
||||
vreader.Goto(idxConv.convert(vtx + i) - index_lower_bound);
|
||||
} else {
|
||||
vreader.Goto(vtx + i);
|
||||
}
|
||||
|
||||
data[i] = ReadVertex(vreader);
|
||||
if (outside_range_flag)
|
||||
break;
|
||||
for (int vtx = 0; vtx < vertex_count; ++vtx) {
|
||||
if (indices) {
|
||||
vreader.Goto(idxConv.convert(vtx) - index_lower_bound);
|
||||
} else {
|
||||
vreader.Goto(vtx);
|
||||
}
|
||||
|
||||
data[data_index++] = ReadVertex(vreader);
|
||||
if (data_index < vtcs_per_prim) {
|
||||
// Keep reading. Note: an incomplete prim will stay read for GE_PRIM_KEEP_PREVIOUS.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Okay, we've got enough verts. Reset the index for next time.
|
||||
data_index = 0;
|
||||
if (outside_range_flag) {
|
||||
// Cull the prim if it was outside, and move to the next prim.
|
||||
outside_range_flag = false;
|
||||
continue;
|
||||
}
|
||||
|
@ -282,10 +296,11 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
if (!gstate.isCullEnabled() || gstate.isModeClear()) {
|
||||
Clipper::ProcessTriangle(data[0], data[1], data[2]);
|
||||
Clipper::ProcessTriangle(data[2], data[1], data[0]);
|
||||
} else if (!gstate.getCullMode())
|
||||
} else if (!gstate.getCullMode()) {
|
||||
Clipper::ProcessTriangle(data[2], data[1], data[0]);
|
||||
else
|
||||
} else {
|
||||
Clipper::ProcessTriangle(data[0], data[1], data[2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -307,7 +322,9 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
|
||||
case GE_PRIM_LINE_STRIP:
|
||||
{
|
||||
int skip_count = 1; // Don't draw a line when loading the first vertex
|
||||
// Don't draw a line when loading the first vertex.
|
||||
// If data_index is 1 or 2, etc., it means we're continuing a line strip.
|
||||
int skip_count = data_index == 0 ? 1 : 0;
|
||||
for (int vtx = 0; vtx < vertex_count; ++vtx) {
|
||||
if (indices) {
|
||||
vreader.Goto(idxConv.convert(vtx) - index_lower_bound);
|
||||
|
@ -315,7 +332,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
vreader.Goto(vtx);
|
||||
}
|
||||
|
||||
data[vtx & 1] = ReadVertex(vreader);
|
||||
data[(data_index++) & 1] = ReadVertex(vreader);
|
||||
if (outside_range_flag) {
|
||||
// Drop all primitives containing the current vertex
|
||||
skip_count = 2;
|
||||
|
@ -326,7 +343,8 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
if (skip_count) {
|
||||
--skip_count;
|
||||
} else {
|
||||
Clipper::ProcessLine(data[(vtx & 1) ^ 1], data[vtx & 1]);
|
||||
// We already incremented data_index, so data_index & 1 is previous one.
|
||||
Clipper::ProcessLine(data[data_index & 1], data[(data_index & 1) ^ 1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -334,7 +352,8 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
|
||||
case GE_PRIM_TRIANGLE_STRIP:
|
||||
{
|
||||
int skip_count = 2; // Don't draw a triangle when loading the first two vertices
|
||||
// Don't draw a triangle when loading the first two vertices.
|
||||
int skip_count = data_index >= 2 ? 0 : 2 - data_index;
|
||||
|
||||
for (int vtx = 0; vtx < vertex_count; ++vtx) {
|
||||
if (indices) {
|
||||
|
@ -343,7 +362,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
vreader.Goto(vtx);
|
||||
}
|
||||
|
||||
data[vtx % 3] = ReadVertex(vreader);
|
||||
data[(data_index++) % 3] = ReadVertex(vreader);
|
||||
if (outside_range_flag) {
|
||||
// Drop all primitives containing the current vertex
|
||||
skip_count = 2;
|
||||
|
@ -359,7 +378,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
if (!gstate.isCullEnabled() || gstate.isModeClear()) {
|
||||
Clipper::ProcessTriangle(data[0], data[1], data[2]);
|
||||
Clipper::ProcessTriangle(data[2], data[1], data[0]);
|
||||
} else if ((!gstate.getCullMode()) ^ (vtx % 2)) {
|
||||
} else if ((!gstate.getCullMode()) ^ ((data_index - 1) % 2)) {
|
||||
// We need to reverse the vertex order for each second primitive,
|
||||
// but we additionally need to do that for every primitive if CCW cullmode is used.
|
||||
Clipper::ProcessTriangle(data[2], data[1], data[0]);
|
||||
|
@ -372,23 +391,31 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
|
||||
case GE_PRIM_TRIANGLE_FAN:
|
||||
{
|
||||
unsigned int skip_count = 1; // Don't draw a triangle when loading the first two vertices
|
||||
// Don't draw a triangle when loading the first two vertices.
|
||||
// (this doesn't count the central one.)
|
||||
int skip_count = data_index <= 1 ? 1 : 0;
|
||||
int start_vtx = 0;
|
||||
|
||||
if (indices) {
|
||||
vreader.Goto(idxConv.convert(0) - index_lower_bound);
|
||||
} else {
|
||||
vreader.Goto(0);
|
||||
// Only read the central vertex if we're not continuing.
|
||||
if (data_index == 0) {
|
||||
if (indices) {
|
||||
vreader.Goto(idxConv.convert(0) - index_lower_bound);
|
||||
} else {
|
||||
vreader.Goto(0);
|
||||
}
|
||||
data[0] = ReadVertex(vreader);
|
||||
data_index++;
|
||||
start_vtx = 1;
|
||||
}
|
||||
data[0] = ReadVertex(vreader);
|
||||
|
||||
for (int vtx = 1; vtx < vertex_count; ++vtx) {
|
||||
for (int vtx = start_vtx; vtx < vertex_count; ++vtx) {
|
||||
if (indices) {
|
||||
vreader.Goto(idxConv.convert(vtx) - index_lower_bound);
|
||||
} else {
|
||||
vreader.Goto(vtx);
|
||||
}
|
||||
|
||||
data[2 - (vtx % 2)] = ReadVertex(vreader);
|
||||
data[2 - ((data_index++) % 2)] = ReadVertex(vreader);
|
||||
if (outside_range_flag) {
|
||||
// Drop all primitives containing the current vertex
|
||||
skip_count = 2;
|
||||
|
@ -404,7 +431,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
|
|||
if (!gstate.isCullEnabled() || gstate.isModeClear()) {
|
||||
Clipper::ProcessTriangle(data[0], data[1], data[2]);
|
||||
Clipper::ProcessTriangle(data[2], data[1], data[0]);
|
||||
} else if ((!gstate.getCullMode()) ^ (vtx % 2)) {
|
||||
} else if ((!gstate.getCullMode()) ^ ((data_index - 1) % 2)) {
|
||||
// We need to reverse the vertex order for each second primitive,
|
||||
// but we additionally need to do that for every primitive if CCW cullmode is used.
|
||||
Clipper::ProcessTriangle(data[2], data[1], data[0]);
|
||||
|
|
|
@ -126,7 +126,7 @@ public:
|
|||
static DrawingCoords ScreenToDrawing(const ScreenCoords& coords);
|
||||
static ScreenCoords DrawingToScreen(const DrawingCoords& coords);
|
||||
|
||||
static void SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type, int *bytesRead);
|
||||
static void SubmitPrimitive(void* vertices, void* indices, GEPrimitiveType prim_type, int vertex_count, u32 vertex_type, int *bytesRead);
|
||||
|
||||
static bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices);
|
||||
static VertexData ReadVertex(VertexReader& vreader);
|
||||
|
|
Loading…
Add table
Reference in a new issue