softgpu: Implement depth testing.

This commit is contained in:
Tony Wasserka 2013-06-29 17:10:15 +02:00 committed by neobrain
parent 72a71702a5
commit 00b7fbd19e
5 changed files with 77 additions and 6 deletions

View File

@ -162,13 +162,16 @@ void ProcessQuad(VertexData* data)
verts[1].drawpos.x = data[1].drawpos.x;
verts[4].drawpos.x = data[0].drawpos.x;
// Color values of second vertex are used for the whole rectangle
// Color and depth values of second vertex are used for the whole rectangle
verts[0].color0 = verts[1].color0;
verts[1].color0 = verts[1].color0;
verts[5].color0 = verts[1].color0;
verts[0].color1 = verts[1].color1;
verts[1].color1 = verts[1].color1;
verts[5].color1 = verts[1].color1;
verts[0].drawpos.z = verts[1].drawpos.z;
verts[1].drawpos.z = verts[1].drawpos.z;
verts[5].drawpos.z = verts[1].drawpos.z;
Rasterizer::DrawTriangle(verts);
Rasterizer::DrawTriangle(verts+3);

View File

@ -21,6 +21,7 @@
#include "Rasterizer.h"
extern u8* fb;
extern u8* depthbuf;
namespace Rasterizer {
@ -100,7 +101,7 @@ void DrawTriangle(VertexData vertexdata[3])
minY = std::max(minY, gstate.getScissorY1());
maxY = std::min(maxY, gstate.getScissorY2());
DrawingCoords p(minX, minY);
DrawingCoords p(minX, minY, 0);
for (p.y = minY; p.y <= maxY; ++p.y)
{
for (p.x = minX; p.x <= maxX; ++p.x)
@ -114,6 +115,57 @@ void DrawTriangle(VertexData vertexdata[3])
if (w0 >=0 && w1 >= 0 && w2 >= 0)
{
float den = 1.0f/vertexdata[0].clippos.w * w0 + 1.0f/vertexdata[1].clippos.w * w1 + 1.0f/vertexdata[2].clippos.w * w2;
// TODO: Depth range test
// TODO: Is it safe to ignore gstate.isDepthTestEnabled() when clear mode is enabled?
if ((gstate.isDepthTestEnabled() && !gstate.isModeThrough()) || gstate.isModeClear()) {
u16 z = (u16)((vertexdata[0].drawpos.z * w0 / vertexdata[0].clippos.w + vertexdata[1].drawpos.z * w1 / vertexdata[1].clippos.w + vertexdata[2].drawpos.z * w2 / vertexdata[2].clippos.w) / den);
u16 reference_z = *(u16*)&depthbuf[p.x*2+p.y*(gstate.zbwidth&0x7C0)*2];
bool pass = true;
switch (gstate.getDepthTestFunc()) {
case GE_COMP_NEVER:
pass = false;
break;
case GE_COMP_ALWAYS:
pass = true;
break;
case GE_COMP_EQUAL:
pass = (z == reference_z);
break;
case GE_COMP_NOTEQUAL:
pass = (z != reference_z);
break;
case GE_COMP_LESS:
pass = (z < reference_z);
break;
case GE_COMP_LEQUAL:
pass = (z <= reference_z);
break;
case GE_COMP_GREATER:
pass = (z > reference_z);
break;
case GE_COMP_GEQUAL:
pass = (z >= reference_z);
break;
}
// Clear mode forces depth test func to be ALWAYS
if (!pass && !gstate.isModeClear())
continue;
if (gstate.isDepthWriteEnabled() || (gstate.clearmode&0x40)) // TODO: Correct to enable depth writing in the clearmode case?
*(u16*)&depthbuf[p.x*2+p.y*(gstate.zbwidth&0x7C0)*2] = z;
}
float s = (vertexdata[0].texturecoords.s() * w0 / vertexdata[0].clippos.w + vertexdata[1].texturecoords.s() * w1 / vertexdata[1].clippos.w + vertexdata[2].texturecoords.s() * w2 / vertexdata[2].clippos.w) / den;
float t = (vertexdata[0].texturecoords.t() * w0 / vertexdata[0].clippos.w + vertexdata[1].texturecoords.t() * w1 / vertexdata[1].clippos.w + vertexdata[2].texturecoords.t() * w2 / vertexdata[2].clippos.w) / den;
u32 color = 0;
@ -129,7 +181,7 @@ void DrawTriangle(VertexData vertexdata[3])
if (gstate.isTextureMapEnabled())
color |= /*TextureDecoder::*/SampleNearest(0, s, t);
*(u32*)&fb[p.x*4+p.y*(gstate.fbwidth&0x3C0)*4] = color;
*(u32*)&fb[p.x*4+p.y*(gstate.fbwidth&0x7C0)*4] = color;
}
}
}

