Skip to content

Commit

Permalink
deduplicate scanline code with inlined helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
Baekalfen committed Jul 12, 2024
1 parent 3475a4a commit f5853f6
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 93 deletions.
7 changes: 4 additions & 3 deletions pyboy/core/lcd.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,14 @@ cdef class Renderer:
)
cdef void scanline(self, LCD, int) noexcept nogil

@cython.locals(tile_addr=uint64_t, tile=int)
cdef inline (int, int, uint16_t) _get_tile(self, uint8_t, uint8_t, uint16_t, LCD) noexcept nogil
cdef inline (int, int, uint8_t, bint, uint32_t, bint) _get_tile_cgb(self, uint8_t, uint8_t, uint16_t, LCD) noexcept nogil
@cython.locals(col0=uint8_t)
cdef inline void _pixel(self, uint8_t[:,:], uint32_t, int, int, int, int, uint32_t) noexcept nogil
cdef int scanline_background(self, int, int, int, int, int, LCD) noexcept nogil
@cython.locals(col0=uint8_t)
cdef int scanline_window(self, int, int, int, int, int, LCD) noexcept nogil
@cython.locals(col0=uint8_t)
cdef int scanline_background_cgb(self, int, int, int, int, int, LCD) noexcept nogil
@cython.locals(col0=uint8_t)
cdef int scanline_window_cgb(self, int, int, int, int, int, LCD) noexcept nogil
cdef int scanline_blank(self, int, int, int, LCD) noexcept nogil

Expand Down
149 changes: 59 additions & 90 deletions pyboy/core/lcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,143 +500,112 @@ def scanline(self, lcd, y):
# Reset at the end of a frame. We set it to -1, so it will be 0 after the first increment
self.ly_window = -1

def _get_tile(self, y, x, offset, lcd):
tile_addr = offset + y//8*32%0x400 + x//8%32
tile = lcd.VRAM0[tile_addr]

# If using signed tile indices, modify index
if not lcd._LCDC.tiledata_select:
# (x ^ 0x80 - 128) to convert to signed, then
# add 256 for offset (reduces to + 128)
tile = (tile ^ 0x80) + 128

yy = 8*tile + y%8
return tile, yy, tile_addr

def _get_tile_cgb(self, y, x, offset, lcd):
tile, yy, tile_addr = self._get_tile(y, x, offset, lcd)

palette, vbank, horiflip, vertflip, bg_priority = self._cgb_get_background_map_attributes(lcd, tile_addr)

bg_priority_apply = 0
if bg_priority:
# We hide extra rendering information in the lower 8 bits (A) of the 32-bit RGBA format
bg_priority_apply = BG_PRIORITY_FLAG

if vertflip:
yy = (8*tile + (7 - (y) % 8))

return tile, yy, palette, horiflip, bg_priority_apply, vbank

def _pixel(self, tilecache, pixel, x, y, xx, yy, bg_priority_apply):
col0 = (tilecache[yy, xx] == 0) & 1
self._screenbuffer[y, x] = pixel
# COL0_FLAG is 1
self._screenbuffer_attributes[y, x] = bg_priority_apply | col0

def scanline_window(self, y, _x, wx, wy, cols, lcd):
for x in range(_x, _x + cols):
xx = (x-wx) % 8
if xx == 0 or x == _x:
tile_addr = lcd._LCDC.windowmap_offset + (self.ly_window) // 8 * 32 % 0x400 + (x-wx) // 8 % 32
wt = lcd.VRAM0[tile_addr]

# If using signed tile indices, modify index
if not lcd._LCDC.tiledata_select:
# (x ^ 0x80 - 128) to convert to signed, then
# add 256 for offset (reduces to + 128)
wt = (wt ^ 0x80) + 128

yy = 8*wt + (self.ly_window) % 8
wt, yy, _ = self._get_tile(self.ly_window, x - wx, lcd._LCDC.windowmap_offset, lcd)
self.update_tilecache0(lcd, wt, 0)

# TODO: Dynamic direct mapping?
pixel = lcd.BGP.palette_mem_rgb[lcd.BGP.lookup[self._tilecache0[yy, xx]]]

col0 = (self._tilecache0[yy, xx] == 0) & 1
self._screenbuffer[y, x] = pixel
# COL0_FLAG is 1
self._screenbuffer_attributes[y, x] = col0
self._pixel(self._tilecache0, pixel, x, y, xx, yy, 0)
return cols

def scanline_window_cgb(self, y, _x, wx, wy, cols, lcd):
bg_priority_apply = 0
for x in range(_x, _x + cols):
xx = (x-wx) % 8
if xx == 0 or x == _x:
tile_addr = lcd._LCDC.windowmap_offset + (self.ly_window) // 8 * 32 % 0x400 + (x-wx) // 8 % 32
wt = lcd.VRAM0[tile_addr]

# If using signed tile indices, modify index
if not lcd._LCDC.tiledata_select:
# (x ^ 0x80 - 128) to convert to signed, then
# add 256 for offset (reduces to + 128)
wt = (wt ^ 0x80) + 128

