summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices
diff options
context:
space:
mode:
author MooglyGuy <therealmogminer@gmail.com>2019-10-17 23:40:37 +0200
committer MooglyGuy <therealmogminer@gmail.com>2019-10-17 23:55:15 +0200
commit1ff29d0a13ba8cd07f2723d0cc46551880dbfd19 (patch)
treeb4e37f7e9fb7f2a0fd8ac3fe61ed0a056f111146 /src/devices
parente65d3bfb269e222b802c9746d5261377d22415c9 (diff)
-snes_ppu: Fixed background layer drawing based on higan ppu-fast. [byuu, Ryan Holtz]
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/video/snes_ppu.cpp559
-rw-r--r--src/devices/video/snes_ppu.h30
2 files changed, 377 insertions, 212 deletions
diff --git a/src/devices/video/snes_ppu.cpp b/src/devices/video/snes_ppu.cpp
index 8b0f2ec06ec..0890a3d3df2 100644
--- a/src/devices/video/snes_ppu.cpp
+++ b/src/devices/video/snes_ppu.cpp
@@ -75,7 +75,7 @@
#include "emu.h"
#include "video/snes_ppu.h"
-#define KEYPRESS_DEBUG_PRINTS (0)
+#define KEYPRESS_DEBUG_PRINTS (1)
#if KEYPRESS_DEBUG_PRINTS
static bool s_debug_prints = false;
@@ -183,7 +183,9 @@ enum
{
SNES_COLOR_DEPTH_2BPP = 0,
SNES_COLOR_DEPTH_4BPP,
- SNES_COLOR_DEPTH_8BPP
+ SNES_COLOR_DEPTH_8BPP,
+ SNES_COLOR_DEPTH_NONE,
+ SNES_COLOR_DEPTH_MODE7
};
@@ -253,6 +255,7 @@ void snes_ppu_device::device_start()
save_item(NAME(m_layer[i].tilemap), i);
save_item(NAME(m_layer[i].tilemap_size), i);
save_item(NAME(m_layer[i].tile_size), i);
+ save_item(NAME(m_layer[i].tile_mode), i);
save_item(NAME(m_layer[i].mosaic_enabled), i);
save_item(NAME(m_layer[i].main_window_enabled), i);
save_item(NAME(m_layer[i].sub_window_enabled), i);
@@ -260,6 +263,10 @@ void snes_ppu_device::device_start()
save_item(NAME(m_layer[i].sub_bg_enabled), i);
save_item(NAME(m_layer[i].hoffs), i);
save_item(NAME(m_layer[i].voffs), i);
+ save_item(NAME(m_layer[i].priority[0]), i);
+ save_item(NAME(m_layer[i].priority[1]), i);
+ save_item(NAME(m_layer[i].mosaic_counter), i);
+ save_item(NAME(m_layer[i].mosaic_offset), i);
save_item(NAME(m_clipmasks[i]), i);
}
@@ -325,7 +332,7 @@ void snes_ppu_device::device_start()
save_item(NAME(m_clip_to_black));
save_item(NAME(m_prevent_color_math));
save_item(NAME(m_sub_add_mode));
- save_item(NAME(m_bg3_priority_bit));
+ save_item(NAME(m_bg_priority));
save_item(NAME(m_direct_color));
save_item(NAME(m_ppu_last_scroll));
save_item(NAME(m_mode7_last_scroll));
@@ -541,10 +548,7 @@ inline void snes_ppu_device::set_scanline_pixel( int screen, int16_t x, uint16_t
inline void snes_ppu_device::draw_bgtile_lores( uint8_t layer, int16_t ii, uint8_t colour, uint16_t pal, uint8_t direct_colors, uint8_t priority )
{
- int screen;
- uint16_t c;
-
- for (screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++)
+ for (int screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++)
{
if (ii >= 0 && ii < SNES_SCR_WIDTH && m_scanlines[screen].enable)
{
@@ -565,7 +569,7 @@ inline void snes_ppu_device::draw_bgtile_lores( uint8_t layer, int16_t ii, uint8
/* Only draw if we have a colour (0 == transparent) */
if (clr)
{
- c = get_bgcolor(direct_colors, pal, clr);
+ uint16_t c = get_bgcolor(direct_colors, pal, clr);
set_scanline_pixel(screen, ii, c, priority, layer, 0);
}
}
@@ -575,10 +579,7 @@ inline void snes_ppu_device::draw_bgtile_lores( uint8_t layer, int16_t ii, uint8
inline void snes_ppu_device::draw_bgtile_hires( uint8_t layer, int16_t ii, uint8_t colour, uint16_t pal, uint8_t direct_colors, uint8_t priority )
{
- int screen;
- uint16_t c;
-
- for (screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++)
+ for (int screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++)
{
// odd pixels to main screen, even pixels to sub screen
if (ii >= 0 && ii < (SNES_SCR_WIDTH << 1) && ((ii & 1) ^ screen) && m_scanlines[screen].enable)
@@ -600,7 +601,7 @@ inline void snes_ppu_device::draw_bgtile_hires( uint8_t layer, int16_t ii, uint8
/* Only draw if we have a colour (0 == transparent) */
if (clr)
{
- c = get_bgcolor(direct_colors, pal, clr);
+ uint16_t c = get_bgcolor(direct_colors, pal, clr);
set_scanline_pixel(screen, ii >> 1, c, priority, layer, 0);
}
}
@@ -610,12 +611,9 @@ inline void snes_ppu_device::draw_bgtile_hires( uint8_t layer, int16_t ii, uint8
inline void snes_ppu_device::draw_oamtile( int16_t ii, uint8_t colour, uint16_t pal, uint8_t priority )
{
- int screen;
- int blend;
- uint16_t c;
int16_t pos = ii & 0x1ff;
- for (screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++)
+ for (int screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++)
{
if (pos >= 0 && pos < SNES_SCR_WIDTH && m_scanlines[screen].enable)
{
@@ -634,8 +632,8 @@ inline void snes_ppu_device::draw_oamtile( int16_t ii, uint8_t colour, uint16_t
/* Only draw if we have a colour (0 == transparent) */
if (clr)
{
- c = m_cgram[(pal + clr) % FIXED_COLOUR];
- blend = (pal + clr < 192) ? 1 : 0;
+ uint16_t c = m_cgram[(pal + clr) % FIXED_COLOUR];
+ int blend = (pal + clr < 192) ? 1 : 0;
set_scanline_pixel(screen, pos, c, priority, SNES_OAM, blend);
}
}
@@ -728,13 +726,30 @@ inline void snes_ppu_device::draw_tile( uint8_t planes, uint8_t layer, uint32_t
* but in general it works as described.
*************************************************************************************************/
+inline uint32_t snes_ppu_device::get_tile( uint8_t layer_idx, uint32_t hoffset, uint32_t voffset )
+{
+ layer_t &self = m_layer[layer_idx];
+ bool hires = m_mode == 5 || m_mode == 6;
+ uint32_t tile_height = 3 + self.tile_size;
+ uint32_t tile_width = !hires ? tile_height : 4;
+ uint32_t screenx = self.tilemap_size & 1 ? 32 << 5 : 0;
+ uint32_t screeny = self.tilemap_size & 2 ? 32 << (5 + (self.tilemap_size & 1)) : 0;
+ uint32_t tilex = hoffset >> tile_width;
+ uint32_t tiley = voffset >> tile_height;
+ uint32_t offset = (tiley & 0x1f) << 5 | (tilex & 0x1f);
+ if (tilex & 0x20) offset += screenx;
+ if (tiley & 0x20) offset += screeny;
+ uint32_t addr = ((self.tilemap + offset) & 0x7fff) << 1;
+ return m_vram[addr] | (m_vram[addr + 1] << 8);
+}
+
/*********************************************
* get_tmap_addr()
*
* Find the address in VRAM of the tile (x,y)
*********************************************/
-inline uint32_t snes_ppu_device::get_tmap_addr( uint8_t layer, uint8_t tile_size, uint32_t base, uint32_t x, uint32_t y )
+inline uint32_t snes_ppu_device::get_tmap_addr( uint8_t layer, uint8_t hires, uint8_t tile_size, uint32_t base, uint32_t x, uint32_t y )
{
uint32_t res = base;
x >>= (3 + tile_size);
@@ -757,28 +772,14 @@ inline uint32_t snes_ppu_device::get_tmap_addr( uint8_t layer, uint8_t tile_size
* Update an entire line of tiles.
*********************************************/
-inline void snes_ppu_device::update_line( uint16_t curline, uint8_t layer, uint8_t priority_b, uint8_t priority_a, uint8_t color_depth, uint8_t hires, uint8_t offset_per_tile, uint8_t direct_colors )
+inline void snes_ppu_device::update_line( uint16_t curline, uint8_t layer_idx, uint8_t direct_colors )
{
-#if KEYPRESS_DEBUG_PRINTS
- if (s_debug_prints) printf("L:%d ", layer);
-#endif
+ layer_t &layer = m_layer[layer_idx];
- int tile_incr = 0;
- uint16_t opt_bit = (layer == SNES_BG1) ? 13 : (layer == SNES_BG2) ? 14 : 0;
- /* variables depending on color_depth */
- uint8_t color_planes = 2 << color_depth;
- /* below we cheat to simplify the code: 8BPP should have 0 pal offset, not 0x100 (but we take care of this by later using pal % FIXED_COLOUR) */
- uint8_t color_shift = 2 << color_depth;
-
-#if SNES_LAYER_DEBUG
- if (m_debug_options.bg_disabled[layer])
- return;
-#endif /* SNES_LAYER_DEBUG */
-
- m_scanlines[SNES_MAINSCREEN].enable = m_layer[layer].main_bg_enabled;
- m_scanlines[SNES_SUBSCREEN].enable = m_layer[layer].sub_bg_enabled;
- m_scanlines[SNES_MAINSCREEN].clip = m_layer[layer].main_window_enabled;
- m_scanlines[SNES_SUBSCREEN].clip = m_layer[layer].sub_window_enabled;
+ m_scanlines[SNES_MAINSCREEN].enable = layer.main_bg_enabled;
+ m_scanlines[SNES_SUBSCREEN].enable = layer.sub_bg_enabled;
+ m_scanlines[SNES_MAINSCREEN].clip = layer.main_window_enabled;
+ m_scanlines[SNES_SUBSCREEN].clip = layer.sub_window_enabled;
if (!m_scanlines[SNES_MAINSCREEN].enable && !m_scanlines[SNES_SUBSCREEN].enable)
{
@@ -788,155 +789,182 @@ inline void snes_ppu_device::update_line( uint16_t curline, uint8_t layer, uint8
return;
}
- /* Handle Mosaic effects */
- if (m_layer[layer].mosaic_enabled)
- curline -= (curline % (m_mosaic_size + 1));
+ bool hires = m_mode == 5 || m_mode == 6;
+ bool opt_mode = m_mode == 2 || m_mode == 4 || m_mode == 6;
+ bool direct_color_mode = direct_colors && layer_idx == SNES_BG1 && (m_mode == 3 || m_mode == 4);
+ uint32_t color_shift = 3 + layer.tile_mode;
+ int width = 256 << hires;
- if ((m_interlace == 2) && !hires && !m_pseudo_hires)
- curline /= 2;
+ uint32_t tile_height = 3 + layer.tile_size;
+ uint32_t tile_width = !hires ? tile_height : 4;
+ uint32_t tile_mask = 0x0fff >> layer.tile_mode;
+ uint32_t tiledata_index = layer.charmap >> (3 + layer.tile_mode);
- /* Find the size of the tiles (8x8 or 16x16) */
- uint8_t tile_size = m_layer[layer].tile_size;
+ uint32_t palette_base = m_mode == 0 ? layer_idx << 5 : 0;
+ uint32_t palette_shift = 2 << layer.tile_mode;
- /* Find scroll info */
- uint32_t xoff = m_layer[layer].hoffs;
- uint32_t yoff = m_layer[layer].voffs;
+ uint32_t hscroll = layer.hoffs;
+ uint32_t vscroll = layer.voffs;
+ uint32_t hmask = (width << layer.tile_size << !!(layer.tilemap_size & 1)) - 1;
+ uint32_t vmask = (width << layer.tile_size << !!(layer.tilemap_size & 2)) - 1;
- uint8_t xscroll = xoff & ((1 << (3 + tile_size)) - 1);
+ uint32_t y = layer.mosaic_enabled ? layer.mosaic_offset : curline;
- /* Jump to base map address */
- uint32_t tmap = m_layer[layer].tilemap << 9;
- uint32_t charaddr = m_layer[layer].charmap << 13;
+ if (hires)
+ {
+ hscroll <<= 1;
+ if (m_interlace) y = y << 1 | (m_stat78 >> 7);
+ }
-#if KEYPRESS_DEBUG_PRINTS
- if (s_debug_prints) printf("TS:%d XO:%d YO:%d XS:%d TM:%08x CA:%08x\n", tile_size, xoff, yoff, xscroll, tmap, charaddr);
-#endif
+ uint32_t mosaic_counter = 1;
+ uint32_t mosaic_palette = 0;
+ uint32_t mosaic_priority = 0;
+ uint32_t mosaic_color = 0;
- uint16_t ii = 0;
- while (ii < 256 + (8 << tile_size))
+ int x = 0 - (hscroll & 7);
+ while (x < width)
{
- // determine the horizontal position (Bishoujo Janshi Suchie-Pai & Desert Fighter have tile_size & hires == 1)
- uint32_t xpos = xoff + (ii << (tile_size * hires));
- uint32_t ypos = yoff + curline;
-
- if (offset_per_tile != SNES_OPT_NONE)
+ uint32_t hoffset = x + hscroll;
+ uint32_t voffset = y + vscroll;
+ if (opt_mode)
{
- int opt_x = ii + (xoff & 7);
- uint32_t haddr, vaddr;
- uint16_t hval, vval;
-
- if (opt_x >= 8)
+ uint32_t valid_bit = 0x2000 << layer_idx;
+ uint32_t offset_x = x + (hscroll & 7);
+ if (offset_x >= 8) // first column is exempt
{
- switch (offset_per_tile)
+ uint32_t hlookup = get_tile(SNES_BG3, (offset_x - 8) + (m_layer[SNES_BG3].hoffs & ~7), m_layer[SNES_BG3].voffs);
+ if (m_mode == 4)
{
- case SNES_OPT_MODE2:
- case SNES_OPT_MODE6:
- haddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff));
- vaddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff) + 8);
- hval = m_vram[haddr % SNES_VRAM_SIZE] | (m_vram[(haddr + 1) % SNES_VRAM_SIZE] << 8);
- vval = m_vram[vaddr % SNES_VRAM_SIZE] | (m_vram[(vaddr + 1) % SNES_VRAM_SIZE] << 8);
- if (BIT(hval, opt_bit))
- xpos = opt_x + (hval & ~7);
- if (BIT(vval, opt_bit))
- ypos = curline + vval;
- break;
- case SNES_OPT_MODE4:
- haddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff));
- hval = m_vram[haddr % SNES_VRAM_SIZE] | (m_vram[(haddr + 1) % SNES_VRAM_SIZE] << 8);
- if (BIT(hval, opt_bit))
+ if (hlookup & valid_bit)
{
- if (!BIT(hval, 15))
- xpos = opt_x + (hval & ~7);
+ if (!(hlookup & 0x8000))
+ {
+ hoffset = offset_x + (hlookup & ~7);
+ }
else
- ypos = curline + hval;
+ {
+ voffset = y + hlookup;
+ }
+ }
+ }
+ else
+ {
+ uint32_t vlookup = get_tile(SNES_BG3, (offset_x - 8) + (m_layer[SNES_BG3].hoffs & ~7), m_layer[SNES_BG3].voffs + 8);
+ if (hlookup & valid_bit)
+ {
+ hoffset = offset_x + (hlookup & ~7);
+ }
+ if (vlookup & valid_bit)
+ {
+ voffset = y + vlookup;
}
- break;
}
}
}
- uint32_t addr = get_tmap_addr(layer, tile_size, tmap, xpos, ypos);
-
- /*
- Tilemap format
- vhopppcc cccccccc
-
- v/h = Vertical/Horizontal flip this tile.
- o = Tile priority.
- ppp = Tile palette. The number of entries in the palette depends on the Mode and the BG.
- cccccccccc = Tile number.
- */
- uint16_t tilemap = m_vram[addr % SNES_VRAM_SIZE] | (m_vram[(addr + 1) % SNES_VRAM_SIZE] << 8);
- uint16_t vflip = BIT(tilemap, 15);
- uint16_t hflip = BIT(tilemap, 14);
- uint8_t priority = BIT(tilemap, 13) ? priority_a : priority_b;
- uint16_t pal_direct = ((tilemap & 0x1c00) >> 8);
- uint32_t tile = tilemap & 0x03ff;
-
- uint16_t pal = ((pal_direct >> 2) << color_shift);
-
- /* Mode 0 palettes are layer specific */
- if (m_mode == 0)
- {
- pal += (layer << 5);
- }
-
-#if SNES_LAYER_DEBUG
- /* if we want to draw only one of the priorities of this layer */
- if (((m_debug_options.select_pri[layer] & 0x01) && (priority == priority_a)) ||
- ((m_debug_options.select_pri[layer] & 0x02) && (priority == priority_b)))
+ hoffset &= hmask;
+ voffset &= vmask;
+
+ uint32_t tile_number = get_tile(layer_idx, hoffset, voffset);
+ uint32_t mirrory = tile_number & 0x8000 ? 7 : 0;
+ uint32_t mirrorx = tile_number & 0x4000 ? 7 : 0;
+ uint8_t tile_priority = layer.priority[BIT(tile_number, 13)];
+ uint32_t palette_number = tile_number >> 10 & 7;
+ uint32_t palette_index = (palette_base + (palette_number << palette_shift)) & 0xff;
+
+ if (tile_width == 4 && (bool(hoffset & 8) ^ bool(mirrorx))) tile_number += 1;
+ if (tile_height == 4 && (bool(voffset & 8) ^ bool(mirrory))) tile_number += 16;
+ tile_number = ((tile_number & 0x03ff) + tiledata_index) & tile_mask;
+
+ uint16_t address = (((tile_number << color_shift) + ((voffset & 7) ^ mirrory)) & 0x7fff) << 1;
+
+ uint64_t data;
+ data = (uint64_t)m_vram[address + 0] << 0;
+ data |= (uint64_t)m_vram[address + 1] << 8;
+ data |= (uint64_t)m_vram[address + 16] << 16;
+ data |= (uint64_t)m_vram[address + 17] << 24;
+ data |= (uint64_t)m_vram[address + 32] << 32;
+ data |= (uint64_t)m_vram[address + 33] << 40;
+ data |= (uint64_t)m_vram[address + 48] << 48;
+ data |= (uint64_t)m_vram[address + 49] << 56;
+
+ for (uint32_t tilex = 0; tilex < 8; tilex++, x++)
{
- if (!hires && tile_size)
- ii += 16;
- else
- ii += 8;
- continue;
- }
-#endif /* SNES_LAYER_DEBUG */
-
- /* figure out which line to draw */
- int8_t yscroll = ypos & ((8 << tile_size) - 1);
-
- if (tile_size)
- if (BIT(yscroll, 3) != vflip)
- tile += 16;
-
- if (yscroll > 7)
- yscroll &= 7;
-
- if (vflip)
- yscroll = 7 - yscroll;
+ if (x & width) continue;
+ if (!layer.mosaic_enabled || --mosaic_counter == 0)
+ {
+ uint32_t color, shift = mirrorx ? tilex : 7 - tilex;
+ {
+ color = data >> (shift + 0) & 0x01;
+ color |= data >> (shift + 7) & 0x02;
+ }
+ if (layer.tile_mode >= SNES_COLOR_DEPTH_4BPP)
+ {
+ color |= data >> (shift + 14) & 0x04;
+ color |= data >> (shift + 21) & 0x08;
+ }
+ if (layer.tile_mode >= SNES_COLOR_DEPTH_8BPP)
+ {
+ color |= data >> (shift + 28) & 0x10;
+ color |= data >> (shift + 35) & 0x20;
+ color |= data >> (shift + 42) & 0x40;
+ color |= data >> (shift + 49) & 0x80;
+ }
- yscroll <<= 1;
+ mosaic_counter = 1 + m_mosaic_size;
+ mosaic_palette = color;
+ mosaic_priority = tile_priority;
+ if (direct_color_mode)
+ {
+ mosaic_color = direct_color(palette_number, mosaic_palette);
+ }
+ else
+ {
+ mosaic_color = m_cgram[palette_index + mosaic_palette];
+ }
+ }
+ if (!mosaic_palette) continue;
- /* if we have to draw 16 pixels, set tile_incr and adjust tile for horizontal flip */
- if (tile_size || hires)
- {
- if (hflip)
+ if (!hires)
{
- tile += 1;
- tile_incr = -1; // next 8 pixels from previous tile (because of hflip)
+ if (layer.main_bg_enabled && mosaic_priority > m_scanlines[SNES_MAINSCREEN].priority[x])
+ {
+ if (!m_scanlines[SNES_MAINSCREEN].clip || m_clipmasks[layer_idx][x])
+ {
+ set_scanline_pixel(SNES_MAINSCREEN, x, mosaic_color, mosaic_priority, layer_idx, 0);
+ }
+ }
+ if (layer.sub_bg_enabled && mosaic_priority > m_scanlines[SNES_SUBSCREEN].priority[x])
+ {
+ if (!m_scanlines[SNES_SUBSCREEN].clip || m_clipmasks[layer_idx][x])
+ {
+ set_scanline_pixel(SNES_SUBSCREEN, x, mosaic_color, mosaic_priority, layer_idx, 0);
+ }
+ }
}
else
- tile_incr = 1; // next 8 pixels from next tile
- }
-
- if (hires)
- {
- /* draw 16 pixels (the routine will automatically send half of them to the mainscreen scanline and half to the subscreen one) */
- draw_tile(color_planes, layer, charaddr + (((tile + 0) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires);
- draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2 + 8, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires);
- ii += 8;
- }
- else
- {
- draw_tile(color_planes, layer, charaddr + ((tile & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires);
- ii += 8;
-
- if (tile_size)
{
- draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires);
- ii += 8;
+ uint32_t _x = x >> 1;
+ if (x & 1)
+ {
+ if (layer.main_bg_enabled && mosaic_priority > m_scanlines[SNES_MAINSCREEN].priority[_x])
+ {
+ if (!m_scanlines[SNES_MAINSCREEN].clip || m_clipmasks[layer_idx][_x])
+ {
+ set_scanline_pixel(SNES_MAINSCREEN, _x, mosaic_color, mosaic_priority, layer_idx, 0);
+ }
+ }
+ }
+ else
+ {
+ if (layer.sub_bg_enabled && mosaic_priority > m_scanlines[SNES_SUBSCREEN].priority[_x])
+ {
+ if (!m_scanlines[SNES_SUBSCREEN].clip || m_clipmasks[layer_idx][_x])
+ {
+ set_scanline_pixel(SNES_SUBSCREEN, _x, mosaic_color, mosaic_priority, layer_idx, 0);
+ }
+ }
+ }
}
}
}
@@ -951,8 +979,10 @@ inline void snes_ppu_device::update_line( uint16_t curline, uint8_t layer, uint8
#define MODE7_CLIP(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff))
-void snes_ppu_device::update_line_mode7( uint16_t curline, uint8_t layer, uint8_t priority_b, uint8_t priority_a )
+void snes_ppu_device::update_line_mode7( uint16_t curline, uint8_t layer )
{
+ uint8_t priority_a = m_layer[layer].priority[0];
+ uint8_t priority_b = m_layer[layer].priority[1];
uint32_t tiled;
int16_t ma, mb, mc, md;
int32_t xc, yc, tx, ty, sx, sy, hs, vs, xpos, xdir, x0, y0;
@@ -1470,10 +1500,10 @@ void snes_ppu_device::update_mode_0( uint16_t curline )
#endif /* SNES_LAYER_DEBUG */
update_objects(3, 6, 9, 12);
- update_line(curline, SNES_BG1, 8, 11, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG2, 7, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG3, 2, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG4, 1, 4, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0);
+ update_line(curline, SNES_BG1, 0);
+ update_line(curline, SNES_BG2, 0);
+ update_line(curline, SNES_BG3, 0);
+ update_line(curline, SNES_BG4, 0);
}
void snes_ppu_device::update_mode_1( uint16_t curline )
@@ -1483,19 +1513,19 @@ void snes_ppu_device::update_mode_1( uint16_t curline )
return;
#endif /* SNES_LAYER_DEBUG */
- if (!m_bg3_priority_bit)
+ if (!m_bg_priority)
{
update_objects(2, 4, 7, 10);
- update_line(curline, SNES_BG1, 6, 9, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG2, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG3, 1, 3, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0);
+ update_line(curline, SNES_BG1, 0);
+ update_line(curline, SNES_BG2, 0);
+ update_line(curline, SNES_BG3, 0);
}
else
{
update_objects(2, 3, 6, 9);
- update_line(curline, SNES_BG1, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG2, 4, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG3, 1, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0);
+ update_line(curline, SNES_BG1, 0);
+ update_line(curline, SNES_BG2, 0);
+ update_line(curline, SNES_BG3, 0);
}
}
@@ -1507,8 +1537,8 @@ void snes_ppu_device::update_mode_2( uint16_t curline )
#endif /* SNES_LAYER_DEBUG */
update_objects(2, 4, 6, 8);
- update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0);
- update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0);
+ update_line(curline, SNES_BG1, 0);
+ update_line(curline, SNES_BG2, 0);
}
void snes_ppu_device::update_mode_3( uint16_t curline )
@@ -1519,8 +1549,8 @@ void snes_ppu_device::update_mode_3( uint16_t curline )
#endif /* SNES_LAYER_DEBUG */
update_objects(2, 4, 6, 8);
- update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_NONE, m_direct_color);
- update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0);
+ update_line(curline, SNES_BG1, m_direct_color);
+ update_line(curline, SNES_BG2, 0);
}
void snes_ppu_device::update_mode_4( uint16_t curline )
@@ -1531,8 +1561,8 @@ void snes_ppu_device::update_mode_4( uint16_t curline )
#endif /* SNES_LAYER_DEBUG */
update_objects(2, 4, 6, 8);
- update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_MODE4, m_direct_color);
- update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_MODE4, 0);
+ update_line(curline, SNES_BG1, m_direct_color);
+ update_line(curline, SNES_BG2, 0);
}
void snes_ppu_device::update_mode_5( uint16_t curline )
@@ -1543,8 +1573,8 @@ void snes_ppu_device::update_mode_5( uint16_t curline )
#endif /* SNES_LAYER_DEBUG */
update_objects(2, 4, 6, 8);
- update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_NONE, 0);
- update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 1, SNES_OPT_NONE, 0);
+ update_line(curline, SNES_BG1, 0);
+ update_line(curline, SNES_BG2, 0);
}
void snes_ppu_device::update_mode_6( uint16_t curline )
@@ -1555,7 +1585,7 @@ void snes_ppu_device::update_mode_6( uint16_t curline )
#endif /* SNES_LAYER_DEBUG */
update_objects(1, 3, 4, 6);
- update_line(curline, SNES_BG1, 2, 5, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_MODE6, 0);
+ update_line(curline, SNES_BG1, 0);
}
void snes_ppu_device::update_mode_7( uint16_t curline )
@@ -1568,13 +1598,13 @@ void snes_ppu_device::update_mode_7( uint16_t curline )
if (!m_mode7.extbg)
{
update_objects(1, 3, 4, 5);
- update_line_mode7(curline, SNES_BG1, 2, 2);
+ update_line_mode7(curline, SNES_BG1);
}
else
{
update_objects(2, 4, 6, 7);
- update_line_mode7(curline, SNES_BG1, 3, 3);
- update_line_mode7(curline, SNES_BG2, 1, 5);
+ update_line_mode7(curline, SNES_BG1);
+ update_line_mode7(curline, SNES_BG2);
}
}
@@ -1586,6 +1616,8 @@ void snes_ppu_device::update_mode_7( uint16_t curline )
void snes_ppu_device::draw_screens( uint16_t curline )
{
+ if (s_debug_prints) printf("M:%d ", m_mode);
+
switch (m_mode)
{
case 0: update_mode_0(curline); break; /* Mode 0 */
@@ -1614,19 +1646,17 @@ void snes_ppu_device::draw_screens( uint16_t curline )
void snes_ppu_device::update_windowmasks( void )
{
- uint16_t ii, jj;
- int8_t w1, w2;
-
m_update_windows = 0; /* reset the flag */
- for (ii = 0; ii < SNES_SCR_WIDTH; ii++)
+ for (uint16_t ii = 0; ii < SNES_SCR_WIDTH; ii++)
{
- /* update bg 1, 2, 3, 4, obj & color windows */
+ /* update obj & color windows */
/* jj = layer */
- for (jj = 0; jj < 6; jj++)
+ for (uint16_t jj = 0; jj < 6; jj++)
{
m_clipmasks[jj][ii] = 0xff; /* let's start from un-masked */
- w1 = w2 = -1;
+ int8_t w1 = -1;
+ int8_t w2 = -1;
if (m_layer[jj].window1_enabled)
{
@@ -1879,6 +1909,8 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
/* Prepare OAM for this scanline */
update_objects_rto(curline);
+ cache_background();
+
/* Draw scanline */
draw_screens(curline);
@@ -2273,6 +2305,126 @@ WRITE8_MEMBER( snes_ppu_device::cgram_write )
((uint8_t *)m_cgram.get())[offset] = data;
}
+uint16_t snes_ppu_device::direct_color(uint16_t palette, uint16_t group)
+{
+ //palette = -------- BBGGGRRR
+ //group = -------- -----bgr
+ //output = 0BBb00GG Gg0RRRr0
+ return (palette << 7 & 0x6000) + (group << 10 & 0x1000)
+ + (palette << 4 & 0x0380) + (group << 5 & 0x0040)
+ + (palette << 2 & 0x001c) + (group << 1 & 0x0002);
+}
+
+void snes_ppu_device::cache_background()
+{
+ for (int i = SNES_BG1; i <= SNES_BG4; i++)
+ {
+ if (m_beam.current_vert == 0)
+ {
+ m_layer[i].mosaic_counter = m_mosaic_size + 1;
+ m_layer[i].mosaic_offset = 1;
+ }
+ else if (--m_layer[i].mosaic_counter == 0)
+ {
+ m_layer[i].mosaic_counter = m_mosaic_size + 1;
+ m_layer[i].mosaic_offset += m_mosaic_size + 1;
+ }
+ }
+}
+
+void snes_ppu_device::update_video_mode()
+{
+ switch (m_mode)
+ {
+ case 0:
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_2BPP;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_2BPP;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_2BPP;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_2BPP;
+ m_layer[SNES_BG1].priority[0] = 8; m_layer[SNES_BG1].priority[1] = 11;
+ m_layer[SNES_BG2].priority[0] = 7; m_layer[SNES_BG2].priority[1] = 10;
+ m_layer[SNES_BG3].priority[0] = 2; m_layer[SNES_BG3].priority[1] = 5;
+ m_layer[SNES_BG4].priority[0] = 1; m_layer[SNES_BG4].priority[1] = 4;
+ break;
+ case 1:
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_4BPP;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_4BPP;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_2BPP;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ if (m_bg_priority)
+ {
+ m_layer[SNES_BG1].priority[0] = 5; m_layer[SNES_BG1].priority[1] = 8;
+ m_layer[SNES_BG2].priority[0] = 4; m_layer[SNES_BG2].priority[1] = 7;
+ m_layer[SNES_BG3].priority[0] = 1; m_layer[SNES_BG3].priority[1] = 10;
+ }
+ else
+ {
+ m_layer[SNES_BG1].priority[0] = 6; m_layer[SNES_BG1].priority[1] = 9;
+ m_layer[SNES_BG2].priority[0] = 5; m_layer[SNES_BG2].priority[1] = 8;
+ m_layer[SNES_BG3].priority[0] = 1; m_layer[SNES_BG3].priority[1] = 3;
+ }
+ break;
+ case 2:
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_4BPP;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_4BPP;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG1].priority[0] = 3; m_layer[SNES_BG1].priority[1] = 7;
+ m_layer[SNES_BG2].priority[0] = 1; m_layer[SNES_BG2].priority[1] = 5;
+ break;
+ case 3:
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_8BPP;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_4BPP;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG1].priority[0] = 3; m_layer[SNES_BG1].priority[1] = 7;
+ m_layer[SNES_BG2].priority[0] = 1; m_layer[SNES_BG2].priority[1] = 5;
+ break;
+ case 4:
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_8BPP;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_2BPP;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG1].priority[0] = 3; m_layer[SNES_BG1].priority[1] = 7;
+ m_layer[SNES_BG2].priority[0] = 1; m_layer[SNES_BG2].priority[1] = 5;
+ break;
+ case 5:
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_4BPP;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_2BPP;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG1].priority[0] = 3; m_layer[SNES_BG1].priority[1] = 7;
+ m_layer[SNES_BG2].priority[0] = 1; m_layer[SNES_BG2].priority[1] = 5;
+ break;
+ case 6:
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_4BPP;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG1].priority[0] = 2; m_layer[SNES_BG1].priority[1] = 5;
+ break;
+ case 7:
+ if (m_mode7.extbg)
+ {
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_MODE7;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG1].priority[0] = 2; m_layer[SNES_BG1].priority[1] = 2;
+ }
+ else
+ {
+ m_layer[SNES_BG1].tile_mode = SNES_COLOR_DEPTH_MODE7;
+ m_layer[SNES_BG2].tile_mode = SNES_COLOR_DEPTH_MODE7;
+ m_layer[SNES_BG3].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG4].tile_mode = SNES_COLOR_DEPTH_NONE;
+ m_layer[SNES_BG1].priority[0] = 3; m_layer[SNES_BG1].priority[1] = 3;
+ m_layer[SNES_BG2].priority[0] = 1; m_layer[SNES_BG2].priority[1] = 5;
+ }
+ break;
+ }
+}
+
uint8_t snes_ppu_device::read(address_space &space, uint32_t offset, uint8_t wrio_bit7)
{
uint8_t value;
@@ -2483,12 +2635,12 @@ void snes_ppu_device::write(address_space &space, uint32_t offset, uint8_t data)
case BGMODE: /* BG mode and character size settings */
m_mode = data & 0x07;
dynamic_res_change();
- m_bg3_priority_bit = BIT(data, 3);
+ m_bg_priority = BIT(data, 3);
m_layer[SNES_BG1].tile_size = BIT(data, 4);
m_layer[SNES_BG2].tile_size = BIT(data, 5);
m_layer[SNES_BG3].tile_size = BIT(data, 6);
m_layer[SNES_BG4].tile_size = BIT(data, 7);
- m_update_offsets = 1;
+ update_video_mode();
break;
case MOSAIC: /* Size and screen designation for mosaic */
m_mosaic_size = (data & 0xf0) >> 4;
@@ -2501,16 +2653,16 @@ void snes_ppu_device::write(address_space &space, uint32_t offset, uint8_t data)
case BG2SC: /* Address for storing SC data BG2 SC size designation */
case BG3SC: /* Address for storing SC data BG3 SC size designation */
case BG4SC: /* Address for storing SC data BG4 SC size designation */
- m_layer[offset - BG1SC].tilemap = data & 0xfc;
+ m_layer[offset - BG1SC].tilemap = data << 8 & 0x7c00;
m_layer[offset - BG1SC].tilemap_size = data & 0x3;
break;
case BG12NBA: /* Address for BG 1 and 2 character data */
- m_layer[SNES_BG1].charmap = (data & 0x0f);
- m_layer[SNES_BG2].charmap = (data & 0xf0) >> 4;
+ m_layer[SNES_BG1].charmap = data << 12 & 0x7000;
+ m_layer[SNES_BG2].charmap = data << 8 & 0x7000;
break;
case BG34NBA: /* Address for BG 3 and 4 character data */
- m_layer[SNES_BG3].charmap = (data & 0x0f);
- m_layer[SNES_BG4].charmap = (data & 0xf0) >> 4;
+ m_layer[SNES_BG3].charmap = data << 12 & 0x7000;
+ m_layer[SNES_BG4].charmap = data << 8 & 0x7000;
break;
// Anomie says "H Current = (Byte<<8) | (Prev&~7) | ((Current>>8)&7); V Current = (Current<<8) | Prev;" and Prev is shared by all scrolls but in Mode 7!
@@ -2820,6 +2972,7 @@ void snes_ppu_device::write(address_space &space, uint32_t offset, uint8_t data)
if ((data & 0x8) != (PPU_REG(SETINI) & 0x8))
osd_printf_debug("Pseudo 512 mode: %s\n", (data & 0x8) ? "on" : "off");
#endif
+ update_video_mode();
break;
}
@@ -2963,4 +3116,4 @@ uint8_t snes_ppu_device::dbg_video( uint16_t curline )
return 0;
}
-#endif /* SNES_LAYER_DEBUG */
+#endif /* SNES_LAYER_DEBUG */ \ No newline at end of file
diff --git a/src/devices/video/snes_ppu.h b/src/devices/video/snes_ppu.h
index baab1e264b1..91563fbdb78 100644
--- a/src/devices/video/snes_ppu.h
+++ b/src/devices/video/snes_ppu.h
@@ -111,7 +111,7 @@ protected:
SNES_SCANLINE m_scanlines[2];
- struct
+ struct layer_t
{
/* clipmasks */
uint8_t window1_enabled, window1_invert;
@@ -120,11 +120,12 @@ protected:
/* color math enabled */
uint8_t color_math;
- uint8_t charmap;
- uint8_t tilemap;
+ uint16_t charmap;
+ uint16_t tilemap;
uint8_t tilemap_size;
uint8_t tile_size;
+ uint8_t tile_mode;
uint8_t mosaic_enabled; // actually used only for layers 0->3!
uint8_t main_window_enabled;
@@ -134,7 +135,14 @@ protected:
uint16_t hoffs;
uint16_t voffs;
- } m_layer[6]; // this is for the BG1 - BG2 - BG3 - BG4 - OBJ - color layers
+
+ uint8_t priority[2];
+
+ uint16_t mosaic_counter;
+ uint16_t mosaic_offset;
+ };
+
+ layer_t m_layer[6]; // this is for the BG1 - BG2 - BG3 - BG4 - OBJ - color layers
struct
{
@@ -219,7 +227,7 @@ protected:
uint8_t m_clip_to_black;
uint8_t m_prevent_color_math;
uint8_t m_sub_add_mode;
- uint8_t m_bg3_priority_bit;
+ uint8_t m_bg_priority;
uint8_t m_direct_color;
uint8_t m_ppu_last_scroll; /* as per Anomie's doc and Theme Park, all scroll regs shares (but mode 7 ones) the same
'previous' scroll value */
@@ -262,9 +270,10 @@ protected:
inline void draw_bgtile_hires(uint8_t layer, int16_t ii, uint8_t colour, uint16_t pal, uint8_t direct_colors, uint8_t priority);
inline void draw_oamtile(int16_t ii, uint8_t colour, uint16_t pal, uint8_t priority);
inline void draw_tile(uint8_t planes, uint8_t layer, uint32_t tileaddr, int16_t x, uint8_t priority, uint8_t flip, uint8_t direct_colors, uint16_t pal, uint8_t hires);
- inline uint32_t get_tmap_addr(uint8_t layer, uint8_t tile_size, uint32_t base, uint32_t x, uint32_t y);
- inline void update_line(uint16_t curline, uint8_t layer, uint8_t priority_b, uint8_t priority_a, uint8_t color_depth, uint8_t hires, uint8_t offset_per_tile, uint8_t direct_colors);
- void update_line_mode7(uint16_t curline, uint8_t layer, uint8_t priority_b, uint8_t priority_a);
+ inline uint32_t get_tmap_addr(uint8_t layer, uint8_t hires, uint8_t tile_size, uint32_t base, uint32_t x, uint32_t y);
+ inline uint32_t get_tile(uint8_t layer_idx, uint32_t hoffset, uint32_t voffset);
+ inline void update_line(uint16_t curline, uint8_t layer, uint8_t direct_colors);
+ void update_line_mode7(uint16_t curline, uint8_t layer);
void update_obsel(void);
void oam_list_build(void);
int is_sprite_on_scanline(uint16_t curline, uint8_t sprite);
@@ -281,6 +290,9 @@ protected:
void draw_screens(uint16_t curline);
void update_windowmasks(void);
void update_offsets(void);
+ void update_video_mode(void);
+ void cache_background(void);
+ uint16_t direct_color(uint16_t palette, uint16_t group);
inline void draw_blend(uint16_t offset, uint16_t *colour, uint8_t prevent_color_math, uint8_t black_pen_clip, int switch_screens);
void dynamic_res_change();
@@ -314,4 +326,4 @@ private:
DECLARE_DEVICE_TYPE(SNES_PPU, snes_ppu_device)
-#endif // MAME_VIDEO_SNES_PPU_H
+#endif // MAME_VIDEO_SNES_PPU_H \ No newline at end of file