mirror of
https://github.com/libretro/ppsspp.git
synced 2025-01-22 08:44:51 +00:00
softgpu: Process rasterization in screen space, rather than drawing space.
This commit is contained in:
parent
c707140512
commit
74eafcab1a
@ -165,13 +165,13 @@ void ProcessQuad(const VertexData& v0, const VertexData& v1)
|
||||
} else {
|
||||
// through mode handling
|
||||
VertexData buf[4];
|
||||
buf[0].drawpos = DrawingCoords(v0.drawpos.x, v0.drawpos.y, v1.drawpos.z);
|
||||
buf[0].screenpos = ScreenCoords(v0.screenpos.x, v0.screenpos.y, v1.screenpos.z);
|
||||
buf[0].texturecoords = v0.texturecoords;
|
||||
|
||||
buf[1].drawpos = DrawingCoords(v0.drawpos.x, v1.drawpos.y, v1.drawpos.z);
|
||||
buf[1].screenpos = ScreenCoords(v0.screenpos.x, v1.screenpos.y, v1.screenpos.z);
|
||||
buf[1].texturecoords = Vec2<float>(v0.texturecoords.x, v1.texturecoords.y);
|
||||
|
||||
buf[2].drawpos = DrawingCoords(v1.drawpos.x, v0.drawpos.y, v1.drawpos.z);
|
||||
buf[2].screenpos = ScreenCoords(v1.screenpos.x, v0.screenpos.y, v1.screenpos.z);
|
||||
buf[2].texturecoords = Vec2<float>(v1.texturecoords.x, v0.texturecoords.y);
|
||||
|
||||
buf[3] = v1;
|
||||
@ -187,13 +187,13 @@ void ProcessQuad(const VertexData& v0, const VertexData& v1)
|
||||
VertexData* bottomright = &buf[3];
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (buf[i].drawpos.x < topleft->drawpos.x && buf[i].drawpos.y < topleft->drawpos.y)
|
||||
if (buf[i].screenpos.x < topleft->screenpos.x && buf[i].screenpos.y < topleft->screenpos.y)
|
||||
topleft = &buf[i];
|
||||
if (buf[i].drawpos.x > topright->drawpos.x && buf[i].drawpos.y < topright->drawpos.y)
|
||||
if (buf[i].screenpos.x > topright->screenpos.x && buf[i].screenpos.y < topright->screenpos.y)
|
||||
topright = &buf[i];
|
||||
if (buf[i].drawpos.x < bottomleft->drawpos.x && buf[i].drawpos.y > bottomleft->drawpos.y)
|
||||
if (buf[i].screenpos.x < bottomleft->screenpos.x && buf[i].screenpos.y > bottomleft->screenpos.y)
|
||||
bottomleft = &buf[i];
|
||||
if (buf[i].drawpos.x > bottomright->drawpos.x && buf[i].drawpos.y > bottomright->drawpos.y)
|
||||
if (buf[i].screenpos.x > bottomright->screenpos.x && buf[i].screenpos.y > bottomright->screenpos.y)
|
||||
bottomright = &buf[i];
|
||||
}
|
||||
|
||||
@ -281,9 +281,9 @@ void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2)
|
||||
if(indices[i] != SKIP_FLAG)
|
||||
{
|
||||
VertexData data[3] = { *Vertices[indices[i]], *Vertices[indices[i+1]], *Vertices[indices[i+2]] };
|
||||
data[0].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[0].clippos)));
|
||||
data[1].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[1].clippos)));
|
||||
data[2].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[2].clippos)));
|
||||
data[0].screenpos = TransformUnit::ClipToScreen(data[0].clippos);
|
||||
data[1].screenpos = TransformUnit::ClipToScreen(data[1].clippos);
|
||||
data[2].screenpos = TransformUnit::ClipToScreen(data[2].clippos);
|
||||
Rasterizer::DrawTriangle(data[0], data[1], data[2]);
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,8 @@ extern u32 clut[4096];
|
||||
|
||||
namespace Rasterizer {
|
||||
|
||||
static inline int orient2d(const DrawingCoords& v0, const DrawingCoords& v1, const DrawingCoords& v2)
|
||||
//static inline int orient2d(const DrawingCoords& v0, const DrawingCoords& v1, const DrawingCoords& v2)
|
||||
static inline int orient2d(const ScreenCoords& v0, const ScreenCoords& v1, const ScreenCoords& v2)
|
||||
{
|
||||
return ((int)v1.x-(int)v0.x)*((int)v2.y-(int)v0.y) - ((int)v1.y-(int)v0.y)*((int)v2.x-(int)v0.x);
|
||||
}
|
||||
@ -326,7 +327,7 @@ static inline bool IsRightSideOrFlatBottomLine(const Vec2<u10>& vertex, const Ve
|
||||
return vertex.y < line1.y;
|
||||
} else {
|
||||
// check if vertex is on our left => right side
|
||||
return vertex.x < line1.x + (line2.x - line1.x) * (vertex.y - line1.y) / (line2.y - line1.y);
|
||||
return vertex.x < line1.x + ((int)line2.x - (int)line1.x) * ((int)vertex.y - (int)line1.y) / ((int)line2.y - (int)line1.y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,43 +626,46 @@ static inline Vec3<int> AlphaBlendingResult(const Vec3<int>& source_rgb, int sou
|
||||
// Draws triangle, vertices specified in counter-clockwise direction
|
||||
void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2)
|
||||
{
|
||||
Vec2<int> d01((int)v0.drawpos.x - (int)v1.drawpos.x, (int)v0.drawpos.y - (int)v1.drawpos.y);
|
||||
Vec2<int> d02((int)v0.drawpos.x - (int)v2.drawpos.x, (int)v0.drawpos.y - (int)v2.drawpos.y);
|
||||
Vec2<int> d12((int)v1.drawpos.x - (int)v2.drawpos.x, (int)v1.drawpos.y - (int)v2.drawpos.y);
|
||||
Vec2<int> d01((int)v0.screenpos.x - (int)v1.screenpos.x, (int)v0.screenpos.y - (int)v1.screenpos.y);
|
||||
Vec2<int> d02((int)v0.screenpos.x - (int)v2.screenpos.x, (int)v0.screenpos.y - (int)v2.screenpos.y);
|
||||
Vec2<int> d12((int)v1.screenpos.x - (int)v2.screenpos.x, (int)v1.screenpos.y - (int)v2.screenpos.y);
|
||||
|
||||
// Drop primitives which are not in CCW order by checking the cross product
|
||||
if (d01.x * d02.y - d01.y * d02.x < 0)
|
||||
return;
|
||||
|
||||
int minX = std::min(std::min(v0.drawpos.x, v1.drawpos.x), v2.drawpos.x);
|
||||
int minY = std::min(std::min(v0.drawpos.y, v1.drawpos.y), v2.drawpos.y);
|
||||
int maxX = std::max(std::max(v0.drawpos.x, v1.drawpos.x), v2.drawpos.x);
|
||||
int maxY = std::max(std::max(v0.drawpos.y, v1.drawpos.y), v2.drawpos.y);
|
||||
int minX = std::min(std::min(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) / 16 * 16;
|
||||
int minY = std::min(std::min(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) / 16 * 16;
|
||||
int maxX = std::max(std::max(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) / 16 * 16;
|
||||
int maxY = std::max(std::max(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) / 16 * 16;
|
||||
|
||||
minX = std::max(minX, gstate.getScissorX1());
|
||||
maxX = std::min(maxX, gstate.getScissorX2());
|
||||
minY = std::max(minY, gstate.getScissorY1());
|
||||
maxY = std::min(maxY, gstate.getScissorY2());
|
||||
DrawingCoords scissorTL(gstate.getScissorX1(), gstate.getScissorY1(), 0);
|
||||
DrawingCoords scissorBR(gstate.getScissorX2(), gstate.getScissorY2(), 0);
|
||||
minX = std::max(minX, (int)TransformUnit::DrawingToScreen(scissorTL).x);
|
||||
maxX = std::min(maxX, (int)TransformUnit::DrawingToScreen(scissorBR).x);
|
||||
minY = std::max(minY, (int)TransformUnit::DrawingToScreen(scissorTL).y);
|
||||
maxY = std::min(maxY, (int)TransformUnit::DrawingToScreen(scissorBR).y);
|
||||
|
||||
int bias0 = IsRightSideOrFlatBottomLine(v0.drawpos.xy(), v1.drawpos.xy(), v2.drawpos.xy()) ? -1 : 0;
|
||||
int bias1 = IsRightSideOrFlatBottomLine(v1.drawpos.xy(), v2.drawpos.xy(), v0.drawpos.xy()) ? -1 : 0;
|
||||
int bias2 = IsRightSideOrFlatBottomLine(v2.drawpos.xy(), v0.drawpos.xy(), v1.drawpos.xy()) ? -1 : 0;
|
||||
int bias0 = IsRightSideOrFlatBottomLine(v0.screenpos.xy(), v1.screenpos.xy(), v2.screenpos.xy()) ? -1 : 0;
|
||||
int bias1 = IsRightSideOrFlatBottomLine(v1.screenpos.xy(), v2.screenpos.xy(), v0.screenpos.xy()) ? -1 : 0;
|
||||
int bias2 = IsRightSideOrFlatBottomLine(v2.screenpos.xy(), v0.screenpos.xy(), v1.screenpos.xy()) ? -1 : 0;
|
||||
|
||||
DrawingCoords p(minX, minY, 0);
|
||||
int w0_base = orient2d(v1.drawpos, v2.drawpos, p);
|
||||
int w1_base = orient2d(v2.drawpos, v0.drawpos, p);
|
||||
int w2_base = orient2d(v0.drawpos, v1.drawpos, p);
|
||||
for (p.y = minY; p.y <= maxY; ++p.y,
|
||||
w0_base += orient2dIncY(d12.x),
|
||||
w1_base += orient2dIncY(-d02.x),
|
||||
w2_base += orient2dIncY(d01.x)) {
|
||||
ScreenCoords pprime(minX, minY, 0);
|
||||
int w0_base = orient2d(v1.screenpos, v2.screenpos, pprime);
|
||||
int w1_base = orient2d(v2.screenpos, v0.screenpos, pprime);
|
||||
int w2_base = orient2d(v0.screenpos, v1.screenpos, pprime);
|
||||
for (pprime.y = minY; pprime.y <= maxY; pprime.y +=16,
|
||||
w0_base += orient2dIncY(d12.x)*16,
|
||||
w1_base += orient2dIncY(-d02.x)*16,
|
||||
w2_base += orient2dIncY(d01.x)*16) {
|
||||
int w0 = w0_base;
|
||||
int w1 = w1_base;
|
||||
int w2 = w2_base;
|
||||
for (p.x = minX; p.x <= maxX; ++p.x,
|
||||
w0 += orient2dIncX(d12.y),
|
||||
w1 += orient2dIncX(-d02.y),
|
||||
w2 += orient2dIncX(d01.y)) {
|
||||
for (pprime.x = minX; pprime.x <= maxX; pprime.x +=16,
|
||||
w0 += orient2dIncX(d12.y)*16,
|
||||
w1 += orient2dIncX(-d02.y)*16,
|
||||
w2 += orient2dIncX(d01.y)*16) {
|
||||
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
|
||||
|
||||
// If p is on or inside all edges, render pixel
|
||||
// TODO: Should we render if the pixel is both on the left and the right side? (i.e. degenerated triangle)
|
||||
@ -680,7 +684,7 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData&
|
||||
prim_color_rgb = ((v0.color0.rgb().Cast<float>() * w0 +
|
||||
v1.color0.rgb().Cast<float>() * w1 +
|
||||
v2.color0.rgb().Cast<float>() * w2) / (w0+w1+w2)).Cast<int>();
|
||||
prim_color_a = (int)((v0.color0.a() * w0 + v1.color0.a() * w1 + v2.color0.a() * w2) / (w0+w1+w2));
|
||||
prim_color_a = (int)(((float)v0.color0.a() * w0 + (float)v1.color0.a() * w1 + (float)v2.color0.a() * w2) / (w0+w1+w2));
|
||||
sec_color = ((v0.color1.Cast<float>() * w0 +
|
||||
v1.color1.Cast<float>() * w1 +
|
||||
v2.color1.Cast<float>() * w2) / (w0+w1+w2)).Cast<int>();
|
||||
@ -719,7 +723,7 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData&
|
||||
// TODO: Fogging
|
||||
|
||||
// TODO: Is that the correct way to interpolate?
|
||||
u16 z = (u16)((v0.drawpos.z * w0 + v1.drawpos.z * w1 + v2.drawpos.z * w2) / (w0+w1+w2));
|
||||
u16 z = (u16)(((float)v0.screenpos.z * w0 + (float)v1.screenpos.z * w1 + (float)v2.screenpos.z * w2) / (w0+w1+w2));
|
||||
|
||||
// Depth range test
|
||||
if (!gstate.isModeThrough())
|
||||
@ -757,6 +761,7 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData&
|
||||
else if (!gstate.isModeClear() && gstate.isDepthWriteEnabled())
|
||||
SetPixelDepth(p.x, p.y, z);
|
||||
}
|
||||
|
||||
if (gstate.isAlphaBlendEnabled() && !gstate.isModeClear()) {
|
||||
Vec4<int> dst = Vec4<int>::FromRGBA(GetPixelColor(p.x, p.y));
|
||||
prim_color_rgb = AlphaBlendingResult(prim_color_rgb, prim_color_a, dst);
|
||||
|
@ -86,6 +86,15 @@ DrawingCoords TransformUnit::ScreenToDrawing(const ScreenCoords& coords)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ScreenCoords TransformUnit::DrawingToScreen(const DrawingCoords& coords)
|
||||
{
|
||||
ScreenCoords ret;
|
||||
ret.x = (((u32)coords.x * 16 + (gstate.offsetx&0xffff)));
|
||||
ret.y = (((u32)coords.y * 16 + (gstate.offsety&0xffff)));
|
||||
ret.z = coords.z;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VertexData ReadVertex(VertexReader& vreader)
|
||||
{
|
||||
VertexData vertex;
|
||||
@ -149,7 +158,7 @@ static VertexData ReadVertex(VertexReader& vreader)
|
||||
vertex.modelpos = ModelCoords(pos[0], pos[1], pos[2]);
|
||||
vertex.worldpos = WorldCoords(TransformUnit::ModelToWorld(vertex.modelpos));
|
||||
vertex.clippos = ClipCoords(TransformUnit::ViewToClip(TransformUnit::WorldToView(vertex.worldpos)));
|
||||
vertex.drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(ClipToScreenInternal(vertex.clippos)));
|
||||
vertex.screenpos = ClipToScreenInternal(vertex.clippos);
|
||||
|
||||
if (vreader.hasNormal()) {
|
||||
vertex.worldnormal = TransformUnit::ModelToWorld(vertex.normal) - Vec3<float>(gstate.worldMatrix[9], gstate.worldMatrix[10], gstate.worldMatrix[11]);
|
||||
@ -158,9 +167,9 @@ static VertexData ReadVertex(VertexReader& vreader)
|
||||
|
||||
Lighting::Process(vertex);
|
||||
} else {
|
||||
vertex.drawpos.x = pos[0];
|
||||
vertex.drawpos.y = pos[1];
|
||||
vertex.drawpos.z = pos[2];
|
||||
vertex.screenpos.x = (u32)pos[0] * 16 + (gstate.offsetx&0xffff);
|
||||
vertex.screenpos.y = (u32)pos[1] * 16 + (gstate.offsety&0xffff);
|
||||
vertex.screenpos.z = pos[2];
|
||||
vertex.clippos.w = 1.f;
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,18 @@ struct ScreenCoords
|
||||
fixed16 y;
|
||||
u16 z;
|
||||
|
||||
Vec2<fixed16> xy() const { return Vec2<fixed16>(x, y); }
|
||||
|
||||
ScreenCoords operator * (const float t) const
|
||||
{
|
||||
return ScreenCoords(x * t, y * t, z * t);
|
||||
}
|
||||
|
||||
ScreenCoords operator / (const int t) const
|
||||
{
|
||||
return ScreenCoords(x / t, y / t, z / t);
|
||||
}
|
||||
|
||||
ScreenCoords operator + (const ScreenCoords& oth) const
|
||||
{
|
||||
return ScreenCoords(x + oth.x, y + oth.y, z + oth.z);
|
||||
@ -78,7 +85,7 @@ struct VertexData
|
||||
|
||||
modelpos = ::Lerp(a.modelpos, b.modelpos, t);
|
||||
clippos = ::Lerp(a.clippos, b.clippos, t);
|
||||
drawpos = ::Lerp(a.drawpos, b.drawpos, t); // TODO: Should use a LerpInt (?)
|
||||
screenpos = ::Lerp(a.screenpos, b.screenpos, t); // TODO: Should use a LerpInt (?)
|
||||
texturecoords = ::Lerp(a.texturecoords, b.texturecoords, t);
|
||||
normal = ::Lerp(a.normal, b.normal, t);
|
||||
|
||||
@ -90,7 +97,7 @@ struct VertexData
|
||||
ModelCoords modelpos;
|
||||
WorldCoords worldpos; // TODO: Storing this is dumb, should transform the light to clip space instead
|
||||
ClipCoords clippos;
|
||||
DrawingCoords drawpos; // TODO: Shouldn't store this ?
|
||||
ScreenCoords screenpos; // TODO: Shouldn't store this ?
|
||||
Vec2<float> texturecoords;
|
||||
Vec3<float> normal;
|
||||
WorldCoords worldnormal;
|
||||
@ -106,6 +113,7 @@ public:
|
||||
static ClipCoords ViewToClip(const ViewCoords& coords);
|
||||
static ScreenCoords ClipToScreen(const ClipCoords& coords);
|
||||
static DrawingCoords ScreenToDrawing(const ScreenCoords& coords);
|
||||
static ScreenCoords DrawingToScreen(const DrawingCoords& coords);
|
||||
|
||||
static void SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, u32 prim_type, u32 vertex_type);
|
||||
static void SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type);
|
||||
|
Loading…
x
Reference in New Issue
Block a user