📄 screen.asm
字号:
%if 0
SNEeSe, an Open Source Super NES emulator.
Copyright (c) 1998-2004 Charles Bilyue'.
Portions Copyright (c) 2003-2004 Daniel Horchner.
This is free software. See 'LICENSE' for details.
You must read and accept the license prior to use.
%endif
; screen.asm
; Screen rendering code
; -BGMODE specific handlers, including specialized handlers for:
; offset change in Modes 2, 4, and 6;
; -Basic BG scanline renderers;
; -Line offset in tile tables.
;
;%define MSR_PROFILING
%define NO_PLOTTER_PER_PRIORITY
%define WATCH_RENDER_BREAKS
;%define LAYERS_PER_LINE
;%define NO_NP_RENDER
;%define NO_OFFSET_CHANGE
;%define NO_OFFSET_CHANGE_DISABLE
;%define NO_EARLY_PRIORITY_ELIMINATION
;%define OFFSET_CHANGE_ELIMINATION
%ifdef NO_NP_RENDER
%define NO_EARLY_PRIORITY_ELIMINATION
%endif
%ifndef LAYERS_PER_LINE
%define NO_EARLY_PRIORITY_ELIMINATION
%endif
%define SNEeSe_ppu_screen_asm
%include "misc.inc"
%include "clear.inc"
%include "ppu/sprites.inc"
%include "ppu/ppu.inc"
%include "ppu/tiles.inc"
%include "ppu/screen.inc"
EXTERN_C use_mmx,use_fpu_copies,preload_cache,preload_cache_2
section .text
EXPORT_C screen_text_start
section .data
EXPORT_C screen_data_start
section .bss
EXPORT_C screen_bss_start
section .data
ALIGND
%macro Generate_Tile_Offset_Table 1
dd 16*8*(%1)
dd 16*8*(%1)+1
dd 16*8*(%1)+2
dd 16*8*(%1)+3
dd 16*8*(%1)+4
dd 16*8*(%1)+5
dd 16*8*(%1)+6
dd 16*8*(%1)+7
%endmacro
EXPORT Tile_Offset_Table_16_8
Generate_Tile_Offset_Table 0
Generate_Tile_Offset_Table 1
EXPORT Screen_Mode
dd C_LABEL(SCREEN_MODE_0)
dd C_LABEL(SCREEN_MODE_1)
dd C_LABEL(SCREEN_MODE_2)
dd C_LABEL(SCREEN_MODE_3)
dd C_LABEL(SCREEN_MODE_4)
dd C_LABEL(SCREEN_MODE_5)
dd C_LABEL(SCREEN_MODE_6)
dd C_LABEL(SCREEN_MODE_7)
EXPORT palette_2bpl
dd 0x03030303, 0x07070707, 0x0B0B0B0B, 0x0F0F0F0F
dd 0x13131313, 0x17171717, 0x1B1B1B1B, 0x1F1F1F1F
EXPORT palette_4bpl
dd 0x0F0F0F0F, 0x1F1F1F1F, 0x2F2F2F2F, 0x3F3F3F3F
dd 0x4F4F4F4F, 0x5F5F5F5F, 0x6F6F6F6F, 0x7F7F7F7F
palette_2bpl_mmx:
dd 0x03030303, 0x03030303, 0x07070707, 0x07070707
dd 0x0B0B0B0B, 0x0B0B0B0B, 0x0F0F0F0F, 0x0F0F0F0F
dd 0x13131313, 0x13131313, 0x17171717, 0x17171717
dd 0x1B1B1B1B, 0x1B1B1B1B, 0x1F1F1F1F, 0x1F1F1F1F
palette_4bpl_mmx:
dd 0x0F0F0F0F, 0x0F0F0F0F, 0x1F1F1F1F, 0x1F1F1F1F
dd 0x2F2F2F2F, 0x2F2F2F2F, 0x3F3F3F3F, 0x3F3F3F3F
dd 0x4F4F4F4F, 0x4F4F4F4F, 0x5F5F5F5F, 0x5F5F5F5F
dd 0x6F6F6F6F, 0x6F6F6F6F, 0x7F7F7F7F, 0x7F7F7F7F
section .bss
;Z-buffer for display
;#L = tiles/pixels for layer # (low priority)
;#H = tiles/pixels for layer # (high priority)
;#S = sprites (# priority) 34 24 14 04
;BA = back area 00
;L7 = (2L) mode-7 EXTBG low priority 1
;N7 = (1L) mode-7 EXTBG low priority 2, mode-7 w/o EXTBG
;H7 = (2H) mode-7 EXTBG high priority
;modes 0-1
;layer 3H 3S 1H 2H 2S 1L 2L 1S 3H 4H 0S 3L 4L BA
;Z 38 34 32 31 24 22 21 14 12 11 04 02 01 00
;modes 2-7
;layer 3S 1H 2S 2H 1S 1L 0S 2L BA
;Z 34 32 24 22 14 12 04 02 00
ALIGNB
EXPORT DisplayZ,skipb (8+256+8)
ALIGNB
EXPORT_C Current_Line_Render,skipl
EXPORT_C Last_Frame_Line,skipl
EXPORT Ready_Line_Render,skipl
EXPORT BaseDestPtr ,skipl
EXPORT Render_Select,skipl ; Base renderer
EXPORT Render_Mode ,skipl ; Mode renderer
%if 0
MOSAIC
Mosaic effect uses a scanline countdown register, which is loaded at
scanline 1, and reloaded at start of every scanline where it is 0.
Backgrounds with enable bits set in MOSAIC register do not update their
scanline counters except on MOSAIC countdown reload. If mosaic effect is
enabled on a non-reload scanline, it will continue to use the previous
line's counter. If enabled on a reload scanline, it will use the current
line's counter.
Countdown register always counts down on every line during display period
(force blank not tested), even when effect is not enabled on any
background, or when size is set to 0. Countdown register is shared for all
backgrounds.
%endif
;Countdown register for MOSAIC
EXPORT MosaicCountdown ,skipl
EXPORT BGLineCount ,skipl
EXPORT LineAddress ,skipl ; Address of tileset, + offset to line in tile
EXPORT LineAddressY,skipl ; Same, for vertical flip
EXPORT TileMask ,skipl ; Tile address mask, for tileset wrap
EXPORT Palette_Base,skipl
; Used for offset change map addressing
EXPORT OffsetChangeMap_VOffset,skipl ; BG3VOFS + BG3SC
EXPORT OffsetChangeVMap_VOffset,skipl ; BG3VOFS + BG3SC (for split-table)
EXPORT Display_Needs_Update,skipb
EXPORT Tile_Layers_Enabled,skipb
EXPORT Tile_priority_bit,skipb
EXPORT Tile_Priority_Used,skipb
EXPORT Tile_Priority_Unused,skipb
EXPORT OffsetChangeDetect1,skipb
EXPORT OffsetChangeDetect2,skipb
EXPORT OffsetChangeDetect3,skipb
EXPORT_C Offset_Change_Disable ,skipb
section .text
ALIGNC
Update_Offset_Change:
mov byte [Redo_Offset_Change],0
mov al,[Redo_Offset_Change_VOffsets]
LOAD_BG_TABLE 3
test al,al
jz .no_recalc_voffsets
mov byte [Redo_Offset_Change_VOffsets],0
;OffsetChangeMap_VOffset = ((BG3VOFS / 8) & 0x1F) * 64 +
; (BG3VOFS & 0x100 ? BLMapAddressBG3 - TLMapAddressBG3 : 0);
;OffsetChangeVMap_VOffset = ((BG3VOFS / 8 + 1) & 0x1F) * 64 +
; ((BG3VOFS + 8) & 0x100 ? BLMapAddressBG3 - TLMapAddressBG3 : 0) -
; OffsetChangeMap_VOffset;
mov edi,[VScroll+edx]
shl edi,3 ; divided by 8 (base tile size),
mov ebx,[VScroll+edx]
and edi,(0x1F << 6) ; * 2 (16-bit words) * 32 (row)
and bh,1
jz .offset_line_in_map_top
mov ebx,[BLMapAddress+edx]
add edi,ebx
mov ebx,[TLMapAddress+edx]
sub edi,ebx
.offset_line_in_map_top:
mov [OffsetChangeMap_VOffset],edi
mov ebx,[VScroll+edx]
add edi,byte 32*2 ; next row
add ebx,byte 8
and edi,(0x1F << 6) ; * 2 (16-bit words) * 32 (row)
and bh,1
jz .vmap_offset_line_in_map_top
mov ebx,[BLMapAddress+edx]
add edi,ebx
mov ebx,[TLMapAddress+edx]
sub edi,ebx
.vmap_offset_line_in_map_top:
mov ebx,[OffsetChangeMap_VOffset]
sub edi,ebx
mov [OffsetChangeVMap_VOffset],edi
.no_recalc_voffsets:
; Update BG3 position for offset change
LOAD_BG_TABLE 3
mov ecx,[HScroll+edx]
mov esi,TLMapAddress
mov edi,TRMapAddress
and ch,1 ;8x8 tile size
jz .first_tile_in_left_screen_map
add esi,byte (TRMapAddress-TLMapAddress)
add edi,byte (TLMapAddress-TRMapAddress)
.first_tile_in_left_screen_map:
mov esi,[esi+edx]
mov edi,[edi+edx]
mov [VLMapAddress+edx],esi
mov [VRMapAddress+edx],edi
%ifdef OFFSET_CHANGE_ELIMINATION
xor eax,eax
mov ebx,[OffsetChangeMap_VOffset]
mov al,[HScroll + edx]
mov cl,32
shr eax,3
add esi,ebx
sub cl,al
lea esi,[esi+eax*2]
mov edx,[OffsetChangeVMap_VOffset]
add edi,ebx
mov ah,0
mov bl,0
.detect_loop:
mov ch,[esi+1]
or ah,ch
mov bh,[esi+1+edx]
add esi,byte 2
or bl,bh
dec cl
jnz .detect_loop
add cl,al
jz .detect_end
mov al,0
mov esi,edi
jmp .detect_loop
.detect_end:
mov [OffsetChangeDetect1],ah
or ah,bl
mov [OffsetChangeDetect2],bl
mov [OffsetChangeDetect3],ah
%endif
ret
%macro SORT_OFFSET_CHANGE 0
test byte [Tile_Layers_Enabled],3 ;BG1 || BG2
jz %%no_recalc
mov al,[BGMODE_Allowed_Offset_Change]
test al,al
jz %%no_recalc
mov al,[Redo_Offset_Change]
test al,al
jz %%no_recalc
call Update_Offset_Change
%%no_recalc:
%endmacro
ALIGNC
EXPORT_C Clear_Scanlines
;edi = dest address, ebp = line count
mov al,[C_LABEL(use_fpu_copies)]
test al,al
jnz .clear_fpu
mov al,[C_LABEL(use_mmx)]
test al,al
jnz .clear_mmx
xor eax,eax
mov ecx,256/4
push es
mov edx,ds
mov es,edx
cld
cmp byte [C_LABEL(preload_cache)],0
jnz C_LABEL(Clear_Scanlines_Preload).clear_loop
.clear_loop:
rep stosd
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/4
jnz .clear_loop
pop es
ret
ALIGNC
.clear_fpu:
fldz
mov ecx,256/16
.clear_fpu_loop:
fst qword [edi+0]
fst qword [edi+8]
add edi,byte 16
dec ecx
jnz .clear_fpu_loop
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/16
jnz .clear_fpu_loop
fstp st0
ret
ALIGNC
.clear_mmx:
pxor mm0,mm0
mov ecx,256/16
.clear_mmx_loop:
movq [edi+0],mm0
movq [edi+8],mm0
add edi,byte 16
dec ecx
jnz .clear_mmx_loop
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/16
jnz .clear_mmx_loop
emms
ret
ALIGNC
EXPORT_C Clear_Scanlines_Preload
;edi = dest address, ebp = line count
cmp byte [C_LABEL(preload_cache_2)],0
jz C_LABEL(Clear_Scanlines)
mov al,[C_LABEL(use_fpu_copies)]
test al,al
jnz .clear_fpu
mov al,[C_LABEL(use_mmx)]
test al,al
jnz .clear_mmx
xor eax,eax
mov ecx,256/4
push es
mov edx,ds
mov es,edx
cld
.clear_loop:
; Load area to clear into cache
mov bl,[edi+0]
mov bl,[edi+32*1]
mov bl,[edi+32*2]
mov bl,[edi+32*3]
mov bl,[edi+32*4]
mov bl,[edi+32*5]
mov bl,[edi+32*6]
mov bl,[edi+32*7]
mov bl,[edi+16]
mov bl,[edi+16*3]
mov bl,[edi+16*5]
mov bl,[edi+16*7]
mov bl,[edi+16*9]
mov bl,[edi+16*11]
mov bl,[edi+16*13]
mov bl,[edi+16*15]
rep stosd
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/4
jnz .clear_loop
pop es
ret
ALIGNC
.clear_fpu:
fldz
mov ecx,256/16
.clear_fpu_next_line:
; Load area to clear into cache
mov bl,[edi+0]
mov bl,[edi+32*1]
mov bl,[edi+32*2]
mov bl,[edi+32*3]
mov bl,[edi+32*4]
mov bl,[edi+32*5]
mov bl,[edi+32*6]
mov bl,[edi+32*7]
.clear_fpu_loop:
fst qword [edi+0]
fst qword [edi+8]
add edi,byte 16
dec ecx
jnz .clear_fpu_loop
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
mov ecx,256/16
jnz .clear_fpu_next_line
fstp st0
ret
ALIGNC
.clear_mmx:
pxor mm0,mm0
mov ecx,256/16
.clear_mmx_next_line:
; Load area to clear into cache
mov bl,[edi+0]
mov bl,[edi+32*1]
mov bl,[edi+32*2]
mov bl,[edi+32*3]
mov bl,[edi+32*4]
mov bl,[edi+32*5]
mov bl,[edi+32*6]
mov bl,[edi+32*7]
.clear_mmx_loop:
movq [edi+0],mm0
movq [edi+8],mm0
add edi,byte 16
dec ecx
jnz .clear_mmx_next_line
add edi,byte GfxBufferLineSlack ; Point screen to next line
dec ebp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -