-screen: Added support for screens that vary horizontal width mid-frame, and hooked it up to the SNES driver. Fixes dkongcu intro and others. [Ryan Holtz]

This commit is contained in:
MooglyGuy 2019-10-24 18:52:15 +02:00
parent e0bac48f8f
commit 100767b3df
6 changed files with 274 additions and 70 deletions

View File

@ -1865,7 +1865,7 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
if (m_screen_disabled) /* screen is forced blank */
for (int x = 0; x < SNES_SCR_WIDTH * 2; x++)
bitmap.pix32(curline, x) = rgb_t::black();
bitmap.pix32(0, x) = rgb_t::black();
else
{
/* Update clip window masks if necessary */
@ -1947,8 +1947,8 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
int g = (((c & 0x3e0) >> 5) * fade) >> 4;
int b = (((c & 0x7c00) >> 10) * fade) >> 4;
bitmap.pix32(curline, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
bitmap.pix32(curline, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
bitmap.pix32(0, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
bitmap.pix32(0, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
}
else
{
@ -1986,7 +1986,7 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
int g = (((c & 0x3e0) >> 5) * fade) >> 4;
int b = (((c & 0x7c00) >> 10) * fade) >> 4;
bitmap.pix32(curline, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
bitmap.pix32(0, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
prev_colour = tmp_col0;
/* average the second pixel if required, or draw it directly*/
@ -1999,7 +1999,7 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
g = (((c & 0x3e0) >> 5) * fade) >> 4;
b = (((c & 0x7c00) >> 10) * fade) >> 4;
bitmap.pix32(curline, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
bitmap.pix32(0, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
prev_colour = tmp_col1;
}
}

View File

@ -531,7 +531,12 @@ void screen_device::svg_renderer::rebuild_cache()
//-------------------------------------------------
screen_device::screen_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, SCREEN, tag, owner, clock)
: screen_device(mconfig, SCREEN, tag, owner, clock)
{
}
screen_device::screen_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, m_type(SCREEN_TYPE_RASTER)
, m_orientation(ROT0)
, m_phys_aspect(0U, 0U)
@ -548,6 +553,7 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev
, m_video_attributes(0)
, m_svg_region(*this, DEVICE_SELF)
, m_container(nullptr)
, m_max_width(100)
, m_width(100)
, m_height(100)
, m_visarea(0, 99, 0, 99)
@ -608,6 +614,11 @@ void screen_device::device_validity_check(validity_checker &valid) const
if (m_screen_update_ind16.isnull() && m_screen_update_rgb32.isnull())
osd_printf_error("Missing SCREEN_UPDATE function\n");
}
else
{
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
osd_printf_error("Non-raster display cannot have a variable width\n");
}
// check for zero frame rate
if (m_refresh == 0)
@ -735,7 +746,8 @@ void screen_device::device_start()
// configure bitmap formats and allocate screen bitmaps
// svg is RGB32 too, and doesn't have any update method
texture_format texformat = !m_screen_update_ind16.isnull() ? TEXFORMAT_PALETTE16 : TEXFORMAT_RGB32;
const bool screen16 = !m_screen_update_ind16.isnull();
texture_format texformat = screen16 ? TEXFORMAT_PALETTE16 : TEXFORMAT_RGB32;
for (auto & elem : m_bitmap)
{
@ -750,6 +762,25 @@ void screen_device::device_start()
m_texture[1] = machine().render().texture_alloc();
m_texture[1]->set_id((u64(m_unique_id) << 57) | 1);
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
for (int i = 0; i < m_height; i++)
{
for (int j = 0; j < 2; j++)
{
if (screen16)
{
m_scan_bitmaps[j].push_back(new bitmap_ind16(m_width, 1));
}
else
{
m_scan_bitmaps[j].push_back(new bitmap_rgb32(m_width, 1));
}
}
m_scan_widths.push_back(m_width);
}
}
// configure the default cliparea
render_container::user_settings settings;
m_container->get_user_settings(settings);
@ -877,10 +908,18 @@ void screen_device::device_timer(emu_timer &timer, device_timer_id id, int param
// first scanline
case TID_SCANLINE0:
reset_partial_updates();
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
pre_update_scanline(0);
}
break;
// subsequent scanlines when scanline updates are enabled
case TID_SCANLINE:
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
pre_update_scanline(param);
}
if (m_video_attributes & VIDEO_UPDATE_SCANLINE)
{
// force a partial update to the current scanline
@ -917,12 +956,20 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a
assert(frame_period > 0);
// fill in the new parameters
m_max_width = std::max(m_max_width, width);
m_width = width;
m_height = height;
m_visarea = visarea;
// reallocate bitmap if necessary
realloc_screen_bitmaps();
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
update_scan_bitmap_size(vpos());
}
else
{
realloc_screen_bitmaps();
}
// compute timing parameters
m_frame_period = frame_period;
@ -987,6 +1034,29 @@ void screen_device::reset_origin(int beamy, int beamx)
}
//-------------------------------------------------
// update_scan_bitmap_size - reallocate the
// bitmap for a specific scanline
//-------------------------------------------------
void screen_device::update_scan_bitmap_size(int y)
{
// determine effective size to allocate
s32 effwidth = std::max(m_max_width, m_visarea.right() + 1);
if (machine().input().code_pressed(KEYCODE_Q))
{
printf("Updating scan bitmap %d to %d (%d vs. %d)\n", y, effwidth, m_max_width, m_visarea.right() + 1);
}
if (m_scan_widths[y] == effwidth)
return;
m_scan_bitmaps[m_curbitmap][y]->resize(effwidth, 1);
m_scan_widths[y] = effwidth;
}
//-------------------------------------------------
// realloc_screen_bitmaps - reallocate bitmaps
// and textures as necessary
@ -999,7 +1069,8 @@ void screen_device::realloc_screen_bitmaps()
return;
// determine effective size to allocate
s32 effwidth = std::max(m_width, m_visarea.right() + 1);
const bool per_scanline = (m_video_attributes & VIDEO_VARIABLE_WIDTH);
s32 effwidth = std::max(per_scanline ? m_max_width : m_width, m_visarea.right() + 1);
s32 effheight = std::max(m_height, m_visarea.bottom() + 1);
// reize all registered screen bitmaps
@ -1017,6 +1088,17 @@ void screen_device::realloc_screen_bitmaps()
}
//-------------------------------------------------
// pre_update_scanline - check if the bitmap for
// a specific scanline needs its size updated
//-------------------------------------------------
void screen_device::pre_update_scanline(int y)
{
update_scan_bitmap_size(y);
}
//-------------------------------------------------
// set_visible_area - just set the visible area
//-------------------------------------------------
@ -1066,9 +1148,7 @@ bool screen_device::update_partial(int scanline)
// set the range of scanlines to render
rectangle clip(m_visarea);
clip.sety(
(std::max)(clip.top(), m_last_partial_scan),
(std::min)(clip.bottom(), scanline));
clip.sety((std::max)(clip.top(), m_last_partial_scan), (std::min)(clip.bottom(), scanline));
// skip if entirely outside of visible area
if (clip.top() > clip.bottom())
@ -1081,23 +1161,45 @@ bool screen_device::update_partial(int scanline)
LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.top(), clip.bottom()));
g_profiler.start(PROFILER_VIDEO);
u32 flags;
if (m_type != SCREEN_TYPE_SVG)
u32 flags = 0;
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
switch (curbitmap.format())
rectangle scan_clip(clip);
for (int y = clip.top(); y <= clip.bottom(); y++)
{
default:
case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
scan_clip.sety(y, y);
pre_update_scanline(y);
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
switch (curbitmap.format())
{
default:
case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break;
case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break;
}
m_partial_updates_this_frame++;
}
}
else
{
flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip);
if (m_type != SCREEN_TYPE_SVG)
{
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
switch (curbitmap.format())
{
default:
case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
}
}
else
{
flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip);
}
m_partial_updates_this_frame++;
}
m_partial_updates_this_frame++;
g_profiler.stop();
// if we modified the bitmap, we have to commit
@ -1147,11 +1249,10 @@ void screen_device::update_now()
if (m_partial_scan_hpos > 0)
{
// now finish the previous partial scanline
clip.set(
(std::max)(clip.left(), m_partial_scan_hpos),
clip.right(),
(std::max)(clip.top(), m_last_partial_scan),
(std::min)(clip.bottom(), m_last_partial_scan));
clip.set((std::max)(clip.left(), m_partial_scan_hpos),
clip.right(),
(std::max)(clip.top(), m_last_partial_scan),
(std::min)(clip.bottom(), m_last_partial_scan));
// if there's something to draw, do it
if (!clip.empty())
@ -1159,11 +1260,24 @@ void screen_device::update_now()
g_profiler.start(PROFILER_VIDEO);
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
switch (curbitmap.format())
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
default:
case BITMAP_FORMAT_IND16: m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
case BITMAP_FORMAT_RGB32: m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
pre_update_scanline(m_last_partial_scan);
switch (curbitmap.format())
{
default:
case BITMAP_FORMAT_IND16: m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][m_last_partial_scan], clip); break;
case BITMAP_FORMAT_RGB32: m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][m_last_partial_scan], clip); break;
}
}
else
{
switch (curbitmap.format())
{
default:
case BITMAP_FORMAT_IND16: m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
case BITMAP_FORMAT_RGB32: m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
}
}
m_partial_updates_this_frame++;
@ -1181,11 +1295,10 @@ void screen_device::update_now()
// now draw this partial scanline
clip = m_visarea;
clip.set(
(std::max)(clip.left(), m_partial_scan_hpos),
(std::min)(clip.right(), current_hpos),
(std::max)(clip.top(), current_vpos),
(std::min)(clip.bottom(), current_vpos));
clip.set((std::max)(clip.left(), m_partial_scan_hpos),
(std::min)(clip.right(), current_hpos),
(std::max)(clip.top(), current_vpos),
(std::min)(clip.bottom(), current_vpos));
// and if there's something to draw, do it
if (!clip.empty())
@ -1194,13 +1307,26 @@ void screen_device::update_now()
LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right()));
u32 flags;
u32 flags = 0;
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
switch (curbitmap.format())
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
default:
case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
pre_update_scanline(current_vpos);
switch (curbitmap.format())
{
default:
case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break;
case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break;
}
}
else
{
switch (curbitmap.format())
{
default:
case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
}
}
m_partial_updates_this_frame++;
@ -1254,21 +1380,28 @@ u32 screen_device::pixel(s32 x, s32 y)
if (x < 0 || y < 0 || x >= srcwidth || y >= srcheight)
return 0;
const bool per_scanline = (m_video_attributes & VIDEO_VARIABLE_WIDTH);
switch (curbitmap.format())
{
case BITMAP_FORMAT_IND16:
{
bitmap_ind16 &srcbitmap = curbitmap.as_ind16();
const u16 src = srcbitmap.pix(y, x);
bitmap_ind16 &srcbitmap = per_scanline ? *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_ind16();
const u16 src = per_scanline ? srcbitmap.pix(0, x) : srcbitmap.pix(y, x);
const rgb_t *palette = m_palette->palette()->entry_list_adjusted();
return (u32)palette[src];
}
case BITMAP_FORMAT_RGB32:
{
// iterate over rows in the destination
bitmap_rgb32 &srcbitmap = curbitmap.as_rgb32();
return (u32)srcbitmap.pix(y, x);
if (per_scanline)
{
return (u32)(*(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y]).pix(0, x);
}
else
{
return (u32)curbitmap.as_rgb32().pix(y, x);
}
}
default:
@ -1290,15 +1423,17 @@ void screen_device::pixels(u32 *buffer)
const rectangle &visarea = visible_area();
const bool per_scanline = (m_video_attributes & VIDEO_VARIABLE_WIDTH);
switch (curbitmap.format())
{
case BITMAP_FORMAT_IND16:
{
bitmap_ind16 &srcbitmap = curbitmap.as_ind16();
const rgb_t *palette = m_palette->palette()->entry_list_adjusted();
for (int y = visarea.min_y; y <= visarea.max_y; y++)
{
const u16 *src = &srcbitmap.pix(y, visarea.min_x);
bitmap_ind16 &srcbitmap = per_scanline ? *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_ind16();
const u16 *src = &srcbitmap.pix(per_scanline ? 0 : y, visarea.min_x);
for (int x = visarea.min_x; x <= visarea.max_x; x++)
{
*buffer++ = palette[*src++];
@ -1309,10 +1444,10 @@ void screen_device::pixels(u32 *buffer)
case BITMAP_FORMAT_RGB32:
{
bitmap_rgb32 &srcbitmap = curbitmap.as_rgb32();
for (int y = visarea.min_y; y <= visarea.max_y; y++)
{
const u32 *src = &srcbitmap.pix(y, visarea.min_x);
bitmap_rgb32 &srcbitmap = per_scanline ? *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_rgb32();
const u32 *src = &srcbitmap.pix(per_scanline ? 0 : y, visarea.min_x);
for (int x = visarea.min_x; x <= visarea.max_x; x++)
{
*buffer++ = *src++;
@ -1508,6 +1643,57 @@ void screen_device::vblank_end()
}
//-------------------------------------------------
// create_composited_bitmap - composite scanline
// bitmaps into the output bitmap
//-------------------------------------------------
void screen_device::create_composited_bitmap()
{
screen_bitmap &curbitmap = m_bitmap[m_curtexture];
if (!curbitmap.valid())
return;
s32 dstwidth = std::max(m_max_width, m_visarea.right() + 1);
int dstheight = curbitmap.height();
switch (curbitmap.format())
{
default:
case BITMAP_FORMAT_IND16:
{
for (int y = 0; y < dstheight; y++)
{
bitmap_ind16 &srcbitmap = *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y];
u16 *dst = &curbitmap.as_ind16().pix16(y);
const u16 *src = &srcbitmap.pix16(0);
const int dx = (m_scan_widths[y] << 15) / dstwidth;
for (int x = 0; x < m_scan_widths[y]; x += dx)
{
*dst++ = src[x >> 15];
}
}
}
case BITMAP_FORMAT_RGB32:
{
for (int y = 0; y < dstheight; y++)
{
bitmap_rgb32 &srcbitmap = *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y];
u32 *dst = &curbitmap.as_rgb32().pix32(y);
const u32 *src = &srcbitmap.pix32(0);
const int dx = (m_scan_widths[y] << 15) / dstwidth;
for (int x = 0; x < dstwidth << 15; x += dx)
{
*dst++ = src[x >> 15];
}
}
break;
}
}
}
//-------------------------------------------------
// update_quads - set up the quads for this
// screen
@ -1524,6 +1710,10 @@ bool screen_device::update_quads()
// if we're not skipping the frame and if the screen actually changed, then update the texture
if (!machine().video().skip_this_frame() && m_changed)
{
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
create_composited_bitmap();
}
m_texture[m_curbitmap]->set_bitmap(m_bitmap[m_curbitmap], m_visarea, m_bitmap[m_curbitmap].texformat());
m_curtexture = m_curbitmap;
m_curbitmap = 1 - m_curbitmap;
@ -1568,8 +1758,8 @@ void screen_device::update_burnin()
int ystep = (srcheight << 16) / dstheight;
int xstart = (u32(rand()) % 32767) * xstep / 32767;
int ystart = (u32(rand()) % 32767) * ystep / 32767;
int srcx, srcy;
int x, y;
bool per_scanline = (m_video_attributes & VIDEO_VARIABLE_WIDTH);
switch (curbitmap.format())
{
@ -1577,13 +1767,13 @@ void screen_device::update_burnin()
case BITMAP_FORMAT_IND16:
{
// iterate over rows in the destination
bitmap_ind16 &srcbitmap = curbitmap.as_ind16();
for (y = 0, srcy = ystart; y < dstheight; y++, srcy += ystep)
for (int y = 0, srcy = ystart; y < dstheight; y++, srcy += ystep)
{
bitmap_ind16 &srcbitmap = per_scanline ? *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_ind16();
u64 *dst = &m_burnin.pix64(y);
const u16 *src = &srcbitmap.pix16(srcy >> 16);
const u16 *src = &srcbitmap.pix16(per_scanline ? 0 : (srcy >> 16));
const rgb_t *palette = m_palette->palette()->entry_list_adjusted();
for (x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
for (int x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
{
rgb_t pixel = palette[src[srcx >> 16]];
dst[x] += pixel.g() + pixel.r() + pixel.b();
@ -1595,12 +1785,12 @@ void screen_device::update_burnin()
case BITMAP_FORMAT_RGB32:
{
// iterate over rows in the destination
bitmap_rgb32 &srcbitmap = curbitmap.as_rgb32();
for (y = 0, srcy = ystart; y < dstheight; y++, srcy += ystep)
for (int y = 0, srcy = ystart; y < dstheight; y++, srcy += ystep)
{
bitmap_rgb32 &srcbitmap = per_scanline ? *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_rgb32();
u64 *dst = &m_burnin.pix64(y);
const u32 *src = &srcbitmap.pix32(srcy >> 16);
for (x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
const u32 *src = &srcbitmap.pix32(per_scanline ? 0 : (srcy >> 16));
for (int x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
{
rgb_t pixel = src[srcx >> 16];
dst[x] += pixel.g() + pixel.r() + pixel.b();

View File

@ -63,6 +63,9 @@ constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed
@def VIDEO_UPDATE_SCANLINE
calls VIDEO_UPDATE for every visible scanline, even for skipped frames
@def VIDEO_VARIABLE_WIDTH
causes the screen to construct its final bitmap from a composite upscale of individual scanline bitmaps
@}
*/
@ -72,6 +75,7 @@ constexpr u32 VIDEO_UPDATE_AFTER_VBLANK = 0x0004;
constexpr u32 VIDEO_SELF_RENDER = 0x0008;
constexpr u32 VIDEO_ALWAYS_UPDATE = 0x0080;
constexpr u32 VIDEO_UPDATE_SCANLINE = 0x0100;
constexpr u32 VIDEO_VARIABLE_WIDTH = 0x0200;
//**************************************************************************
@ -182,7 +186,7 @@ public:
set_type(type);
set_color(color);
}
~screen_device();
virtual ~screen_device();
// configuration readers
screen_type_enum screen_type() const { return m_type; }
@ -224,7 +228,7 @@ public:
/// \param [in] vbstart Index of first line in vertical blanking
/// period after visible lines.
/// \return Reference to device for method chaining.
screen_device &set_raw(u32 pixclock, u16 htotal, u16 hbend, u16 hbstart, u16 vtotal, u16 vbend, u16 vbstart)
virtual screen_device &set_raw(u32 pixclock, u16 htotal, u16 hbend, u16 hbstart, u16 vtotal, u16 vbend, u16 vbstart)
{
assert(pixclock != 0);
m_clock = pixclock;
@ -389,7 +393,7 @@ public:
// beam positioning and state
int vpos() const;
int hpos() const;
virtual int hpos() const;
DECLARE_READ_LINE_MEMBER(vblank) const { return (machine().time() < m_vblank_end_time) ? 1 : 0; }
DECLARE_READ_LINE_MEMBER(hblank) const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; }
@ -403,14 +407,14 @@ public:
u64 frame_number() const { return m_frame_number; }
// pixel-level access
u32 pixel(s32 x, s32 y);
void pixels(u32* buffer);
virtual u32 pixel(s32 x, s32 y);
virtual void pixels(u32* buffer);
// updating
int partial_updates() const { return m_partial_updates_this_frame; }
bool update_partial(int scanline);
void update_now();
void reset_partial_updates();
virtual bool update_partial(int scanline);
virtual void update_now();
virtual void reset_partial_updates();
// additional helpers
void register_vblank_callback(vblank_state_delegate vblank_callback);
@ -424,7 +428,9 @@ public:
static constexpr int DEFAULT_FRAME_RATE = 60;
static const attotime DEFAULT_FRAME_PERIOD;
private:
protected:
screen_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
class svg_renderer;
// timer IDs
@ -453,6 +459,9 @@ private:
void vblank_end();
void finalize_burnin();
void load_effect_overlay(const char *filename);
void update_scan_bitmap_size(int y);
void pre_update_scanline(int y);
void create_composited_bitmap();
// inline configuration data
screen_type_enum m_type; // type of screen
@ -475,14 +484,17 @@ private:
render_container * m_container; // pointer to our container
std::unique_ptr<svg_renderer> m_svg; // the svg renderer
// dimensions
int m_max_width; // maximum width encountered
int m_width; // current width (HTOTAL)
int m_height; // current height (VTOTAL)
rectangle m_visarea; // current visible area (HBLANK end/start, VBLANK end/start)
std::vector<int> m_scan_widths; // current width, in samples, of each individual scanline
// textures and bitmaps
texture_format m_texformat; // texture format
render_texture * m_texture[2]; // 2x textures for the screen bitmap
screen_bitmap m_bitmap[2]; // 2x bitmaps for rendering
std::vector<bitmap_t *> m_scan_bitmaps[2]; // 2x bitmaps for each individual scanline
bitmap_ind8 m_priority; // priority bitmap
bitmap_ind64 m_burnin; // burn-in bitmap
u8 m_curbitmap; // current bitmap index

View File

@ -38,6 +38,7 @@ constexpr int MAX_FRAMESKIP = FRAMESKIP_LEVELS - 2;
class video_manager
{
friend class screen_device;
friend class variable_width_screen_device;
public:
// movie format options

View File

@ -1351,6 +1351,7 @@ void snes_console_state::snes(machine_config &config)
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(DOTCLK_NTSC * 2, SNES_HTOTAL * 2, 0, SNES_SCR_WIDTH * 2, SNES_VTOTAL_NTSC, 0, SNES_SCR_HEIGHT_NTSC);
m_screen->set_video_attributes(VIDEO_VARIABLE_WIDTH);
m_screen->set_screen_update(FUNC(snes_state::screen_update));
SNES_PPU(config, m_ppu, MCLK_NTSC);

View File

@ -235,7 +235,7 @@ TIMER_CALLBACK_MEMBER(snes_state::snes_hblank_tick)
hdma(cpu0space);
if (m_screen->vpos() > 0)
m_screen->update_partial((m_ppu->interlace() == 2) ? (m_ppu->current_vert() * m_ppu->interlace()) : m_ppu->current_vert());
m_screen->update_partial((m_ppu->interlace() == 2) ? (m_ppu->current_vert() * m_ppu->interlace()) : m_ppu->current_vert() - 1);
}
// signal hblank
@ -1035,7 +1035,7 @@ void snes_state::snes_init_timers()
// SNES hcounter has a 0-339 range. hblank starts at counter 260.
// clayfighter sets an HIRQ at 260, apparently it wants it to be before hdma kicks off, so we'll delay 2 pixels.
m_hblank_offset = 128;
m_hblank_offset = 274;
m_hblank_timer->adjust(m_screen->time_until_pos(m_ppu->vtotal() - 1, m_hblank_offset));
}