View File

@ -34,7 +34,8 @@ static GLint uni_tex = -1;
static GLuint program;
const int FB_HEIGHT = 272;
u8* fb = NULL; // TODO: Default address?
u8* fb = NULL;
u8* depthbuf = NULL;
GLuint OpenGL_CompileProgram(const char* vertexShader, const char* fragmentShader)
{
@ -135,7 +136,8 @@ SoftGPU::SoftGPU()
attr_pos = glGetAttribLocation(program, "pos");
attr_tex = glGetAttribLocation(program, "TexCoordIn");
fb = Memory::GetPointer(0x44000000);
fb = Memory::GetPointer(0x44000000); // TODO: correct default address?
depthbuf = Memory::GetPointer(0x44000000); // TODO: correct default address?
}
SoftGPU::~SoftGPU()
@ -531,6 +533,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff)
case GE_CMD_ZBUFPTR:
{
u32 ptr = op & 0xFFE000;
depthbuf = Memory::GetPointer(0x44000000 | (gstate.fbptr & 0xFFE000) | ((gstate.fbwidth & 0xFF0000) << 8));
DEBUG_LOG(G3D,"Zbuf Ptr: %06x", ptr);
}
break;
@ -538,6 +541,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff)
case GE_CMD_ZBUFWIDTH:
{
u32 w = data & 0xFFFFFF;
depthbuf = Memory::GetPointer(0x44000000 | (gstate.fbptr & 0xFFE000) | ((gstate.fbwidth & 0xFF0000) << 8));
DEBUG_LOG(G3D,"Zbuf Width: %i", w);
}
break;

View File

@ -63,6 +63,7 @@ DrawingCoords TransformUnit::ScreenToDrawing(const ScreenCoords& coords)
// TODO: What to do when offset > coord?
ret.x = (((u32)coords.x - (gstate.offsetx&0xffff))/16) & 0x3ff;
ret.y = (((u32)coords.y - (gstate.offsety&0xffff))/16) & 0x3ff;
ret.z = coords.z;
return ret;
}
@ -152,6 +153,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type
} else {
data[i].drawpos.x = pos[0];
data[i].drawpos.y = pos[1];
data[i].drawpos.z = 0; // TODO: Not sure if that's what we should do here
}
}

View File

@ -35,7 +35,15 @@ struct ScreenCoords
u16 z;
};
typedef Vec2<u10> DrawingCoords; // TODO: Keep z component?
struct DrawingCoords
{
DrawingCoords() {}
DrawingCoords(u10 x, u10 y, u16 z) : x(x), y(y), z(z) {}
u10 x;
u10 y;
u16 z;
};
struct VertexData
{
@ -51,8 +59,10 @@ struct VertexData
clippos.z = LINTERP(t, a.clippos.z, b.clippos.z);
clippos.w = LINTERP(t, a.clippos.w, b.clippos.w);
// TODO: Should use a LINTERP_INT, too
drawpos.x = LINTERP(t, a.drawpos.x, b.drawpos.x);
drawpos.y = LINTERP(t, a.drawpos.y, b.drawpos.y);
drawpos.z = LINTERP(t, a.drawpos.z, b.drawpos.z);
texturecoords.x = LINTERP(t, a.texturecoords.x, b.texturecoords.x);
texturecoords.y = LINTERP(t, a.texturecoords.y, b.texturecoords.y);