Skip to content

Commit

Permalink
gpu: sw: Prepare for anti-aliasing implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
fleroviux committed Jan 20, 2024
1 parent a813db1 commit 9928bbd
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ namespace dual::nds::gpu {
Color4 ShadeTexturedPolygon(Polygon::Mode polygon_mode, Color4 texture_color, Color4 vertex_color);
Color4 ShadeShadedUntexturedPolygon(Color4 vertex_color);
Color4 SampleTexture(TextureParams params, u32 palette_base, Vector2<Fixed12x4> uv);
void RenderAntiAliasing();

template<typename T>
auto ReadTextureVRAM(u32 address) {
Expand All @@ -80,8 +81,8 @@ namespace dual::nds::gpu {
bool m_enable_w_buffer{};
u8 m_vram_texture_copy[524288]{};
u8 m_vram_palette_copy[131072]{};
Color4 m_frame_buffer[192][256];
u32 m_depth_buffer[192][256];
Color4 m_frame_buffer[2][192][256];
u32 m_depth_buffer[2][192][256];
PixelAttributes m_attribute_buffer[192][256];
std::array<Color4, 32> m_toon_table{};
};
Expand Down
87 changes: 67 additions & 20 deletions src/dual/src/nds/video_unit/gpu/renderer/software/rasterizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,23 @@ namespace dual::nds::gpu {

for(int y = 0; y < 192; y++) {
for(int x = 0; x < 256; x++) {
m_frame_buffer[y][x] = clear_color;
m_frame_buffer[0][y][x] = clear_color;
}
}

// @todo: is clearing this actually necessary?
for(int y = 0; y < 192; y++) {
for(int x = 0; x < 256; x++) {
m_frame_buffer[1][y][x] = Color4{0, 0, 0, 0};
}
}

const u32 clear_depth = (((u32)m_io.clear_depth << 9) + (((u32)m_io.clear_depth + 1u) >> 15)) * 0x1FFu;

for(int y = 0; y < 192; y++) {
for(int x = 0; x < 256; x++) {
m_depth_buffer[y][x] = clear_depth;
m_depth_buffer[0][y][x] = clear_depth;
m_depth_buffer[1][y][x] = clear_depth;
}
}

Expand Down Expand Up @@ -281,7 +289,7 @@ namespace dual::nds::gpu {
for(int x = x0; x <= x1; x++) {
line_interp.Setup(line.w_16[0], line.w_16[1], x, line.x[0], line.x[1]);

const u32 depth_old = m_depth_buffer[y][x];
const u32 depth_old = m_depth_buffer[0][y][x];
const u32 depth_new = m_enable_w_buffer ?
line_interp.Perp(line.depth[0], line.depth[1]) : line_interp.Lerp(line.depth[0], line.depth[1]);

Expand All @@ -305,9 +313,10 @@ namespace dual::nds::gpu {
continue;
}

if(!depth_test_passed) {
continue;
}
// @todo: I guess we can do this early reject if anti-aliasing is disabled.
// if(!depth_test_passed) {
// continue;
// }

line_interp.Perp(line.color[0], line.color[1], color);
line_interp.Perp(line.uv[0], line.uv[1], uv);
Expand All @@ -330,37 +339,71 @@ namespace dual::nds::gpu {

const bool opaque_pixel = color.A() == 63;

// // @todo: translucent pixels should be blended into both the top and bottom pixel.

const auto AlphaBlend = [this](Color4 top, Color4 bottom) {
if(bottom.A() == 0) return top;

// @todo: this will be calculated multiple times even though it stays the same.
const Fixed6 a0 = top.A();
const Fixed6 a1 = Fixed6{63} - a0;

for(const int i: {0, 1, 2}) {
top[i] = top[i] * a0 + bottom[i] * a1;
}
top.A() = std::max(top.A(), bottom.A());
return top;
};

// @todo: simplify this
if(!opaque_pixel) {
// @todo: do not reject pixel if the destination pixel is opaque.
if(attributes.poly_id[1] == polygon_id) {
continue;
}
}

bool color_write = true;

if(m_io.disp3dcnt.enable_alpha_blend && m_frame_buffer[y][x].A() != 0) {
const Fixed6 a0 = color.A();
const Fixed6 a1 = Fixed6{63} - a0;
for (const int i: {0, 1, 2}) {
color[i] = color[i] * a0 + m_frame_buffer[y][x][i] * a1;
// @todo: maybe simplify this.
if(polygon_mode == Polygon::Mode::Shadow) {
// We assume that polygon_id != 0 here because we discard the other shadow polygon pixels.
color_write = attributes.flags & PixelAttributes::Shadow && attributes.poly_id[0] != polygon_id;
}

if(!depth_test_passed) {
// @todo: most likely this is incorrect for the "equals" depth test.
if(color_write && depth_new < m_depth_buffer[1][y][x]) {
// @todo: validate that the new bottom pixel will be alpha blended into the old bottom pixel.
if(!opaque_pixel) {
m_frame_buffer[1][y][x] = AlphaBlend(color, m_frame_buffer[1][y][x]);
} else {
m_frame_buffer[1][y][x] = color;
}
color.A() = std::max(color.A(), m_frame_buffer[y][x].A());
m_depth_buffer[1][y][x] = depth_new;
}
continue;
}

if(polygon_mode == Polygon::Mode::Shadow) {
// We assume that polygon_id != 0 here because we discard the other shadow polygon pixels.
if(attributes.flags & PixelAttributes::Shadow && attributes.poly_id[0] != polygon_id) {
m_frame_buffer[y][x] = color;
if(color_write) {
if(!opaque_pixel) {
m_frame_buffer[1][y][x] = AlphaBlend(color, m_frame_buffer[1][y][x]);
m_frame_buffer[0][y][x] = AlphaBlend(color, m_frame_buffer[0][y][x]);
} else {
m_frame_buffer[1][y][x] = m_frame_buffer[0][y][x];
m_frame_buffer[0][y][x] = color;
}
} else {
m_frame_buffer[y][x] = color;
}

// @todo: ensure that this is correct if translucent depth write is off.
m_depth_buffer[1][y][x] = m_depth_buffer[0][y][x];

if(opaque_pixel) {
m_depth_buffer[y][x] = depth_new;
m_depth_buffer[0][y][x] = depth_new;
attributes.poly_id[0] = polygon_id;
} else {
if(polygon.attributes.enable_translucent_depth_write) {
m_depth_buffer[y][x] = depth_new;
m_depth_buffer[0][y][x] = depth_new;
}
attributes.poly_id[1] = polygon_id;
}
Expand Down Expand Up @@ -599,4 +642,8 @@ namespace dual::nds::gpu {
return {};
}

void SoftwareRenderer::RenderAntiAliasing() {
// draw the rest of the owl
}

} // namespace dual::nds::gpu
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ namespace dual::nds::gpu {
CopyVRAM();
RenderRearPlane();
RenderPolygons(viewport, polygons);

if(m_io.disp3dcnt.enable_anti_aliasing) {
RenderAntiAliasing();
}
}

void SoftwareRenderer::CaptureColor(int scanline, std::span<u16, 256> dst_buffer, int dst_width, bool display_capture) {
// @todo: write a separate method for display capture?

for(int x = 0; x < dst_width; x++) {
const Color4& color = m_frame_buffer[scanline][x];
const Color4& color = m_frame_buffer[0][scanline][x];

if(display_capture) {
dst_buffer[x] = color.ToRGB555() | (color.A() != 0 ? 0x8000u : 0u);
Expand All @@ -37,7 +41,7 @@ namespace dual::nds::gpu {
// Most likely the alpha-blending math needs to happen with higher precision (but how many bits?).
// @todo: make this more accurate.
for(int x = 0; x < 256; x++) {
dst_buffer[x] = (m_frame_buffer[scanline][x].A().Raw() + 1) >> 2;
dst_buffer[x] = (m_frame_buffer[0][scanline][x].A().Raw() + 1) >> 2;
}
}

Expand Down

0 comments on commit 9928bbd

Please sign in to comment.