summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/video.h
blob: 6015eecf146cedbaec3aef9eec540b40b6021d01 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    video.h

    Core MAME video routines.

***************************************************************************/

#pragma once

#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif

#ifndef MAME_EMU_VIDEO_H
#define MAME_EMU_VIDEO_H

#include "aviio.h"


//**************************************************************************
//  CONSTANTS
//**************************************************************************

// number of levels of frameskipping supported
constexpr int FRAMESKIP_LEVELS = 12;
constexpr int MAX_FRAMESKIP = FRAMESKIP_LEVELS - 2;


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// ======================> video_manager

class video_manager
{
	friend class screen_device;
	friend class variable_width_screen_device;

public:
	// movie format options
	enum movie_format
	{
		MF_MNG,
		MF_AVI
	};

	// construction/destruction
	video_manager(running_machine &machine);

	// getters
	running_machine &machine() const { return m_machine; }
	bool skip_this_frame() const { return m_skipping_this_frame; }
	int speed_factor() const { return m_speed; }
	int frameskip() const { return m_auto_frameskip ? -1 : m_frameskip_level; }
	bool throttled() const { return m_throttled; }
	float throttle_rate() const { return m_throttle_rate; }
	bool fastforward() const { return m_fastforward; }
	bool is_recording() const;

	// setters
	void set_frameskip(int frameskip);
	void set_throttled(bool throttled = true) { m_throttled = throttled; }
	void set_throttle_rate(float throttle_rate) { m_throttle_rate = throttle_rate; }
	void set_fastforward(bool ffwd = true) { m_fastforward = ffwd; }
	void set_output_changed() { m_output_changed = true; }

	// misc
	void toggle_throttle();
	void toggle_record_movie(movie_format format);
	void toggle_record_mng() { toggle_record_movie(MF_MNG); }
	void toggle_record_avi() { toggle_record_movie(MF_AVI); }
	osd_file::error open_next(emu_file &file, const char *extension, uint32_t index = 0);
	void compute_snapshot_size(s32 &width, s32 &height);
	void pixels(u32 *buffer);

	// render a frame
	void frame_update(bool from_debugger = false);

	// current speed helpers
	std::string speed_text();
	double speed_percent() const { return m_speed_percent; }
	int effective_frameskip() const;

	// snapshots
	void save_snapshot(screen_device *screen, emu_file &file);
	void save_active_screen_snapshots();
	void save_input_timecode();

	// movies
	void begin_recording(const char *name, movie_format format);
	void begin_recording_mng(const char *name, uint32_t index, screen_device *screen);
	void begin_recording_avi(const char *name, uint32_t index, screen_device *screen);
	void end_recording(movie_format format);
	void end_recording_mng(uint32_t index);
	void end_recording_avi(uint32_t index);
	void add_sound_to_recording(const s16 *sound, int numsamples);
	void add_sound_to_avi_recording(const s16 *sound, int numsamples, uint32_t index);

	void set_timecode_enabled(bool value) { m_timecode_enabled = value; }
	bool get_timecode_enabled() { return m_timecode_enabled; }
	bool get_timecode_write() { return m_timecode_write; }
	void set_timecode_write(bool value) { m_timecode_write = value; }
	void set_timecode_text(std::string &str) { m_timecode_text = str; }
	void set_timecode_start(attotime time) { m_timecode_start = time; }
	void add_to_total_time(attotime time) { m_timecode_total += time; }
	std::string &timecode_text(std::string &str);
	std::string &timecode_total_text(std::string &str);

private:
	// internal helpers
	void exit();
	void screenless_update_callback(void *ptr, int param);
	void postload();

	// effective value helpers
	bool effective_autoframeskip() const;
	bool effective_throttle() const;

	// speed and throttling helpers
	int original_speed_setting() const;
	bool finish_screen_updates();
	void update_throttle(attotime emutime);
	osd_ticks_t throttle_until_ticks(osd_ticks_t target_ticks);
	void update_frameskip();
	void update_refresh_speed();
	void recompute_speed(const attotime &emutime);

	// snapshot/movie helpers
	void create_snapshot_bitmap(screen_device *screen);
	void record_frame();

	// internal state
	running_machine &   m_machine;                  // reference to our machine

