From 07486046c2def0f00f31998f80693d3381074405 Mon Sep 17 00:00:00 2001 From: Nathaniel Walizer Date: Sun, 29 Dec 2024 15:15:18 -0800 Subject: [PATCH] Clean up PPU and SDL render modules --- src/ppu.c | 37 ++--- src/sdl_render.c | 379 +++-------------------------------------------- 2 files changed, 31 insertions(+), 385 deletions(-) diff --git a/src/ppu.c b/src/ppu.c index 45bc16a..7dc18f4 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -32,7 +32,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { } else if (ppu_reg_data == addr) { if (ppu->addr >= nes_ppu_mem_pal_start) { -// printf("PPU: PAL READ %04x > %02x\n", ppu->addr, val); + PPU_LOG("PPU: PAL READ %04x > %02x\n", ppu->addr, val); uint8_t pal_addr = (ppu->addr - nes_ppu_mem_pal_start) & (nes_ppu_mem_pal_size - 1); @@ -42,7 +42,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { val = ppu->data; if (ppu->addr < nes_ppu_mem_vram_start) { -// printf("PPU: CHR MEM READ %04x > %02x\n", ppu->addr, val); + PPU_LOG("PPU: CHR MEM READ %04x > %02x\n", ppu->addr, val); ppu->data = nes_chr_read(ppu->mapper, ppu->addr); } else if (ppu->addr < nes_ppu_mem_vram_start + nes_ppu_mem_vram_size) { @@ -52,7 +52,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { ppu->addr - nes_ppu_mem_vram_start ); } else if (ppu->addr < nes_ppu_mem_pal_start) { - printf("PPU: BLANK READ %04x > %02x\n", ppu->addr, val); + PPU_LOG("PPU: BLANK READ %04x > %02x\n", ppu->addr, val); /* ppu->data = *(nes_map_chr_addr(ppu->mapper, ppu->addr)); @@ -69,6 +69,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { return val; } +// Copy t to v (decoded into scroll_x, control) static inline void nes_ppu_internal_copy_x(nes_ppu* ppu) { ppu->control &= ~(1U); ppu->control |= ((ppu->t >> 10) & 1U); @@ -77,9 +78,8 @@ static inline void nes_ppu_internal_copy_x(nes_ppu* ppu) { (ppu->x & 0b111U); } +// Copy t to v (decoded into scroll_y, control) static inline void nes_ppu_internal_copy_y(nes_ppu* ppu) { - // Copy t to v (decoded into scroll_x, scroll_y, ctrl) - ppu->control &= ~(0b10U); ppu->control |= ((ppu->t >> 10) & 0b10U); @@ -112,18 +112,17 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { } else if (ppu_reg_scroll == addr) { if (ppu->latch) { PPU_LOG("PPU: Scroll Y %02x\n", val); -// ppu->scroll_y = val; ppu->t &= 0b0000110000011111U; ppu->t |= (uint16_t)(val & 0b00000111U) << 12; ppu->t |= (uint16_t)(val & 0b11111000U) << 2; } else { PPU_LOG("PPU: Scroll X %02x\n", val); -// ppu->scroll_x = val; ppu->t &= ~(0b11111U); ppu->t |= (val & 0b11111000U) >> 3; ppu->x = (val & 0b111U); } + ppu->latch = !ppu->latch; } else if (ppu_reg_addr == addr) { @@ -132,13 +131,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { if (ppu->latch) { ppu->t &= 0xFF00U; ppu->t |= val; -/* - // Take advantage of the quick split quirk - ppu->scroll_x &= 0b00000111; - ppu->scroll_x |= (val & 0b00011111); - ppu->scroll_y &= 0b11000111; - ppu->scroll_y |= (val & 0b11100000) >> 2; -*/ + ppu->addr = (ppu->t & 0x3FFFU); VRAM_LOG("PPU: VRAM ADDR %04x\n", ppu->addr); @@ -152,18 +145,8 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { } else { ppu->t &= 0x00FFU; ppu->t |= (uint16_t)(0x3FU & val) << 8; -/* - // Take advantage of the quick split quirk - ppu->control &= ~ppu_Control_Nametable_Mask; - ppu->control |= (val & 0b1100) >> 2; - ppu->scroll_y &= 0b00111000; - ppu->scroll_y |= (val & 0b11) << 6; - ppu->scroll_y |= (val & 0b110000) >> 4; - - PPU_LOG("PPU: Scroll X, Y = %d, %d\n", - ppu->scroll_x, ppu->scroll_y); -*/ } + ppu->latch = !ppu->latch; } else if (ppu_reg_data == addr) { @@ -174,7 +157,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { uint8_t pal_addr = (ppu->addr - nes_ppu_mem_pal_start) & (nes_ppu_mem_pal_size - 1); -// printf("PPU: PAL %02x < %02x\n", pal_addr, val); + PPU_LOG("PPU: PAL %02x < %02x\n", pal_addr, val); ppu->palette[pal_addr] = val; if ((pal_addr & 0b11) == 0) { ppu->palette[pal_addr & 0xF] = val; @@ -206,7 +189,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { nes_vram_write(ppu->mapper, vram_addr, val); } else { -// printf("PPU: CHR MEM WRITE %04x > %02x\n", ppu->addr, val); +// PPU_LOG("PPU: CHR MEM WRITE %04x > %02x\n", ppu->addr, val); nes_chr_write(ppu->mapper, ppu->addr, val); } diff --git a/src/sdl_render.c b/src/sdl_render.c index 61a204d..bcc271d 100644 --- a/src/sdl_render.c +++ b/src/sdl_render.c @@ -248,57 +248,6 @@ static inline void render_bg_sprite_line( } } -/* -static void render_bg_sprite(const nes_ppu* ppu, int index, - const uint8_t* pal, - void* loc, int pitch) { - uint8_t* sprite = chr_mem(ppu, index * 16U); - uint8_t* dst_line = (uint8_t*)loc; - - for (int y = 8; y > 0; --y) { - uint8_t lo = sprite[0U]; - uint8_t hi = sprite[8U]; - uint8_t* dst = dst_line; - for (int x = 8; x > 0; --x) { - int pal_idx = ( ((hi & 0x80) >> 6) | - ((lo & 0x80) >> 7)); - *dst++ = (pal_idx ? pal[pal_idx] : 0xFFU); - hi <<= 1; - lo <<= 1; - } - dst_line += pitch; - ++sprite; - } -} - -static void render_background_area(const nes_ppu* ppu, int page, - void* buffer, int pitch, - int xs, int ys, int w, int h) { - int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0; - const uint8_t* index_line = nes_map_vram_addr(ppu->mapper, - page << 10); - const uint8_t* attrs = index_line + 960U; - index_line += xs + (ys * nes_ppu_blocks_w); - uint8_t* dst_line = (uint8_t*)buffer; - for (int y = ys; y < h + ys; ++y) { - uint8_t* dst = dst_line; - const uint8_t* index = index_line; - for (int x = xs; x < w + xs; ++x) { - int attr_idx = ((y / 4) * 8) + (x / 4); - int shift = 2 * ((y & 0b10) | ((x & 0b10) >> 1)); - int pal_idx = (attrs[attr_idx] >> shift) & 3; - const uint8_t* pal = &ppu->palette[pal_idx * 4]; - render_bg_sprite(ppu, bank + *index, pal, - dst, pitch); - ++index; - dst += 8; - } - dst_line += pitch * 8; - index_line += nes_ppu_blocks_w; - } -} -*/ - static inline void render_bg_scanline_area( const nes_ppu* ppu, int page, uint8_t* dst, int x, int y, int w) { @@ -338,13 +287,7 @@ static void render_bg_scanline(const nes_ppu* ppu,/* int scanline,*/ uint8_t* dst) { int page = (ppu->control & ppu_Control_Nametable_Mask); int x = ppu->scroll_x; - int y = ppu->scroll_y /*+ scanline*/; -/* - if (y >= nes_ppu_render_h) { - y -= nes_ppu_render_h; - page ^= 0b10; - } -*/ + int y = ppu->scroll_y; int w = (nes_ppu_render_w - x); if (!(ppu->mask & ppu_Mask_Left_Back)) { // Handle column 0 flag - need to fill with transparency @@ -358,70 +301,6 @@ static void render_bg_scanline(const nes_ppu* ppu,/* int scanline,*/ nes_ppu_render_w - w); } -/* -static void render_background_line(const nes_ppu* ppu, int line, - void* buffer, int pitch) { - // TODO: Handle column 0 flag - - int page = (ppu->control & ppu_Control_Nametable_Mask); - int x = ppu->scroll_x / 8; - line += ppu->scroll_y / 8; - - if (line >= nes_ppu_blocks_h) { - line -= nes_ppu_blocks_h; - page ^= 0b10; - } - - // Left - render_background_area( - ppu, page, buffer, pitch, - x, line, - nes_ppu_blocks_w - x, 1 - ); - - // Right - buffer += (nes_ppu_blocks_w - x) * 8U; - render_background_area( - ppu, page ^ 1, buffer, pitch, - 0, line, - 1U + x, 1 - ); -} - -static void render_sprite(nes_ppu* ppu, int index, - const uint8_t* pal, uint8_t attr, - void* loc, int pitch) { - uint8_t* sprite = chr_mem(ppu, index * 16U); - uint8_t* dst_line = (uint8_t*)loc; - int dx = 1; - if (attr & oam_Attr_Flip_X) { - dst_line += 7; - dx = -dx; - } - if (attr & oam_Attr_Flip_Y) { - dst_line += (7 * pitch); - pitch = -pitch; - } - - for (int y = 8; y > 0; --y) { - uint8_t lo = sprite[0U]; - uint8_t hi = sprite[8U]; - uint8_t* dst = dst_line; - for (int x = 8; x > 0; --x) { - int pal_idx = ( ((hi & 0x80) >> 6) | - ((lo & 0x80) >> 7)); - int nes_pal_idx = (pal_idx ? pal[pal_idx] : 0xFFU); - *dst = nes_pal_idx; - dst += dx; - hi <<= 1; - lo <<= 1; - } - dst_line += pitch; - ++sprite; - } -} -*/ - static void render_line_sprites(nes_ppu* ppu, uint8_t* dst_line, int scanline, const uint8_t* back, const oam_sprite* sprites, @@ -478,72 +357,6 @@ static void render_line_sprites(nes_ppu* ppu, uint8_t* dst_line, } } -/* -static void render_sprites(nes_ppu* ppu, - SDL_Surface* buffer, - SDL_Surface* target, - int background) { - int bank = (ppu->control & ppu_Control_Sprite_Bank) ? - 0x100 : 0; - const oam_sprite* sprites = (const oam_sprite*)ppu->oam; - uint8_t* dst_origin = (uint8_t*)buffer->pixels; - int pitch = buffer->pitch; - for ( int i_sprite = nes_ppu_oam_sprite_count - 1; - i_sprite >= 0; --i_sprite) { - const oam_sprite* sprite = &sprites[i_sprite]; - if ((sprite->attr & oam_Attr_Background) ^ background) { - continue; - } - if ( !(ppu->mask & ppu_Mask_Left_Sprite) && - sprite->x < 8) { - continue; - } - int y = (sprite->y + 1); - if (y >= nes_ppu_render_h) continue; - uint8_t* dst = dst_origin; - int index = sprite->index; - if (ppu->control & ppu_Control_Sprite_Size) { - bank = (index & 1) ? 0x100 : 0; - index &= 0xFEU; - } - index += bank; - int pal_idx = (sprite->attr & oam_Attr_Pal_Mask); - const uint8_t* pal = &ppu->palette[16 + (pal_idx * 4)]; - if (ppu->control & ppu_Control_Sprite_Size) { - if (sprite->attr & oam_Attr_Flip_Y) index++; - render_sprite(ppu, index, pal, sprite->attr, - dst, pitch); - dst += pitch * 8; - if (sprite->attr & oam_Attr_Flip_Y) { - index--; - } else { - index++; - } - } - render_sprite(ppu, index, pal, sprite->attr, - dst, pitch); - - SDL_Rect sprite_rect = { - .x = 0, - .y = 0, - .w = 8, - .h = (ppu->control & ppu_Control_Sprite_Size) ? - 16 : 8, - }; - - SDL_Rect target_rect = { - .x = sprite->x, - .y = y, - .w = 8, - .h = (ppu->control & ppu_Control_Sprite_Size) ? - 16 : 8, - }; - SDL_BlitSurface(buffer, &sprite_rect, - target, &target_rect); - } -} -*/ - // Check sprite (0 only) collision on a scanline // This assumes that we've verified that this sprite // intersects with this scanline. @@ -555,6 +368,8 @@ static int eval_sprite_line(const nes_ppu* ppu, int y, const uint8_t* back) { int hit_pos = -1; + // TODO: Handle Column 0 mask + if (sprite->attr & oam_Attr_Flip_Y) y = 7 - y; uint8_t lo = chr[0U + y]; uint8_t hi = chr[8U + y]; @@ -583,103 +398,6 @@ static int eval_sprite_line(const nes_ppu* ppu, int y, return hit_pos; } -#if 0 -static void update_sprite_hit(nes_ppu* ppu, int block_line, - const void* back_pixels, - int back_pitch) { - const oam_sprite* sprite = (oam_sprite*)ppu->oam; - int x_fine = ppu->scroll_x % 8; - int y_fine = ppu->scroll_x % 8; - int index = sprite->index; - if (ppu->control & ppu_Control_Sprite_Bank) { - index += 0x100U; - } - const uint8_t* chr = chr_mem(ppu, index * 16U); - int render_line = block_line * 8U; - int start_y = (sprite->y + 1) + y_fine - render_line; - int end_y = start_y + 8; - if (start_y < 8 && end_y > 0) { - if (start_y < 0) start_y = 0; - if (end_y > 8) end_y = 8; - int hit = -1; - const uint8_t* back = (uint8_t*)back_pixels + x_fine; - back += (render_line + start_y) * back_pitch; - for (int y = start_y; y < end_y; ++y) { - hit = eval_sprite_line( - ppu, render_line + y - y_fine, - sprite, chr, back - ); - if (hit >= 0) { - ppu->hit_line = y - y_fine + render_line; - ppu->hit_dot = hit; - break; - } - back += back_pitch; - } - } -} - -static void render_block_line(nes_ppu* ppu, int line, - sdl_render_data* data) { - // Render single line of blocks - - render_background_line(ppu, line, - data->background_line->pixels, - data->background_line->pitch); - - int x_fine = ppu->scroll_x % 8; - int y_fine = ppu->scroll_y % 8; - - // Check for Sprite 0 Hit - if ( 0 >= ppu->hit_line && - (ppu->mask & ppu_Mask_Sprite)) { - update_sprite_hit(ppu, line, - data->background_line->pixels, - data->background_line->pitch); - } - - // Copy line onto full background - - const uint8_t* src = data->background_line->pixels + - x_fine; - int start_y = ((line * 8U) - y_fine); - int end_y = start_y + 8; - if (start_y < 0) { - src -= (start_y * data->background_line->pitch); - start_y = 0; - } - uint8_t* dst = data->background->pixels + - (start_y * data->background->pitch); - - for (int y = start_y; y < end_y; ++y) { - if ((void*)dst >= data->background->pixels) { - memcpy(dst, src, nes_ppu_render_w); - } - src += data->background_line->pitch; - dst += data->background->pitch; - } - -/* - SDL_Rect back_rect = { - .x = x_fine, - .y = 0, - .w = nes_ppu_render_w, - .h = 8U, - }; - - SDL_Rect render_rect = { - .x = 0, - .y = (line * 8U) - y_fine, - .w = nes_ppu_render_w, - .h = 8U, - }; - - SDL_BlitSurface(data->background_line, &back_rect, - data->background, &render_rect); -*/ -} -#endif - static void update_scanline_hit(nes_ppu* ppu, uint8_t* back_line, int scanline) { const oam_sprite* sprite = &ppu->oam[0]; @@ -758,7 +476,6 @@ static void dump_line_sprites(const nes_ppu* ppu, int line, static void render_scanline(nes_ppu* ppu, int line, sdl_render_data* data) { - SDL_Rect dst_rect = { .x = 0, .y = line, @@ -788,7 +505,6 @@ static void render_scanline(nes_ppu* ppu, int line, .h = 1, }; - uint8_t* foreground = data->foreground->pixels; uint8_t* background = data->background->pixels; // We check for hits if EITHER layer is enabled. @@ -797,25 +513,26 @@ static void render_scanline(nes_ppu* ppu, int line, update_scanline_hit(ppu, background, line); } - if (line >= 0) { - oam_sprite line_sprites[8] = {0}; - int n_sprites = select_line_sprites(ppu, line, - line_sprites, 8); + oam_sprite line_sprites[8] = {0}; + int n_sprites = select_line_sprites(ppu, line, + line_sprites, 8); - dump_line_sprites(ppu, line, line_sprites, n_sprites); + dump_line_sprites(ppu, line, line_sprites, n_sprites); - if (ppu->mask & ppu_Mask_Back) { - SDL_BlitSurface(data->background, &src_rect, - data->target, &dst_rect); - } + if (ppu->mask & ppu_Mask_Back) { + SDL_BlitSurface(data->background, &src_rect, + data->target, &dst_rect); + } - if (ppu->mask & ppu_Mask_Sprite) { - memset(foreground, 0xFFU, nes_ppu_render_w); - render_line_sprites(ppu, foreground, line, background, - line_sprites, n_sprites); - SDL_BlitSurface(data->foreground, &src_rect, - data->target, &dst_rect); - } + if (ppu->mask & ppu_Mask_Sprite) { + uint8_t* foreground = data->foreground->pixels; + memset(foreground, 0xFFU, nes_ppu_render_w); + + render_line_sprites(ppu, foreground, line, background, + line_sprites, n_sprites); + + SDL_BlitSurface(data->foreground, &src_rect, + data->target, &dst_rect); } } @@ -825,34 +542,10 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { if (ppu->scanline < nes_ppu_prerender) { REND_LOG("Scanline %3d -> Prerender\n", ppu->scanline); -/* - memset(data->foreground->pixels, 0xFFU, - data->foreground->pitch * data->foreground->h); - - if (ppu->mask & ppu_Mask_Sprite) { - render_sprites(ppu, data->sprite, data->target, - oam_Attr_Background); - - render_sprites(ppu, data->sprite, data->foreground, 0); - } -*/ -/* - int line = ppu->scanline - (int)nes_ppu_prerender; - render_scanline(ppu, line, data); -*/ + // TODO: Perform evaluations here? } else if (ppu->scanline < nes_ppu_prerender + nes_ppu_height) { -/* - int line = (ppu->scanline - (int)nes_ppu_prerender) / 8; - - REND_LOG("Scanline %3d -> Line %2d @ X %d\n", ppu->scanline, line, ppu->scroll_x); - - // TODO: Only re-render if VRAM/scroll changes? - if (ppu->mask & ppu_Mask_Back) { - render_block_line(ppu, line, data); - } -*/ REND_LOG("Scanline %3d : N %d X %d Y %d\n", ppu->scanline, ppu->control & ppu_Control_Nametable_Mask, @@ -862,37 +555,7 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { } else { REND_LOG("Scanline %3d -> Postrender\n", ppu->scanline); -/* - if (ppu->mask & ppu_Mask_Sprite) { - render_sprites(ppu, data->sprite, data->target, - oam_Attr_Background); - } -*/ -/* - if (ppu->mask & ppu_Mask_Back) { - // Render final partial line - if (0 != (ppu->scroll_y % 8)) { - if (ppu->mask & ppu_Mask_Sprite) { - // TODO: Render background sprites that start this block - } - if (ppu->mask & ppu_Mask_Back) { - render_block_line(ppu, nes_ppu_blocks_h, data); - } - if (ppu->mask & ppu_Mask_Sprite) { - // TODO: Render foreground sprites that end this block - } - } - SDL_BlitSurface(data->background, NULL, - data->target, NULL); - } - - if (ppu->mask & ppu_Mask_Sprite) { - render_sprites(ppu, data->sprite, data->target, 0); - SDL_BlitSurface(data->foreground, NULL, - data->target, NULL); - } -*/ SDL_Texture* texture = SDL_CreateTextureFromSurface( data->renderer, data->target );