w_palette, w_vbank, w_horiflip, w_vertflip, w_bg_priority = self._cgb_get_background_map_attributes(
lcd, tile_addr
wt, yy, w_palette, w_horiflip, bg_priority_apply, vbank = self._get_tile_cgb(
self.ly_window, x - wx, lcd._LCDC.windowmap_offset, lcd
)
if w_vbank:
self.update_tilecache1(lcd, wt, w_vbank)
w_tilecache = self._tilecache1
else:
self.update_tilecache0(lcd, wt, w_vbank)
w_tilecache = self._tilecache0

if w_vertflip:
yy = (8*wt + (7 - (self.ly_window) % 8))
# NOTE: Not allowed to return memoryview in Cython tuple
if vbank:
self.update_tilecache1(lcd, wt, vbank)
tilecache = self._tilecache1
else:
yy = 8*wt + (self.ly_window) % 8
self.update_tilecache0(lcd, wt, vbank)
tilecache = self._tilecache0

if w_horiflip:
xx = 7 - xx

pixel = lcd.bcpd.palette_mem_rgb[w_palette*4 + w_tilecache[yy, xx]]
bg_priority_apply = 0
if w_bg_priority:
# We hide extra rendering information in the lower 8 bits (A) of the 32-bit RGBA format
bg_priority_apply = BG_PRIORITY_FLAG

col0 = (w_tilecache[yy, xx] == 0) & 1
self._screenbuffer[y, x] = pixel
# COL0_FLAG is 1
self._screenbuffer_attributes[y, x] = bg_priority_apply | col0
pixel = lcd.bcpd.palette_mem_rgb[w_palette*4 + tilecache[yy, xx]]
self._pixel(tilecache, pixel, x, y, xx, yy, bg_priority_apply)
return cols

def scanline_background(self, y, _x, bx, by, cols, lcd):
for x in range(_x, _x + cols):
# bx mask used for the half tile at the left side when scrolling
b_xx = (x + (bx & 0b111)) % 8
if b_xx == 0 or x == 0:
tile_addr = lcd._LCDC.backgroundmap_offset + (y+by) // 8 * 32 % 0x400 + (x+bx) // 8 % 32
bt = lcd.VRAM0[tile_addr]

# If using signed tile indices, modify index
if not lcd._LCDC.tiledata_select:
# (x ^ 0x80 - 128) to convert to signed, then
# add 256 for offset (reduces to + 128)
bt = (bt ^ 0x80) + 128

b_yy = 8*bt + (y+by) % 8
bt, b_yy, _ = self._get_tile(y + by, x + bx, lcd._LCDC.backgroundmap_offset, lcd)
self.update_tilecache0(lcd, bt, 0)

xx = b_xx
yy = b_yy

# TODO: Dynamic direct mapping?
pixel = lcd.BGP.palette_mem_rgb[lcd.BGP.lookup[self._tilecache0[yy, xx]]]

col0 = (self._tilecache0[yy, xx] == 0) & 1
self._screenbuffer[y, x] = pixel
self._screenbuffer_attributes[y, x] = col0
self._pixel(self._tilecache0, pixel, x, y, xx, yy, 0)
return cols

def scanline_background_cgb(self, y, _x, bx, by, cols, lcd):
for x in range(_x, _x + cols):
# bx mask used for the half tile at the left side when scrolling
xx = (x + (bx & 0b111)) % 8
if xx == 0 or x == 0:
tile_addr = lcd._LCDC.backgroundmap_offset + (y+by) // 8 * 32 % 0x400 + (x+bx) // 8 % 32
bt = lcd.VRAM0[tile_addr]

# If using signed tile indices, modify index
if not lcd._LCDC.tiledata_select:
# (x ^ 0x80 - 128) to convert to signed, then
# add 256 for offset (reduces to + 128)
bt = (bt ^ 0x80) + 128

b_palette, b_vbank, b_horiflip, b_vertflip, b_bg_priority = self._cgb_get_background_map_attributes(
lcd, tile_addr
bt, yy, b_palette, b_horiflip, bg_priority_apply, vbank = self._get_tile_cgb(
y + by, x + bx, lcd._LCDC.backgroundmap_offset, lcd
)
if b_vbank:
self.update_tilecache1(lcd, bt, b_vbank)
b_tilecache = self._tilecache1
# NOTE: Not allowed to return memoryview in Cython tuple
if vbank:
self.update_tilecache1(lcd, bt, vbank)
tilecache = self._tilecache1
else:
self.update_tilecache0(lcd, bt, b_vbank)
b_tilecache = self._tilecache0

if b_vertflip:
yy = (8*bt + (7 - (y+by) % 8))
else:
yy = 8*bt + (y+by) % 8
self.update_tilecache0(lcd, bt, vbank)
tilecache = self._tilecache0

if b_horiflip:
xx = 7 - xx

pixel = lcd.bcpd.palette_mem_rgb[b_palette*4 + b_tilecache[yy, xx]]
bg_priority_apply = 0
if b_bg_priority:
# We hide extra rendering information in the lower 8 bits (A) of the 32-bit RGBA format
bg_priority_apply = BG_PRIORITY_FLAG

col0 = (b_tilecache[yy, xx] == 0) & 1
self._screenbuffer[y, x] = pixel
self._screenbuffer_attributes[y, x] = bg_priority_apply | col0
pixel = lcd.bcpd.palette_mem_rgb[b_palette*4 + tilecache[yy, xx]]
self._pixel(tilecache, pixel, x, y, xx, yy, bg_priority_apply)
return cols

def scanline_blank(self, y, _x, cols, lcd):
Expand Down

0 comments on commit f5853f6

Please sign in to comment.