Update screen driver

This commit is contained in:
OM3GAZX committed 2026-07-08 14:32:20 -06:00
1 parent bf2d3c85a9
commit 45d64b0804
2 files changed
+247 -164

No files matched your search

+222 -129
View File
@@ -12,6 +12,8 @@
#include "screen.h"
#include "emuopts.h"
#include "fileio.h"
#include "main.h"
#include "render.h"
#include "rendutil.h"
@@ -20,6 +22,19 @@
#include <set>
#ifdef __LIBRETRO__
#include "libretro/osdretro.h"
#endif
//**************************************************************************
// DEBUGGING
//**************************************************************************
#define VERBOSE (0)
#define LOG_PARTIAL_UPDATES(x) do { if (VERBOSE) logerror x; } while (0)
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -543,8 +558,9 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev
, m_curbitmap(0)
, m_curtexture(0)
, m_changed(true)
, m_last_partial_reset(attotime::zero)
, m_last_partial_scan(0)
, m_partial_scan_hpos(-1)
, m_partial_scan_hpos(0)
, m_color(rgb_t(0xff, 0xff, 0xff, 0xff))
, m_brightness(0xff)
, m_frame_period(DEFAULT_FRAME_PERIOD.as_attoseconds())
@@ -760,8 +776,6 @@ void screen_device::device_resolve_objects()
// bind our handlers
m_screen_update_ind16.resolve();
m_screen_update_rgb32.resolve();
m_screen_vblank.resolve_safe();
m_scanline_cb.resolve();
// assign our format to the palette before it starts
if (m_palette)
@@ -824,15 +838,19 @@ void screen_device::device_start()
m_container->set_user_settings(settings);
// allocate the VBLANK timers
m_vblank_begin_timer = timer_alloc(TID_VBLANK_START);
m_vblank_end_timer = timer_alloc(TID_VBLANK_END);
m_vblank_begin_timer = timer_alloc(FUNC(screen_device::vblank_begin), this);
m_vblank_end_timer = timer_alloc(FUNC(screen_device::vblank_end), this);
// allocate a timer to reset partial updates
m_scanline0_timer = timer_alloc(TID_SCANLINE0);
m_scanline0_timer = timer_alloc(FUNC(screen_device::first_scanline_tick), this);
// allocate a timer to generate per-scanline updates
if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb)
m_scanline_timer = timer_alloc(TID_SCANLINE);
if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset())
m_scanline_timer = timer_alloc(FUNC(screen_device::scanline_tick), this);
#ifdef __LIBRETRO__
screen_configured = 0;
#endif
// configure the screen with the default parameters
configure(m_width, m_height, m_visarea, m_refresh);
@@ -842,7 +860,7 @@ void screen_device::device_start()
m_vblank_end_time = attotime(0, m_vblank_period);
// start the timer to generate per-scanline updates
if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb)
if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset())
m_scanline_timer->adjust(time_until_pos(0));
// create burn-in bitmap
@@ -867,6 +885,7 @@ void screen_device::device_start()
save_item(NAME(m_visarea.min_y));
save_item(NAME(m_visarea.max_x));
save_item(NAME(m_visarea.max_y));
save_item(NAME(m_last_partial_reset));
save_item(NAME(m_last_partial_scan));
save_item(NAME(m_frame_period));
save_item(NAME(m_brightness));
@@ -876,6 +895,9 @@ void screen_device::device_start()
save_item(NAME(m_vblank_start_time));
save_item(NAME(m_vblank_end_time));
save_item(NAME(m_frame_number));
if (m_oldstyle_vblank_supplied)
logerror("%s: Deprecated legacy Old Style screen configured (set_vblank_time), please use set_raw instead.\n",this->tag());
m_is_primary_screen = (this == screen_device_enumerator(machine().root_device()).first());
}
@@ -917,56 +939,41 @@ void screen_device::device_post_load()
//-------------------------------------------------
// device_timer - called whenever a device timer
// fires
// timer events
//-------------------------------------------------
void screen_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
TIMER_CALLBACK_MEMBER(screen_device::first_scanline_tick)
{
switch (id)
// first scanline
reset_partial_updates();
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
// signal VBLANK start
case TID_VBLANK_START:
vblank_begin();
break;
// signal VBLANK end
case TID_VBLANK_END:
vblank_end();
break;
// 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
update_partial(param);
}
if (m_scanline_cb)
m_scanline_cb(param);
// compute the next visible scanline
param++;
if (param > m_visarea.bottom())
param = m_visarea.top();
m_scanline_timer->adjust(time_until_pos(param), param);
break;
pre_update_scanline(0);
}
}
TIMER_CALLBACK_MEMBER(screen_device::scanline_tick)
{
// subsequent scanlines when scanline updates are enabled
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
update_partial(param);
}
if (!m_scanline_cb.isunset())
m_scanline_cb(param);
// compute the next visible scanline
param++;
if (param > m_visarea.bottom())
param = m_visarea.top();
m_scanline_timer->adjust(time_until_pos(param), param);
}
//-------------------------------------------------
// configure - configure screen parameters
@@ -1006,6 +1013,15 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a
else
m_vblank_period = m_scantime * (height - visarea.height());
#ifdef __LIBRETRO__
/* Performance hack fix for "pong" and "breakout" */
if (screen_configured > 10
&& width == m_width
&& height == m_height
&& floorf(ATTOSECONDS_TO_HZ(frame_period)) == floorf(ATTOSECONDS_TO_HZ(m_frame_period)))
return;
#endif
// we are now fully configured with the new parameters
// and can safely call time_until_pos(), etc.
@@ -1013,7 +1029,7 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a
// call the VBLANK start timer now; otherwise, adjust it for the future
attoseconds_t delta = (machine().time() - m_vblank_start_time).as_attoseconds();
if (delta >= m_frame_period)
vblank_begin();
vblank_begin(0);
else
m_vblank_begin_timer->adjust(time_until_vblank_start());
@@ -1026,6 +1042,17 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a
// adjust speed if necessary
machine().video().update_refresh_speed();
#ifdef __LIBRETRO__
float retro_fps_new = ATTOSECONDS_TO_HZ(m_frame_period);
if (!screen_configured
&& retro_fps_new != retro_fps
&& retro_fps_new <= 120.0f
&& retro_fps_new >= 40.0f)
retro_fps = retro_fps_new;
screen_configured++;
#endif
}
@@ -1041,19 +1068,19 @@ void screen_device::reset_origin(int beamy, int beamx)
m_vblank_end_time = curtime - attotime(0, beamy * m_scantime + beamx * m_pixeltime);
m_vblank_start_time = m_vblank_end_time - attotime(0, m_vblank_period);
// if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start,
// call the VBLANK start timer now; otherwise, adjust it for the future
if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0)
vblank_begin(0);
else
m_vblank_begin_timer->adjust(time_until_vblank_start());
// if we are resetting relative to (0,0) == VBLANK end, call the
// scanline 0 timer by hand now; otherwise, adjust it for the future
if (beamy == 0 && beamx == 0)
reset_partial_updates();
else
m_scanline0_timer->adjust(time_until_pos(0));
// if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start,
// call the VBLANK start timer now; otherwise, adjust it for the future
if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0)
vblank_begin();
else
m_vblank_begin_timer->adjust(time_until_vblank_start());
}
@@ -1143,21 +1170,40 @@ void screen_device::set_visible_area(int min_x, int max_x, int min_y, int max_y)
bool screen_device::update_partial(int scanline)
{
LOG_PARTIAL_UPDATES(("Partial: update_partial(%s, %d): ", tag(), scanline));
// these two checks only apply if we're allowed to skip frames
if (!(m_video_attributes & VIDEO_ALWAYS_UPDATE))
{
// if skipping this frame, bail
if (machine().video().skip_this_frame())
{
LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n"));
return false;
}
// skip if this screen is not visible anywhere
if (!machine().render().is_live(*this))
{
LOG_PARTIAL_UPDATES(("skipped because screen not live\n"));
return false;
}
}
// skip if we already rendered this line
if (scanline < m_last_partial_scan)
{
LOG_PARTIAL_UPDATES(("skipped because line was already rendered\n"));
return false;
}
// skip if we already rendered this frame
// this can happen if a cpu timeslice that called update_partial is in the previous frame while scanline 0 already started
if (m_last_partial_scan == 0 && m_last_partial_reset > machine().time())
{
LOG_PARTIAL_UPDATES(("skipped because frame was already rendered\n"));
return false;
}
// set the range of scanlines to render
rectangle clip(m_visarea);
@@ -1165,46 +1211,61 @@ bool screen_device::update_partial(int scanline)
// skip if entirely outside of visible area
if (clip.top() > clip.bottom())
{
LOG_PARTIAL_UPDATES(("skipped because outside of visible area\n"));
return false;
}
// otherwise, render
LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.top(), clip.bottom()));
u32 flags = 0;
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
rectangle scan_clip(clip);
for (int y = clip.top(); y <= clip.bottom(); y++)
auto profile = g_profiler.start(PROFILER_VIDEO);
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
scan_clip.sety(y, y);
pre_update_scanline(y);
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, *(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;
}
scan_clip.sety(y, y);
pre_update_scanline(y);
m_partial_updates_this_frame++;
}
}
else
{
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;
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
{
// optional screen_update callback before rendering svg (eg. for preparing outputs used by the svg)
// bitmap can be considered read-only, as it gets overwritten later
if (!m_screen_update_rgb32.isnull())
flags = m_screen_update_rgb32(*this, m_bitmap[m_curbitmap].as_rgb32(), clip);
if (~flags & UPDATE_HAS_NOT_CHANGED)
flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip);
}
m_partial_updates_this_frame++;
}
m_partial_updates_this_frame++;
// stop profiling
}
// if we modified the bitmap, we have to commit
@@ -1212,7 +1273,7 @@ bool screen_device::update_partial(int scanline)
// remember where we left off
m_last_partial_scan = scanline + 1;
m_partial_scan_hpos = -1;
m_partial_scan_hpos = 0;
return true;
}
@@ -1229,11 +1290,17 @@ void screen_device::update_now()
{
// if skipping this frame, bail
if (machine().video().skip_this_frame())
{
LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n"));
return;
}
// skip if this screen is not visible anywhere
if (!machine().render().is_live(*this))
{
LOG_PARTIAL_UPDATES(("skipped because screen not live\n"));
return;
}
}
int current_vpos = vpos();
@@ -1242,20 +1309,36 @@ void screen_device::update_now()
// skip if we already rendered this line
if (current_vpos < m_last_partial_scan)
{
LOG_PARTIAL_UPDATES(("skipped because line was already rendered\n"));
return;
}
// if beam position is the same, there's nothing to update
if (current_vpos == m_last_partial_scan && current_hpos == m_partial_scan_hpos)
{
LOG_PARTIAL_UPDATES(("skipped because beam position is unchanged\n"));
return;
}
// skip if we already rendered this frame
// this can happen if a cpu timeslice that called update_now is in the previous frame while scanline 0 already started
if (m_last_partial_scan == 0 && m_partial_scan_hpos == 0 && m_last_partial_reset > machine().time())
{
LOG_PARTIAL_UPDATES(("skipped because frame was already rendered\n"));
return;
}
LOG_PARTIAL_UPDATES(("update_now(): Y=%d, X=%d, last partial %d, partial hpos %d (vis %d %d)\n", current_vpos, current_hpos, m_last_partial_scan, m_partial_scan_hpos, m_visarea.right(), m_visarea.bottom()));
// start off by doing a partial update up to the line before us, in case that was necessary
if (current_vpos > m_last_partial_scan)
{
// if the line before us was incomplete, we must do it in two pieces
if (m_partial_scan_hpos >= 0)
if (m_partial_scan_hpos > 0)
{
// now finish the previous partial scanline
clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1),
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));
@@ -1263,6 +1346,8 @@ void screen_device::update_now()
// if there's something to draw, do it
if (!clip.empty())
{
auto profile = g_profiler.start(PROFILER_VIDEO);
u32 flags = 0;
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
@@ -1291,7 +1376,7 @@ void screen_device::update_now()
m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
}
m_partial_scan_hpos = -1;
m_partial_scan_hpos = 0;
m_last_partial_scan++;
}
if (current_vpos > m_last_partial_scan)
@@ -1301,42 +1386,49 @@ void screen_device::update_now()
}
// now draw this partial scanline
clip = m_visarea;
clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1),
(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())
if (current_hpos > 0)
{
u32 flags = 0;
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
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;
}
}
clip = m_visarea;
m_partial_updates_this_frame++;
clip.set((std::max)(clip.left(), m_partial_scan_hpos),
(std::min)(clip.right(), current_hpos - 1),
(std::max)(clip.top(), current_vpos),
(std::min)(clip.bottom(), current_vpos));
// if we modified the bitmap, we have to commit
m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
// and if there's something to draw, do it
if (!clip.empty())
{
auto profile = g_profiler.start(PROFILER_VIDEO);
LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right()));
u32 flags = 0;
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
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++;
// if we modified the bitmap, we have to commit
m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
}
}
// remember where we left off
@@ -1352,8 +1444,9 @@ void screen_device::update_now()
void screen_device::reset_partial_updates()
{
m_last_partial_reset = machine().time();
m_last_partial_scan = 0;
m_partial_scan_hpos = -1;
m_partial_scan_hpos = 0;
m_partial_updates_this_frame = 0;
m_scanline0_timer->adjust(time_until_pos(0));
}
@@ -1592,7 +1685,7 @@ void screen_device::register_screen_bitmap(bitmap_t &bitmap)
// signal the VBLANK period has begun
//-------------------------------------------------
void screen_device::vblank_begin()
TIMER_CALLBACK_MEMBER(screen_device::vblank_begin)
{
// reset the starting VBLANK time
m_vblank_start_time = machine().time();
@@ -1612,7 +1705,7 @@ void screen_device::vblank_begin()
// if no VBLANK period, call the VBLANK end callback immediately, otherwise reset the timer
if (m_vblank_period == 0)
vblank_end();
vblank_end(0);
else
m_vblank_end_timer->adjust(time_until_vblank_end());
}
@@ -1623,7 +1716,7 @@ void screen_device::vblank_begin()
// signal the VBLANK period has ended
//-------------------------------------------------
void screen_device::vblank_end()
TIMER_CALLBACK_MEMBER(screen_device::vblank_end)
{
// call the screen specific callbacks
for (auto &item : m_callback_list)
@@ -1873,7 +1966,7 @@ void screen_device::finalize_burnin()
//-------------------------------------------------
// finalize_burnin - finalize the burnin bitmap
// load_effect_overlay -
//-------------------------------------------------
void screen_device::load_effect_overlay(const char *filename)
+25 -35
View File
@@ -13,6 +13,8 @@
#pragma once
#include "rendertypes.h"
#include <type_traits>
#include <utility>
@@ -31,28 +33,18 @@ enum screen_type_enum
SCREEN_TYPE_SVG
};
// texture formats
enum texture_format
{
TEXFORMAT_UNDEFINED = 0, // require a format to be specified
TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha
TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB
TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB
TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence
};
// screen_update callback flags
constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed
constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed
/*!
@defgroup flags for video_attributes
@{
@def VIDEO_UPDATE_BEFORE_VBLANK
update_video called at the start of the VBLANK period
update_video called at the start of the VBLANK period, this is the default
@todo hack, remove me
@def VIDEO_UPDATE_AFTER_VBLANK
update_video called at the end of the VBLANK period
update_video called at the end of the VBLANK period (in other words: before active display)
@todo hack, remove me
@def VIDEO_SELF_RENDER
@@ -233,9 +225,10 @@ public:
screen_device &set_raw(u32 pixclock, u16 htotal, u16 hbend, u16 hbstart, u16 vtotal, u16 vbend, u16 vbstart)
{
assert(pixclock != 0);
m_clock = pixclock;
set_clock(pixclock);
m_refresh = HZ_TO_ATTOSECONDS(pixclock) * htotal * vtotal;
m_vblank = m_refresh / vtotal * (vtotal - (vbstart - vbend));
m_oldstyle_vblank_supplied = false;
m_width = htotal;
m_height = vtotal;
m_visarea.set(hbend, hbstart ? hbstart - 1 : htotal - 1, vbend, vbstart - 1);
@@ -246,6 +239,10 @@ public:
xtal.validate(std::string("Configuring screen ") + tag());
return set_raw(xtal.value(), htotal, hbend, hbstart, vtotal, vbend, vbstart);
}
screen_device &set_raw(const XTAL &xtal, u16 htotal, u16 vtotal, rectangle visarea)
{
return set_raw(xtal, htotal, visarea.left(), visarea.right() + 1, vtotal, visarea.top(), visarea.bottom() + 1);
}
void set_refresh(attoseconds_t rate) { m_refresh = rate; }
/// \brief Set refresh rate in Hertz
@@ -389,8 +386,8 @@ public:
// beam positioning and state
int vpos() const;
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; }
int vblank() const { return (machine().time() < m_vblank_end_time) ? 1 : 0; }
int hblank() const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; }
// timing
attotime time_until_pos(int vpos, int hpos = 0) const;
@@ -428,30 +425,22 @@ public:
private:
class svg_renderer;
// timer IDs
enum
{
TID_VBLANK_START,
TID_VBLANK_END,
TID_SCANLINE0,
TID_SCANLINE
};
// device-level overrides
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_config_complete() override;
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_stop() override;
virtual void device_resolve_objects() override ATTR_COLD;
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_stop() override ATTR_COLD;
virtual void device_post_load() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// internal helpers
void set_container(render_container &container) { m_container = &container; }
void realloc_screen_bitmaps();
void vblank_begin();
void vblank_end();
TIMER_CALLBACK_MEMBER(vblank_begin);
TIMER_CALLBACK_MEMBER(vblank_end);
TIMER_CALLBACK_MEMBER(first_scanline_tick);
TIMER_CALLBACK_MEMBER(scanline_tick);
void finalize_burnin();
void load_effect_overlay(const char *filename);
void update_scan_bitmap_size(int y);
@@ -473,7 +462,7 @@ private:
screen_update_rgb32_delegate m_screen_update_rgb32; // screen update callback (32-bit RGB)
devcb_write_line m_screen_vblank; // screen vblank line callback
devcb_write32 m_scanline_cb; // screen scanline callback
optional_device<device_palette_interface> m_palette; // our palette
optional_device<device_palette_interface> m_palette; // our palette
u32 m_video_attributes; // flags describing the video system
optional_memory_region m_svg_region; // the region in which the svg data is in
@@ -497,6 +486,7 @@ private:
u8 m_curbitmap; // current bitmap index
u8 m_curtexture; // current texture index
bool m_changed; // has this bitmap changed?
attotime m_last_partial_reset; // last time partial updates were reset
s32 m_last_partial_scan; // scanline of last partial update
s32 m_partial_scan_hpos; // horizontal pixel last rendered on this partial scanline
bitmap_argb32 m_screen_overlay_bitmap; // screen overlay bitmap
@@ -516,7 +506,7 @@ private:
emu_timer * m_scanline0_timer; // scanline 0 timer
emu_timer * m_scanline_timer; // scanline timer
u64 m_frame_number; // the current frame number
u32 m_partial_updates_this_frame;// partial update counter this frame
u32 m_partial_updates_this_frame; // partial update counter this frame
bool m_is_primary_screen;
@@ -529,7 +519,7 @@ private:
vblank_state_delegate m_callback;
};
std::vector<std::unique_ptr<callback_item>> m_callback_list; // list of VBLANK callbacks
std::vector<std::unique_ptr<callback_item>> m_callback_list; // list of VBLANK callbacks
// auto-sizing bitmaps
class auto_bitmap_item