From c3c48eaf81ceb31a784089f07bf2e8e6d2777f61 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Fri, 18 Mar 2022 06:27:37 -0300 Subject: [PATCH] feat: switch from BGR555 to RGBA8888 --- src/main.zig | 4 ++-- src/ppu.zig | 56 ++++++++++++++++++++++++++++++++++++---------------- src/util.zig | 11 +++++++++++ 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/main.zig b/src/main.zig index 3a8a869..595d2a4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -72,7 +72,7 @@ pub fn main() anyerror!void { var cpu = Arm7tdmi.init(&scheduler, &bus); cpu.fastBoot(); - var log_file: ?File = undefined; + var log_file: ?File = null; if (enable_logging) { const file_name: []const u8 = if (is_binary) "zba.bin" else "zba.log"; const file = try std.fs.cwd().createFile(file_name, .{}); @@ -112,7 +112,7 @@ pub fn main() anyerror!void { var renderer = SDL.SDL_CreateRenderer(window, -1, SDL.SDL_RENDERER_ACCELERATED | SDL.SDL_RENDERER_PRESENTVSYNC) orelse sdlPanic(); defer SDL.SDL_DestroyRenderer(renderer); - const texture = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_BGR555, SDL.SDL_TEXTUREACCESS_STREAMING, 240, 160) orelse sdlPanic(); + const texture = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_RGBA8888, SDL.SDL_TEXTUREACCESS_STREAMING, 240, 160) orelse sdlPanic(); defer SDL.SDL_DestroyTexture(texture); // Init FPS Timer diff --git a/src/ppu.zig b/src/ppu.zig index 6071d6a..b4bb5a3 100644 --- a/src/ppu.zig +++ b/src/ppu.zig @@ -11,10 +11,13 @@ const Bitfield = @import("bitfield").Bitfield; const Allocator = std.mem.Allocator; const log = std.log.scoped(.PPU); const pollBlankingDma = @import("bus/dma.zig").pollBlankingDma; +const intToBytes = @import("util.zig").intToBytes; + +const COLOUR_LUT = genColourLut(); pub const width = 240; pub const height = 160; -pub const framebuf_pitch = width * @sizeOf(u16); +pub const framebuf_pitch = width * @sizeOf(u32); pub const Ppu = struct { const Self = @This(); @@ -274,8 +277,7 @@ pub const Ppu = struct { switch (bg_mode) { 0x0 => { - const start = framebuf_pitch * @as(usize, scanline); - + const fb_base = framebuf_pitch * @as(usize, scanline); if (obj_enable) self.fetchSprites(); var i: usize = 0; @@ -292,9 +294,7 @@ pub const Ppu = struct { // If there are any nulls present in self.scanline_buf it means that no background drew a pixel there, so draw backdrop for (self.scanline_buf) |maybe_px, j| { const bgr555 = if (maybe_px) |px| px else self.palette.getBackdrop(); - - self.framebuf[(start + j * 2 + 1)] = @truncate(u8, bgr555 >> 8); - self.framebuf[(start + j * 2 + 0)] = @truncate(u8, bgr555); + std.mem.copy(u8, self.framebuf[fb_base + j * @sizeOf(u32) ..][0..4], &intToBytes(u32, COLOUR_LUT[bgr555 & 0x7FFF])); } // Reset Scanline Buffer @@ -303,23 +303,26 @@ pub const Ppu = struct { std.mem.set(?Sprite, &self.scanline_sprites, null); }, 0x3 => { - const start = framebuf_pitch * @as(usize, scanline); - std.mem.copy(u8, self.framebuf[start..][0..framebuf_pitch], self.vram.buf[start..][0..framebuf_pitch]); + const fb_base = framebuf_pitch * @as(usize, scanline); + const vram_base = width * @sizeOf(u16) * @as(usize, scanline); + + var i: usize = 0; + while (i < width) : (i += 1) { + const bgr555 = self.vram.get16(vram_base + i * @sizeOf(u16)); + std.mem.copy(u8, self.framebuf[fb_base + i * @sizeOf(u32) ..][0..4], &intToBytes(u32, COLOUR_LUT[bgr555 & 0x7FFF])); + } }, 0x4 => { const select = self.dispcnt.frame_select.read(); - const vram_start = width * @as(usize, scanline); - const buf_start = vram_start * @sizeOf(u16); - - const start = vram_start + if (select) 0xA000 else @as(usize, 0); - const end = start + width; // Each Entry is only a byte long + const fb_base = framebuf_pitch * @as(usize, scanline); + const vram_base = width * @as(usize, scanline) + if (select) 0xA000 else @as(usize, 0); // Render Current Scanline - for (self.vram.buf[start..end]) |byte, i| { - const id = @as(u16, byte) * 2; - const j = i * @sizeOf(u16); + for (self.vram.buf[vram_base .. vram_base + width]) |byte, i| { + const pal_id = @as(u16, byte) * @sizeOf(u16); + const bgr555 = self.palette.get16(pal_id); - std.mem.copy(u8, self.framebuf[(buf_start + j)..][0..2], self.palette.buf[id..][0..2]); + std.mem.copy(u8, self.framebuf[fb_base + i * @sizeOf(u32) ..][0..4], &intToBytes(u32, COLOUR_LUT[bgr555 & 0x7FFF])); } }, else => std.debug.panic("[PPU] TODO: Implement BG Mode {}", .{bg_mode}), @@ -684,3 +687,22 @@ fn spriteDimensions(shape: u2, size: u2) [2]u8 { else => std.debug.panic("{} is an invalid sprite shape", .{shape}), }; } + +fn genColourLut() [0x8000]u32 { + return comptime { + @setEvalBranchQuota(0x10001); + + var lut: [0x8000]u32 = undefined; + for (lut) |*px, i| px.* = toRgba8888(i); + return lut; + }; +} + +fn toRgba8888(bgr555: u16) u32 { + const b = @as(u32, bgr555 >> 10 & 0x1F) << 3; + const g = @as(u32, bgr555 >> 5 & 0x1F) << 3; + const r = @as(u32, bgr555 & 0x1F) << 3; + const a: u32 = 0xFF; + + return r << 24 | g << 16 | b << 8 | a; +} diff --git a/src/util.zig b/src/util.zig index 95d2744..202e7ea 100644 --- a/src/util.zig +++ b/src/util.zig @@ -42,3 +42,14 @@ pub const FpsAverage = struct { self.sample_count = 1; } }; + +pub fn intToBytes(comptime T: type, value: anytype) [@sizeOf(T)]u8 { + comptime std.debug.assert(@typeInfo(T) == .Int); + + var result: [@sizeOf(T)]u8 = undefined; + + var i: Log2Int(T) = 0; + while (i < result.len) : (i += 1) result[i] = @truncate(u8, value >> i * @bitSizeOf(u8)); + + return result; +}