netlist video: Add VECTOR support. [Couriersud]

Fixfreq now supports VECTOR screens automatically. For now the default
remains to be RASTER since bgfx does not support VECTOR screens.

Nevertheless please expect changes in the video output. Video output is
now collected timing-exact, i.e. with subpixel accuracy. Only during
screen_update this is converted and scaled to the bitmap. There may be
changes due to rounding in comparison to current rendering.

Also added a link to a video showing a breakout cocktail table.
This commit is contained in:
couriersud 2019-11-17 03:07:04 +01:00
parent 1ac2d06ea1
commit 6b004964ef
3 changed files with 59 additions and 26 deletions

View File

@ -14,6 +14,7 @@
***************************************************************************/
#include "emu.h"
#include "rendutil.h"
#include "fixfreq.h"
//#define VERBOSE 1
@ -83,7 +84,7 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
void fixedfreq_monitor_state::update_bm(const time_type &time)
{
const int pixels = round((time - m_line_time) * m_desc.m_hscale / m_clock_period);
const float pixels = (time - m_line_time) * static_cast<time_type>(m_desc.m_hscale) / m_clock_period;
const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;
uint32_t col(0xffff0000); // Mark sync areas
@ -91,7 +92,8 @@ void fixedfreq_monitor_state::update_bm(const time_type &time)
if (m_sync_signal >= m_desc.m_sync_threshold)
col = m_col;
m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels - m_last_x, col);
m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields), m_last_x, pixels, col});
//m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels, col);
m_last_x = pixels;
}
@ -157,7 +159,6 @@ void fixedfreq_monitor_state::update_sync(const time_type &time, const double da
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
device_video_interface(mconfig, *this, false),
m_cur_bm(0),
m_htotal(0),
m_vtotal(0),
m_refresh_period(time_type(0)),
@ -190,12 +191,8 @@ void fixedfreq_device::device_start()
m_refresh_period = time_type(0);
m_cur_bm = 0;
m_htotal = m_monitor.m_hbackporch;
m_vtotal = m_monitor.m_vbackporch;
m_bitmap[0] = std::make_unique<bitmap_rgb32>(m_htotal * m_monitor.m_hscale, m_vtotal);
m_bitmap[1] = std::make_unique<bitmap_rgb32>(m_htotal * m_monitor.m_hscale, m_vtotal);
m_state.start();
@ -209,9 +206,6 @@ void fixedfreq_device::device_start()
save_item(NAME(m_state.m_last_vsync_time));
save_item(NAME(m_refresh_period));
save_item(NAME(m_state.m_clock_period));
//save_item(NAME(m_bitmap[0]));
//save_item(NAME(m_bitmap[1]));
save_item(NAME(m_cur_bm));
/* sync separator */
save_item(NAME(m_state.m_vsync_filter));
@ -235,15 +229,45 @@ void fixedfreq_device::device_post_load()
uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
copybitmap(bitmap, *m_bitmap[!m_cur_bm], 0, 0, 0, 0, cliprect);
if (screen.screen_type() == SCREEN_TYPE_RASTER)
{
for (auto &f : m_state.m_fragments)
if (f.y < bitmap.height())
bitmap.plot_box(f.x, f.y, f.xr - f.x, 1, f.col);
}
else if (screen.screen_type() == SCREEN_TYPE_VECTOR)
{
constexpr const uint32_t flags(PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTOR(1));
const rectangle &visarea = screen.visible_area();
float xscale = 1.0f / visarea.width();
float yscale = 1.0f / visarea.height();
float xoffs = (float)visarea.min_x;
float yoffs = (float)visarea.min_y;
screen.container().empty();
screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTORBUF(1));
for (auto &f : m_state.m_fragments)
{
const float x0((f.x - xoffs) * xscale);
const float y0((f.y - yoffs) * yscale);
const float x1((f.xr - xoffs) * xscale);
const float y1((f.y + 1.0f - yoffs) * yscale);
screen.container().add_rect(
x0, y0, x1, y1,
(0xff << 24) | (f.col & 0xffffff),
flags);
}
}
m_state.m_fragments.clear();
return 0;
}
void fixedfreq_device::vsync_start_cb(double refresh_time)
{
// toggle bitmap
m_cur_bm ^= 1;
//m_cur_bm ^= 1;
rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(), m_monitor.maxv());
@ -251,13 +275,6 @@ void fixedfreq_device::vsync_start_cb(double refresh_time)
screen().configure(m_htotal * m_monitor.m_hscale, m_vtotal, visarea, DOUBLE_TO_ATTOSECONDS(m_refresh_period));
}
void fixedfreq_device::plot_hline(int x, int y, int w, uint32_t col)
{
bitmap_rgb32 *bm = m_bitmap[m_cur_bm].get();
if (y < bm->height())
bm->plot_box(x, y, w, 1, col);
}
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_composite_monochrome)
{
// double is good enough for this exercise;

View File

@ -60,7 +60,14 @@ struct fixedfreq_monitor_intf
{
virtual ~fixedfreq_monitor_intf() = default;
virtual void vsync_start_cb(double refresh_time) = 0;
virtual void plot_hline(int x, int y, int w, uint32_t col) = 0;
};
struct fixedfreq_monitor_line
{
float y;
float x;
float xr;
uint32_t col;
};
struct fixedfreq_monitor_state
@ -127,8 +134,10 @@ struct fixedfreq_monitor_state
m_clock_period = 1.0 / m_desc.m_monitor_clock;
// Minimum frame period to be passed to video system ?
m_min_frame_period = 0.25 * m_clock_period * m_desc.m_vbackporch * m_desc.m_hbackporch;
m_intf.vsync_start_cb(m_min_frame_period);
m_fragments.clear();
m_intf.vsync_start_cb(m_min_frame_period);
}
void reset()
@ -148,6 +157,7 @@ struct fixedfreq_monitor_state
m_sig_vsync = 0;
m_sig_composite = 0;
m_sig_field = 0;
m_fragments.clear();
}
void update_sync_channel(const time_type &time, const double newval);
@ -163,7 +173,7 @@ struct fixedfreq_monitor_state
double m_sync_signal;
uint32_t m_col;
int m_last_x;
float m_last_x;
int m_last_y;
time_type m_last_sync_time;
time_type m_line_time;
@ -180,6 +190,7 @@ struct fixedfreq_monitor_state
int m_sig_composite;
int m_sig_field;
time_type m_min_frame_period;
std::vector<fixedfreq_monitor_line> m_fragments;
};
// ======================> fixedfreq_device
@ -254,12 +265,9 @@ protected:
//virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
void vsync_start_cb(double refresh_time) override;
void plot_hline(int x, int y, int w, uint32_t col) override;
private:
std::unique_ptr<bitmap_rgb32> m_bitmap[2];
int m_cur_bm;
int m_htotal;
int m_vtotal;

