2 Skelton for retropc emulator
3 Author : Takeda.Toshiya
4 Port to Qt : K.Ohta <whatisthis.sowhat _at_ gmail.com>
6 History: 2015.11.10 Split from qt_main.cpp
7 Note: This class must be compiled per VM, must not integrate shared units.
8 [ win32 main ] -> [ Qt main ] -> [Emu Thread]
13 #include <QWaitCondition>
17 #include "emu_thread.h"
19 #include "qt_gldraw.h"
20 #include "csp_logger.h"
21 #include "menu_flags.h"
25 #define MAX_FONT_SIZE 32
27 #define MAX_SKIP_FRAMES 10
29 EmuThreadClass::EmuThreadClass(META_MainWindow *rootWindow, EMU *pp_emu, USING_FLAGS *p, QObject *parent)
30 : EmuThreadClassBase(rootWindow, pp_emu, p, parent)
34 EmuThreadClass::~EmuThreadClass()
38 int EmuThreadClass::get_interval(void)
41 accum += p_emu->get_frame_interval();
42 int interval = accum >> 10;
43 accum -= interval << 10;
47 void EmuThreadClass::moved_mouse(int x, int y)
51 #if defined(USE_MOUSE)
52 p_emu->set_mouse_pointer(x, y);
56 void EmuThreadClass::button_pressed_mouse_sub(Qt::MouseButton button)
58 #if defined(USE_MOUSE)
59 int stat = p_emu->get_mouse_button();
60 bool flag = p_emu->is_mouse_enabled();
68 case Qt::MiddleButton:
70 emit sig_mouse_enable(flag);
73 p_emu->set_mouse_button(stat);
77 void EmuThreadClass::button_released_mouse_sub(Qt::MouseButton button)
79 #if defined(USE_MOUSE)
80 int stat = p_emu->get_mouse_button();
88 case Qt::MiddleButton:
89 //emit sig_mouse_enable(false);
92 p_emu->set_mouse_button(stat);
96 void EmuThreadClass::get_fd_string(void)
103 uint32_t access_drv = 0;
104 #if defined(USE_ACCESS_LAMP) && defined(USE_FD1)
105 access_drv = p_emu->get_access_lamp_status();
108 for(i = 0; i < using_flags->get_max_drive(); i++) {
109 if(p_emu->is_floppy_disk_inserted(i)) {
110 if(using_flags->is_use_access_lamp()) {
111 if(i == (access_drv - 1)) {
112 alamp = QString::fromUtf8("<FONT COLOR=RED>●</FONT> ");
114 alamp = QString::fromUtf8("○ ");
116 tmpstr = QString::fromUtf8("FD");
117 tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
119 tmpstr = QString::fromUtf8("FD");
120 tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
122 if(emu->d88_file[i].bank_num > 0) {
123 iname = QString::fromUtf8(emu->d88_file[i].disk_name[emu->d88_file[i].cur_bank]);
125 iname = QString::fromUtf8("*Inserted*");
127 tmpstr = tmpstr + iname;
129 tmpstr = QString::fromUtf8("× FD") + QString::number(i) + QString::fromUtf8(":");
130 tmpstr = tmpstr + QString::fromUtf8(" ");
132 if(tmpstr != fd_text[i]) {
133 emit sig_change_osd_fd(i, tmpstr);
141 void EmuThreadClass::get_qd_string(void)
148 uint32_t access_drv = 0;
149 # if defined(USE_ACCESS_LAMP)
150 access_drv = p_emu->get_access_lamp_status();
152 for(i = 0; i < using_flags->get_max_qd(); i++) {
153 if(p_emu->is_quick_disk_inserted(i)) {
154 if(using_flags->is_use_access_lamp()) {
155 if(i == (access_drv - 1)) {
156 alamp = QString::fromUtf8("● ");
158 alamp = QString::fromUtf8("○ ");
160 tmpstr = QString::fromUtf8("QD");
161 tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
163 tmpstr = QString::fromUtf8("QD");
164 tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
166 iname = QString::fromUtf8("*Inserted*");
167 tmpstr = tmpstr + iname;
169 tmpstr = QString::fromUtf8("× QD") + QString::number(i) + QString::fromUtf8(":");
170 tmpstr = tmpstr + QString::fromUtf8(" ");
172 if(tmpstr != qd_text[i]) {
173 emit sig_change_osd_qd(i, tmpstr);
180 void EmuThreadClass::get_tape_string()
182 QString tmpstr = QString::fromUtf8("");
184 #if defined(USE_TAPE) && !defined(TAPE_BINARY_ONLY)
185 if(p_emu->is_tape_inserted()) {
186 int tape_counter = p_emu->get_tape_position();
187 tmpstr = QString::fromUtf8("");
188 if(p_emu->is_tape_playing()) {
189 tmpstr = QString::fromUtf8("<FONT COLOR=BLUE>▶ </FONT>");
190 } else if(p_emu->is_tape_recording()) {
191 tmpstr = QString::fromUtf8("<FONT COLOR=RED>● </FONT>");
193 tmpstr = QString::fromUtf8("<FONT COLOR=BLACK>■ </FONT>");
195 if(tape_counter >= 100) {
196 tmpstr = tmpstr + QString::fromUtf8("BOTTOM");
197 } else if(tape_counter >= 0) {
198 tmpstr = tmpstr + QString::number(tape_counter) + QString::fromUtf8("%");
200 tmpstr = tmpstr + QString::fromUtf8("TOP");
203 tmpstr = QString::fromUtf8("EMPTY");
205 if(tmpstr != cmt_text) {
206 emit sig_change_osd_cmt(tmpstr);
212 void EmuThreadClass::get_cd_string(void)
214 #if defined(USE_COMPACT_DISC)
216 if(p_emu->is_compact_disc_inserted()) {
217 tmpstr = QString::fromUtf8("○");
219 tmpstr = QString::fromUtf8("Not Inserted");
221 if(tmpstr != cdrom_text) {
222 emit sig_change_osd_cdrom(tmpstr);
228 void EmuThreadClass::get_bubble_string(void)
230 #if defined(USE_BUBBLE1)
235 for(i = 0; i < using_flags->get_max_bubble() ; i++) {
236 if(p_emu->is_bubble_casette_inserted(i)) {
237 alamp = QString::fromUtf8("● ");
238 tmpstr = QString::fromUtf8("BUB");
239 tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
241 tmpstr = QString::fromUtf8("× BUB") + QString::number(i) + QString::fromUtf8(":");
242 tmpstr = tmpstr + QString::fromUtf8(" ");
244 if(tmpstr != bubble_text[i]) {
245 emit sig_change_osd_bubble(i, tmpstr);
246 bubble_text[i] = tmpstr;
252 void EmuThreadClass::doWork(const QString ¶ms)
254 int interval = 0, sleep_period = 0;
260 uint32_t led_data = 0x00000000;
261 uint32_t led_data_old = 0x00000000;
269 bool req_draw = true;
270 bool vert_line_bak = using_flags->get_config_ptr()->opengl_scanline_vert;
271 bool horiz_line_bak = using_flags->get_config_ptr()->opengl_scanline_horiz;
272 bool gl_crt_filter_bak = using_flags->get_config_ptr()->use_opengl_filters;
273 int opengl_filter_num_bak = using_flags->get_config_ptr()->opengl_filter_num;
274 //uint32_t key_mod_old = 0xffffffff;
275 int no_draw_count = 0;
278 doing_debug_command = false;
281 // draw_timing = false;
283 bSpecialResetReq = false;
284 bLoadStateReq = false;
285 bSaveStateReq = false;
286 bUpdateConfigReq = false;
287 bStartRecordSoundReq = false;
288 bStopRecordSoundReq = false;
289 bStartRecordMovieReq = false;
296 //key_up_queue.clear();
297 //key_down_queue.clear();
300 for(int i = 0; i < using_flags->get_max_drive(); i++) qd_text[i].clear();
301 for(int i = 0; i < using_flags->get_max_drive(); i++) fd_text[i].clear();
304 for(int i = 0; i < using_flags->get_max_bubble(); i++) bubble_text[i].clear();
307 //p_emu->SetHostCpus(this->idealThreadCount());
308 if(MainWindow == NULL) {
309 if(bRunThread == false){
316 if(using_flags->get_use_led_device() > 0) emit sig_send_data_led((quint32)led_data);
324 if(bLoadStateReq != false) {
326 bLoadStateReq = false;
330 if(bResetReq != false) {
335 #ifdef USE_SPECIAL_RESET
336 if(bSpecialResetReq != false) {
337 p_emu->special_reset();
338 bSpecialResetReq = false;
342 if(bSaveStateReq != false) {
344 bSaveStateReq = false;
347 #if defined(USE_MINIMUM_RENDERING)
348 if((vert_line_bak != p_config->opengl_scanline_vert) ||
349 (horiz_line_bak != p_config->opengl_scanline_horiz) ||
350 (gl_crt_filter_bak != p_config->use_opengl_filters) ||
351 (opengl_filter_num_bak != p_config->opengl_filter_num)) req_draw = true;
352 vert_line_bak = p_config->opengl_scanline_vert;
353 horiz_line_bak = p_config->opengl_scanline_horiz;
354 gl_crt_filter_bak = p_config->use_opengl_filters;
355 opengl_filter_num_bak = p_config->opengl_filter_num;
357 if(bStartRecordSoundReq != false) {
358 p_emu->start_record_sound();
359 bStartRecordSoundReq = false;
362 if(bStopRecordSoundReq != false) {
363 p_emu->stop_record_sound();
364 bStopRecordSoundReq = false;
367 if(bUpdateConfigReq != false) {
368 p_emu->update_config();
369 bUpdateConfigReq = false;
372 if(bStartRecordMovieReq != false) {
373 if(!prevRecordReq && (record_fps > 0) && (record_fps < 75)) {
374 p_emu->start_record_video(record_fps);
375 prevRecordReq = true;
379 p_emu->stop_record_video();
381 prevRecordReq = false;
387 #if defined(USE_MOUSE) // Will fix
388 emit sig_is_enable_mouse(p_emu->is_mouse_enabled());
390 #if defined(USE_SOUND_VOLUME)
391 for(int ii = 0; ii < USE_SOUND_VOLUME; ii++) {
392 if(bUpdateVolumeReq[ii]) {
393 p_emu->set_sound_device_volume(ii, p_config->sound_volume_l[ii], p_config->sound_volume_r[ii]);
394 bUpdateVolumeReq[ii] = false;
399 if(!roma_kana_queue.isEmpty()) {
400 #if defined(USE_AUTO_KEY)
401 FIFO *dmy = emu->get_auto_key_buffer();
404 QString tmps = roma_kana_queue.dequeue();
405 this->do_start_auto_key(tmps);
409 roma_kana_queue.clear();
412 if(roma_kana_queue.isEmpty()) {
413 roma_kana_conv = false;
418 while(!is_empty_key_up()) {
422 p_emu->key_modifiers(sp.mod);
423 p_emu->key_up(sp.code);
425 while(!is_empty_key_down()) {
427 dequeue_key_down(&sp);
428 p_emu->key_modifiers(sp.mod);
429 p_emu->key_down(sp.code, sp.repeat);
432 run_frames = p_emu->run();
433 total_frames += run_frames;
434 #if defined(USE_MINIMUM_RENDERING)
435 req_draw |= p_emu->is_screen_changed();
439 #ifdef USE_LED_DEVICE
440 led_data = p_emu->get_led_status();
441 if(led_data != led_data_old) {
442 emit sig_send_data_led((quint32)led_data);
443 led_data_old = led_data;
448 interval += get_interval();
449 now_skip = p_emu->is_frame_skippable() && !p_emu->is_video_recording();
451 if((prev_skip && !now_skip) || next_time == 0) {
452 next_time = tick_timer.elapsed();
455 next_time += interval;
457 prev_skip = now_skip;
458 //printf("p_emu::RUN Frames = %d SKIP=%d Interval = %d NextTime = %d\n", run_frames, now_skip, interval, next_time);
459 if(next_time > tick_timer.elapsed()) {
460 // update window if enough time
461 // draw_timing = false;
464 int count_limit = (int)(FRAMES_PER_SEC / 3);
465 #if defined(SUPPORT_TV_RENDER)
466 if(config.rendering_type == CONFIG_RENDER_TYPE_TV) {
470 if(no_draw_count > count_limit) {
476 //emit sig_draw_thread(true);
478 emit sig_draw_thread(req_draw);
481 // sleep 1 frame priod if need
482 current_time = tick_timer.elapsed();
483 if((int)(next_time - current_time) >= 10) {
484 sleep_period = next_time - current_time;
486 } else if(++skip_frames > MAX_SKIP_FRAMES) {
487 // update window at least once per 10 frames
488 // draw_timing = false;
489 emit sig_draw_thread(true);
492 qint64 tt = tick_timer.elapsed();
493 next_time = tt + get_interval();
494 sleep_period = next_time - tt;
498 if(bRunThread == false){
501 if(sleep_period <= 0) sleep_period = 1;
502 msleep(sleep_period);
505 //emit quit_draw_thread();
506 csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
512 void EmuThreadClass::doSetDisplaySize(int w, int h, int ww, int wh)
515 //p_emu->set_vm_screen_size(w, h, -1, -1, ww, wh);
516 p_emu->set_host_window_size(w, h, true);
519 void EmuThreadClass::print_framerate(int frames)
521 if(frames >= 0) draw_frames += frames;
523 qint64 current_time = tick_timer.elapsed();
524 if(update_fps_time <= current_time && update_fps_time != 0) {
527 int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
529 if(MainWindow->GetPowerState() == false){
530 snprintf(buf, 255, _T("*Power OFF*"));
532 if(p_emu->message_count > 0) {
533 snprintf(buf, 255, _T("%s - %s"), DEVICE_NAME, p_emu->message);
534 p_emu->message_count--;
536 snprintf(buf, 255, _T("%s - %d fps (%d %%)"), DEVICE_NAME, draw_frames, ratio);
539 if(romakana_conversion_mode) {
540 message = QString::fromUtf8("[R]");
541 message = message + QString::fromUtf8(buf);
545 emit message_changed(message);
546 emit window_title_changed(message);
547 update_fps_time += 1000;
548 total_frames = draw_frames = 0;
551 if(update_fps_time <= current_time) {
552 update_fps_time = current_time + 1000;
554 calc_message = false;