Difference between revisions of "Sprite Status/Slot Select"

From SpecNext official Wiki
Jump to: navigation, search
(Core 2.00.22 changes.)
(improving info about HW algorithm)
 
(9 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{Port
 
{{Port
 
|Number=$303B
 
|Number=$303B
|ShortDesc=Selects active sprite slot and palette address, and returns sprite status.
+
|NumberDec=12347
 
|PortMask=%0011 0000 0011 1011 ??
 
|PortMask=%0011 0000 0011 1011 ??
 +
|ShortDesc=Sets active sprite-attribute index and pattern-slot index, reads sprite status.
 
|Readable=Yes
 
|Readable=Yes
 
|Writable=Yes
 
|Writable=Yes
 
|Subsystem=Sprites
 
|Subsystem=Sprites
 
}}
 
}}
Used to select the sprite slot configured by {{PortNo|$xx57}} and {{PortNo|$xx5B}}. Once written, these ports may auto-increment the sprite number they are addressing. This auto-increment happens independently and so the two ports may end up addressing different sprites as a result. A write to this port will resynchronise them to the same sprite.
+
== Write functionality ==
 
+
Used to select the sprite index/slot (0..63 for pattern slots and 0..127 for sprite attribute slots) used by {{PortNo|$xx57}} and {{PortNo|$xx5B}}. Once written, these ports may auto-increment the sprite index they are addressing. This auto-increment happens independently and so the two ports may end up addressing different sprites as a result. A write to this port will resynchronise them to the same sprite. There is also {{NextRegNo|$34}}, which can be set to operate either independently or in link (bit 4 in {{NextRegNo|$09}}) with values set on this port (details in NextReg $34 description).
Also "initializes the address of the palette".
 
  
 
Write to this port with bit 7 set adds an offset of 128 to the pattern upload index (aiming at the second half of 256 byte pattern slot 0..63).
 
Write to this port with bit 7 set adds an offset of 128 to the pattern upload index (aiming at the second half of 256 byte pattern slot 0..63).
  
 +
== Read functionality ==
 
When read, returns sprite status information as follows:
 
When read, returns sprite status information as follows:
  
Line 20: Line 21:
 
| 2-7 || Reserved
 
| 2-7 || Reserved
 
|-
 
|-
| 1 || Max sprites per line flag (set if more than 12 sprites share a line)
+
| 1 || Maximum sprites per line flag.
 +
Set to 1 when sprite renderer ran out of time when preparing next scanline.
 +
Reading the port will reset it to 0.
 
|-
 
|-
| 0 || Collision flag (set if non transparent areas of any 2 sprites overlap)
+
| 0 || Collision flag.
 +
Set to 1 when non transparent pixels of any 2 sprites overlap during rendering scanline.
 +
Reading the port will reset it to 0.
 
|}
 
|}
  
It is not possible to obtain from the sprite hardware the numbers or IDs of the sprites which overlapped. The collision flag should thus be seen as initial broad phase collision detection.
+
== Sprite Engine internals information ==
 +
Sprite renderer is able to draw roughly about 1600..1800 pixels per line (exact amount depends on the video mode timing, slower modes like 50Hz will give renderer more time per line, HDMI 60Hz mode is the most demanding one, allowing only about 100,6 sprites visible per line). In practice at least 100 non-scaled 16x16 sprites should be always rendered without any issue. When up-scaled sprites are used, the rendering time may get exhausted sooner (then bit 1 "maximum sprites" will get set, and rendering is aborted unfinished with some sprite graphics (of sprites defined later in the list) missing in final result). Sprites partially reaching into screen (pixels X=0..319) from left side will use the pixel bandwidth in the same way as if the out-of-screen part of sprite was actually drawn. The sprite part crossing the right side of screen terminates drawing early, saving the pixel bandwidth for later sprites (the clip window does not affect this optimization, it is fixed to 0..319 area).
 +
 
 +
The rendering does proceed through list of sprites from sprite 0 to sprite 127, preparing sprite graphics for *next* scanline, i.e. when ULA pixel area is drawing line Y=14 (raster line register reads 14), the sprite graphics for line 14 was prepared during line 13. Thus "maximum" and "collision" flags read at the end of scanline 13 (start of scanline 14) contains already results of what is visible as line 14 on screen.
 +
 
 +
The attributes of particular sprite are read in single 28MHz cycle when the sprite rendering starts, i.e. attributes of sprite 0 are read somewhere around end of previous scanline (after pixel at sprite coordinate 319 is outputted), and as rendering progresses, attributes of sprite 127 are read somewhere toward end of scanline (or completely skipped in case the sprite renderer runs out of time due to large-scale sprites encountered early - the skipped sprites are also missing in the "collision" test, the "collision" flag is set only when particular colliding sprite pixels are rendered successfully and collision was "visible" on screen).
 +
 
 +