	// screenless systems
	emu_timer *         m_screenless_frame_timer;   // timer to signal VBLANK start
	bool                m_output_changed;           // did an output element change?

	// throttling calculations
	osd_ticks_t         m_throttle_last_ticks;      // osd_ticks the last call to throttle
	attotime            m_throttle_realtime;        // real time the last call to throttle
	attotime            m_throttle_emutime;         // emulated time the last call to throttle
	u32                 m_throttle_history;         // history of frames where we were fast enough

	// dynamic speed computation
	osd_ticks_t         m_speed_last_realtime;      // real time at the last speed calculation
	attotime            m_speed_last_emutime;       // emulated time at the last speed calculation
	double              m_speed_percent;            // most recent speed percentage

	// overall speed computation
	u32                 m_overall_real_seconds;     // accumulated real seconds at normal speed
	osd_ticks_t         m_overall_real_ticks;       // accumulated real ticks at normal speed
	attotime            m_overall_emutime;          // accumulated emulated time at normal speed
	u32                 m_overall_valid_counter;    // number of consecutive valid time periods

	// configuration
	bool                m_throttled;                // flag: true if we're currently throttled
	float               m_throttle_rate;            // target rate for throttling
	bool                m_fastforward;              // flag: true if we're currently fast-forwarding
	u32                 m_seconds_to_run;           // number of seconds to run before quitting
	bool                m_auto_frameskip;           // flag: true if we're automatically frameskipping
	u32                 m_speed;                    // overall speed (*1000)

	// frameskipping
	u8                  m_empty_skip_count;         // number of empty frames we have skipped
	u8                  m_frameskip_level;          // current frameskip level
	u8                  m_frameskip_counter;        // counter that counts through the frameskip steps
	s8                  m_frameskip_adjust;
	bool                m_skipping_this_frame;      // flag: true if we are skipping the current frame
	osd_ticks_t         m_average_oversleep;        // average number of ticks the OSD oversleeps

	// snapshot stuff
	render_target *     m_snap_target;              // screen shapshot target
	bitmap_rgb32        m_snap_bitmap;              // screen snapshot bitmap
	bool                m_snap_native;              // are we using native per-screen layouts?
	s32                 m_snap_width;               // width of snapshots (0 == auto)
	s32                 m_snap_height;              // height of snapshots (0 == auto)

	// movie recording - MNG
	class mng_info_t
	{
	public:
		mng_info_t()
			: m_mng_frame_period(attotime::zero)
			, m_mng_next_frame_time(attotime::zero)
			, m_mng_frame(0) { }

		std::unique_ptr<emu_file> m_mng_file;              // handle to the open movie file
		attotime            m_mng_frame_period;         // period of a single movie frame
		attotime            m_mng_next_frame_time;      // time of next frame
		u32                 m_mng_frame;                // current movie frame number
	};
	std::vector<mng_info_t> m_mngs;

	// movie recording - AVI
	class avi_info_t
	{
	public:
		avi_info_t()
			: m_avi_file(nullptr)
			, m_avi_frame_period(attotime::zero)
			, m_avi_next_frame_time(attotime::zero)
			, m_avi_frame(0) { }

		avi_file::ptr       m_avi_file;                 // handle to the open movie file
		attotime            m_avi_frame_period;         // period of a single movie frame
		attotime            m_avi_next_frame_time;      // time of next frame
		u32                 m_avi_frame;                // current movie frame number
	};
	std::vector<avi_info_t> m_avis;

	static const bool   s_skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS];

	static const attoseconds_t ATTOSECONDS_PER_SPEED_UPDATE = ATTOSECONDS_PER_SECOND / 4;
	static const int PAUSED_REFRESH_RATE = 30;

	bool                m_timecode_enabled;     // inp.timecode record enabled
	bool                m_timecode_write;       // Show/hide timer at right (partial time)
	std::string         m_timecode_text;        // Message for that video part (intro, gameplay, extra)
	attotime            m_timecode_start;       // Starting timer for that video part (intro, gameplay, extra)
	attotime            m_timecode_total;       // Show/hide timer at left (total elapsed on resulting video preview)
};

#endif // MAME_EMU_VIDEO_H