View File

@ -97,6 +97,12 @@ TODO: Volleyball...
* https://www.youtube.com/watch?v=pDrRnJOCKZc (no longer available)
*
* https://www.youtube.com/watch?v=fiShX2pTz9A
* https://www.youtube.com/watch?v=YmzH4E3x1_g
*
* Breakout videos:
*
* https://www.youtube.com/watch?v=NOGO49j5gCE
*
*/
static const int NS_PER_CLOCK_PONG = static_cast<int>((double) NETLIST_INTERNAL_RES / (double) 7159000 + 0.5);
@ -483,6 +489,7 @@ void pong_state::pong(machine_config &config)
/* video hardware */
SCREEN(config, "screen", SCREEN_TYPE_RASTER);
//SCREEN(config, "screen", SCREEN_TYPE_VECTOR);
FIXFREQ(config, m_video).set_screen("screen");
m_video->set_monitor_clock(MASTER_CLOCK_PONG);
m_video->set_horz_params(H_TOTAL_PONG-67,H_TOTAL_PONG-40,H_TOTAL_PONG-8,H_TOTAL_PONG);
@ -533,8 +540,9 @@ void breakout_state::breakout(machine_config &config)
NETLIST_ANALOG_OUTPUT(config, "maincpu:coin_counter", 0).set_params("CON_T", FUNC(breakout_state::coin_counter_cb));
/* video hardware */
SCREEN(config, "screen", SCREEN_TYPE_RASTER);
FIXFREQ(config, m_video).set_screen("screen");
SCREEN(config, "screen", SCREEN_TYPE_RASTER);
//SCREEN(config, "screen", SCREEN_TYPE_VECTOR);
/* The Pixel width is a 2,1,2,1,2,1,1,1 repeating pattern
* Thus we must use double resolution horizontally
*/