In case you are "multiplexing" sprites (changing sprite attributes during single frame to make particular sprite appear multiple times at screen at different lines), the sprite attributes for line ''Y'' must be updated when line ''Y-1'' video output starts (for sprite 0 obviously slightly ahead of ''Y-1'' scanline start, but not at start of ''Y-2'' scanline, as that would modify sprite position already for scanline ''Y-1'' result.
 +
 
 +
It is not possible to obtain from the sprite hardware the numbers or IDs of the sprites which overlapped in the "collision". The collision flag should thus be seen as initial broad phase collision detection (you can slightly narrow the detection by reading the flag at different scanlines, for example reading it at player's "top" line first to reset it, and at player's "bottom" line to ignore all sprite collisions happening above/below player).

Latest revision as of 23:59, 12 November 2020

Number $303B
Decimal 12347
Short desc. Sets active sprite-attribute index and pattern-slot index, reads sprite status.
Bit Mask %0011 0000 0011 1011 ??
Readable Yes
Writable Yes
Subsystem Sprites

Write functionality

Used to select the sprite index/slot (0..63 for pattern slots and 0..127 for sprite attribute slots) used by Sprite Attribute Upload ($xx57 / 87) and Sprite Pattern Upload ($xx5B / 91). Once written, these ports may auto-increment the sprite index they are addressing. This auto-increment happens independently and so the two ports may end up addressing different sprites as a result. A write to this port will resynchronise them to the same sprite. There is also Sprite port-mirror Index Register ($34), which can be set to operate either independently or in link (bit 4 in Peripheral 4 Register ($09)) with values set on this port (details in NextReg $34 description).

Write to this port with bit 7 set adds an offset of 128 to the pattern upload index (aiming at the second half of 256 byte pattern slot 0..63).

Read functionality

When read, returns sprite status information as follows:

Bit Effect
2-7 Reserved
1 Maximum sprites per line flag.

Set to 1 when sprite renderer ran out of time when preparing next scanline. Reading the port will reset it to 0.

0 Collision flag.

Set to 1 when non transparent pixels of any 2 sprites overlap during rendering scanline. Reading the port will reset it to 0.

Sprite Engine internals information

Sprite renderer is able to draw roughly about 1600..1800 pixels per line (exact amount depends on the video mode timing, slower modes like 50Hz will give renderer more time per line, HDMI 60Hz mode is the most demanding one, allowing only about 100,6 sprites visible per line). In practice at least 100 non-scaled 16x16 sprites should be always rendered without any issue. When up-scaled sprites are used, the rendering time may get exhausted sooner (then bit 1 "maximum sprites" will get set, and rendering is aborted unfinished with some sprite graphics (of sprites defined later in the list) missing in final result). Sprites partially reaching into screen (pixels X=0..319) from left side will use the pixel bandwidth in the same way as if the out-of-screen part of sprite was actually drawn. The sprite part crossing the right side of screen terminates drawing early, saving the pixel bandwidth for later sprites (the clip window does not affect this optimization, it is fixed to 0..319 area).

The rendering does proceed through list of sprites from sprite 0 to sprite 127, preparing sprite graphics for *next* scanline, i.e. when ULA pixel area is drawing line Y=14 (raster line register reads 14), the sprite graphics for line 14 was prepared during line 13. Thus "maximum" and "collision" flags read at the end of scanline 13 (start of scanline 14) contains already results of what is visible as line 14 on screen.

The attributes of particular sprite are read in single 28MHz cycle when the sprite rendering starts, i.e. attributes of sprite 0 are read somewhere around end of previous scanline (after pixel at sprite coordinate 319 is outputted), and as rendering progresses, attributes of sprite 127 are read somewhere toward end of scanline (or completely skipped in case the sprite renderer runs out of time due to large-scale sprites encountered early - the skipped sprites are also missing in the "collision" test, the "collision" flag is set only when particular colliding sprite pixels are rendered successfully and collision was "visible" on screen).

In case you are "multiplexing" sprites (changing sprite attributes during single frame to make particular sprite appear multiple times at screen at different lines), the sprite attributes for line Y must be updated when line Y-1 video output starts (for sprite 0 obviously slightly ahead of Y-1 scanline start, but not at start of Y-2 scanline, as that would modify sprite position already for scanline Y-1 result.

It is not possible to obtain from the sprite hardware the numbers or IDs of the sprites which overlapped in the "collision". The collision flag should thus be seen as initial broad phase collision detection (you can slightly narrow the detection by reading the flag at different scanlines, for example reading it at player's "top" line first to reset it, and at player's "bottom" line to ignore all sprite collisions happening above/below player).