Detect sprite drawing (1:1 texture mapping), run a simpler function without the triangle state tracking.

This will allow further simplification and specialization.
This commit is contained in:
Henrik Rydgård 2019-10-23 00:18:30 +02:00
parent 510229b68b
commit c7f6724f7e
5 changed files with 104 additions and 0 deletions

View file

@ -197,6 +197,7 @@
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<ForcedIncludeFiles>Common/DbgNew.h</ForcedIncludeFiles>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -184,6 +184,39 @@ void ProcessRect(const VertexData& v0, const VertexData& v1)
ProcessTriangle(*topleft, *bottomleft, *bottomright, buf[3]);
} else {
// through mode handling
// Check for simple case: No depth, alpha != 0 testing only, no blend, texture mapping 1:1 etc.
// Also check for scissor rectangle etc.
// That is, state commonly used in PSX games and ports like Darkstalker.
// In that case we can call DrawPSXSprite.
int xdiff = v1.screenpos.x - v0.screenpos.x;
int ydiff = v1.screenpos.y - v0.screenpos.y;
int udiff = (v1.texturecoords.x - v0.texturecoords.x) * 16.0f;
int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * 16.0f;
bool coord_check =
(xdiff == udiff /* || xdiff == -udiff*/) &&
(ydiff == vdiff /* || ydiff == -vdiff*/);
// TODO: The U/V mirror support is off by one somehow. Predecrement?
/*
bool state_check =
!gstate.isModeClear() &&
!gstate.isFogEnabled() &&
gstate.isTextureMapEnabled() &&
!gstate.isDepthTestEnabled() &&
!gstate.isStencilTestEnabled();
bool alpha_check =
gstate.getAlphaTestFunction() == GEComparison::GE_COMP_GREATER &&
gstate.getAlphaTestMask() == 0xFF &&
gstate.getAlphaTestRef() == 0;
*/
bool state_check = !gstate.isModeClear();
bool alpha_check = true;
if ((coord_check || !gstate.isTextureMapEnabled()) && state_check && alpha_check) {
Rasterizer::DrawPSXSprite(v0, v1);
return;
}
VertexData buf[4];
buf[0].screenpos = ScreenCoords(v0.screenpos.x, v0.screenpos.y, v1.screenpos.z);
buf[0].texturecoords = v0.texturecoords;

View file

@ -1287,6 +1287,54 @@ void DrawTriangleSlice(
}
}
void DrawPSXSprite(const VertexData& v0, const VertexData& v1) {
u8 *texptr = nullptr;
GETextureFormat texfmt = gstate.getTextureFormat();
u32 texaddr = gstate.getTextureAddress(0);
int texbufw = GetTextureBufw(0, texaddr, texfmt);
if (Memory::IsValidAddress(texaddr))
texptr = Memory::GetPointerUnchecked(texaddr);
ScreenCoords pprime(v0.screenpos.x, v0.screenpos.y, 0);
Sampler::Funcs sampler = Sampler::GetFuncs();
DrawingCoords pos0 = TransformUnit::ScreenToDrawing(v0.screenpos);
DrawingCoords pos1 = TransformUnit::ScreenToDrawing(v1.screenpos);
int z = pos0.z;
float fog = 1.0f;
if (gstate.isTextureMapEnabled()) {
// 1:1 (but with mirror support) texture mapping!
int s = v0.texturecoords.x;
int t = v0.texturecoords.y;
int ds = v1.texturecoords.x > v0.texturecoords.x ? 1 : -1;
int dt = v1.texturecoords.y > v0.texturecoords.y ? 1 : -1;
for (int y = pos0.y; y < pos1.y; y++) {
s = v0.texturecoords.x;
for (int x = pos0.x; x < pos1.x; x++) {
Vec4<int> prim_color = v0.color0;
Vec4<int> tex_color = Vec4<int>::FromRGBA(sampler.nearest(s, t, texptr, texbufw, 0));
prim_color = GetTextureFunctionOutput(prim_color, tex_color);
DrawingCoords pos(x, y, z);
DrawSinglePixel<false>(pos, (u16)z, fog, prim_color);
s += ds;
}
t += dt;
}
}
else {
for (int y = pos0.y; y < pos1.y; y++) {
for (int x = pos0.x; x < pos1.x; x++) {
Vec4<int> prim_color = v0.color0;
DrawingCoords pos(x, y, z);
DrawSinglePixel<false>(pos, (u16)z, fog, prim_color);
}
}
}
}
// Draws triangle, vertices specified in counter-clockwise direction
void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2)
{

View file

@ -27,6 +27,7 @@ namespace Rasterizer {
void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2);
void DrawPoint(const VertexData &v0);
void DrawLine(const VertexData &v0, const VertexData &v1);
void DrawPSXSprite(const VertexData &v0, const VertexData &v1);
void ClearRectangle(const VertexData &v0, const VertexData &v1);
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer);

View file

@ -470,6 +470,27 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
data[2].color0 == data[3].color0) {
// It's a rectangle!
Clipper::ProcessRect(data[0], data[3]);
break;
}
// There's the other vertex order too...
if (data[0].screenpos.x == data[2].screenpos.x &&
data[0].screenpos.y == data[1].screenpos.y &&
data[1].screenpos.x == data[3].screenpos.x &&
data[2].screenpos.y == data[3].screenpos.y &&
data[2].screenpos.y > data[0].screenpos.y && // Avoid rotation handling
data[1].screenpos.x > data[0].screenpos.x &&
data[0].texturecoords.x == data[2].texturecoords.x &&
data[0].texturecoords.y == data[1].texturecoords.y &&
data[1].texturecoords.x == data[3].texturecoords.x &&
data[2].texturecoords.y == data[3].texturecoords.y &&
data[2].texturecoords.y > data[0].texturecoords.y &&
data[1].texturecoords.x > data[0].texturecoords.x &&
data[0].color0 == data[1].color0 &&
data[1].color0 == data[2].color0 &&
data[2].color0 == data[3].color0) {
// It's a rectangle!
Clipper::ProcessRect(data[0], data[3]);
break;
}
}