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"
18 #include "../gui/dock_disks.h"
20 #include "qt_gldraw.h"
21 #include "csp_logger.h"
22 #include "menu_flags.h"
26 #define MAX_FONT_SIZE 32
28 #define MAX_SKIP_FRAMES 10
31 extern CSP_Logger *csp_logger;
32 EmuThreadClass::EmuThreadClass(META_MainWindow *rootWindow, USING_FLAGS *p, QObject *parent)
33 : EmuThreadClassBase(rootWindow, p, parent)
35 emu = new EMU(rMainWindow, rMainWindow->getGraphicsView(), using_flags);
38 p->set_osd(emu->get_osd());
39 emu->get_osd()->moveToThread(this);
42 EmuThreadClass::~EmuThreadClass()
46 void EmuThreadClass::set_romakana(void)
48 romakana_conversion_mode = !romakana_conversion_mode;
49 p_config->romaji_to_kana = !p_config->romaji_to_kana;
50 #if defined(USE_AUTO_KEY)
51 p_emu->set_auto_key_char(romakana_conversion_mode ? 1 : 0);
55 int EmuThreadClass::get_interval(void)
58 accum += p_emu->get_frame_interval();
59 int interval = accum >> 10;
60 accum -= interval << 10;
64 void EmuThreadClass::moved_mouse(int x, int y)
68 #if defined(USE_MOUSE)
69 p_emu->set_mouse_pointer(x, y);
73 void EmuThreadClass::button_pressed_mouse_sub(Qt::MouseButton button)
75 #if defined(USE_MOUSE)
76 int stat = p_emu->get_mouse_button();
77 bool flag = p_emu->is_mouse_enabled();
85 case Qt::MiddleButton:
87 emit sig_mouse_enable(flag);
92 p_emu->set_mouse_button(stat);
96 void EmuThreadClass::button_released_mouse_sub(Qt::MouseButton button)
98 #if defined(USE_MOUSE)
99 int stat = p_emu->get_mouse_button();
104 case Qt::RightButton:
107 case Qt::MiddleButton:
108 //emit sig_mouse_enable(false);
113 p_emu->set_mouse_button(stat);
117 void EmuThreadClass::get_fd_string(void)
124 uint32_t access_drv = 0;
125 access_drv = p_emu->is_floppy_disk_accessed();
127 for(i = 0; i < (int)using_flags->get_max_drive(); i++) {
130 if(p_emu->is_floppy_disk_inserted(i)) {
131 if(i == (access_drv - 1)) {
132 emit sig_set_access_lamp(i + 10, true);
133 alamp = QString::fromUtf8("<FONT COLOR=RED>â</FONT>"); // ðŸU+1F4BE Floppy Disk
135 emit sig_set_access_lamp(i + 10, false);
136 alamp = QString::fromUtf8("<FONT COLOR=BLUE>â</FONT>"); // ðŸU+1F4BE Floppy Disk
139 //tmpstr = tmpstr + QString::fromUtf8(" ");
140 //tmpstr = tmpstr + iname;
141 if(emu->d88_file[i].bank_num > 0) {
142 iname = QString::fromUtf8(emu->d88_file[i].disk_name[emu->d88_file[i].cur_bank]);
144 iname = QString::fromUtf8("*Inserted*");
149 alamp = QString::fromUtf8("Ã");
151 if(alamp != fd_lamp[i]) {
152 emit sig_change_access_lamp(CSP_DockDisks_Domain_FD, i, alamp);
155 if(tmpstr != fd_text[i]) {
156 emit sig_change_osd(CSP_DockDisks_Domain_FD, i, tmpstr);
164 void EmuThreadClass::get_qd_string(void)
171 uint32_t access_drv = 0;
172 access_drv = p_emu->is_quick_disk_accessed();
173 for(i = 0; i < using_flags->get_max_qd(); i++) {
175 if(p_emu->is_quick_disk_inserted(i)) {
176 if(i == (access_drv - 1)) {
177 alamp = QString::fromUtf8("<FONT COLOR=RED>â</FONT>"); // ðœãU+1F4BD MiniDisc
179 alamp = QString::fromUtf8("<FONT COLOR=BLUE>â</FONT>"); // ðœU+1F4BD MiniDisc
182 //tmpstr = tmpstr + QString::fromUtf8(" ");
183 //iname = QString::fromUtf8("*Inserted*");
184 //tmpstr = tmpstr + iname;
186 tmpstr = QString::fromUtf8("Ã");
188 if(tmpstr != qd_text[i]) {
189 emit sig_change_access_lamp(CSP_DockDisks_Domain_QD, i, tmpstr);
196 void EmuThreadClass::get_tape_string()
200 #if defined(USE_TAPE1) && !defined(TAPE_BINARY_ONLY)
201 for(int i = 0; i < MAX_TAPE; i++) {
202 if(p_emu->is_tape_inserted(i)) {
204 const _TCHAR *ts = p_emu->get_tape_message(i);
206 tmpstr = QString::fromUtf8(ts);
207 tmpstr = QString::fromUtf8("<FONT COLOR=RED>") + tmpstr + QString::fromUtf8("</FONT>");
210 tmpstr = QString::fromUtf8("<FONT COLOR=BLUE> EMPTY </FONT>");
212 if(tmpstr != cmt_text[i]) {
213 emit sig_change_osd(CSP_DockDisks_Domain_CMT, i, tmpstr);
214 cmt_text[i] = tmpstr;
220 void EmuThreadClass::get_cd_string(void)
222 #if defined(USE_COMPACT_DISC)
224 if(p_emu->is_compact_disc_inserted()) {
225 tmpstr = QString::fromUtf8("<FONT COLOR=BLUE>ð¿</FONT>"); // U+1F4BF OPTICAL DISC
227 tmpstr = QString::fromUtf8("Ã");
229 if(tmpstr != cdrom_text) {
230 emit sig_change_access_lamp(CSP_DockDisks_Domain_CD, 0, tmpstr);
236 void EmuThreadClass::get_bubble_string(void)
238 #if defined(USE_BUBBLE1)
243 for(i = 0; i < using_flags->get_max_bubble() ; i++) {
244 if(p_emu->is_bubble_casette_inserted(i)) {
245 alamp = QString::fromUtf8("â ");
246 //tmpstr = alamp + QString::fromUtf8(" ");
248 tmpstr = QString::fromUtf8("Ã");
249 //tmpstr = tmpstr + QString::fromUtf8(" ");
251 if(alamp != bubble_text[i]) {
252 emit sig_change_access_lamp(CSP_DockDisks_Domain_Bubble, i, tmpstr);
253 bubble_text[i] = alamp;
259 void EmuThreadClass::doWork(const QString ¶ms)
261 int interval = 0, sleep_period = 0;
266 uint32_t led_data = 0x00000000;
267 uint32_t led_data_old = 0x00000000;
272 bool req_draw = true;
273 bool vert_line_bak = using_flags->get_config_ptr()->opengl_scanline_vert;
274 bool horiz_line_bak = using_flags->get_config_ptr()->opengl_scanline_horiz;
275 bool gl_crt_filter_bak = using_flags->get_config_ptr()->use_opengl_filters;
276 int opengl_filter_num_bak = using_flags->get_config_ptr()->opengl_filter_num;
277 //uint32_t key_mod_old = 0xffffffff;
278 int no_draw_count = 0;
279 bool prevRecordReq = false;
281 doing_debug_command = false;
283 // draw_timing = false;
285 bSpecialResetReq = false;
286 bLoadStateReq = false;
287 bSaveStateReq = false;
288 bUpdateConfigReq = false;
289 bStartRecordSoundReq = false;
290 bStopRecordSoundReq = false;
291 bStartRecordMovieReq = false;
299 //key_up_queue.clear();
300 //key_down_queue.clear();
303 for(int i = 0; i < using_flags->get_max_qd(); i++) qd_text[i].clear();
304 for(int i = 0; i < using_flags->get_max_drive(); i++) {
306 fd_lamp[i] = QString::fromUtf8("Ã");
308 for(int i = 0; i < using_flags->get_max_tape(); i++) {
312 for(int i = 0; i < using_flags->get_max_bubble(); i++) bubble_text[i].clear();
315 //p_emu->SetHostCpus(this->idealThreadCount());
316 if(MainWindow == NULL) {
317 if(bRunThread == false){
324 if((using_flags->get_use_extra_leds() > 0) || (using_flags->get_use_key_locked())) emit sig_send_data_led((quint32)led_data);
325 for(int ii = 0; ii < using_flags->get_max_drive(); ii++ ) {
326 emit sig_change_access_lamp(CSP_DockDisks_Domain_FD, ii, fd_lamp[ii]);
335 if(bLoadStateReq != false) {
336 if(!sStateFile.isEmpty()) {
337 p_emu->load_state(sStateFile.toLocal8Bit().constData());
340 bLoadStateReq = false;
344 if(bResetReq != false) {
349 #ifdef USE_SPECIAL_RESET
350 if(bSpecialResetReq != false) {
351 p_emu->special_reset();
352 bSpecialResetReq = false;
356 if(bSaveStateReq != false) {
357 if(!sStateFile.isEmpty()) {
358 p_emu->save_state(sStateFile.toLocal8Bit().constData());
361 bSaveStateReq = false;
364 #if defined(USE_MINIMUM_RENDERING)
365 if((vert_line_bak != p_config->opengl_scanline_vert) ||
366 (horiz_line_bak != p_config->opengl_scanline_horiz) ||
367 (gl_crt_filter_bak != p_config->use_opengl_filters) ||
368 (opengl_filter_num_bak != p_config->opengl_filter_num)) req_draw = true;
369 vert_line_bak = p_config->opengl_scanline_vert;
370 horiz_line_bak = p_config->opengl_scanline_horiz;
371 gl_crt_filter_bak = p_config->use_opengl_filters;
372 opengl_filter_num_bak = p_config->opengl_filter_num;
374 if(bStartRecordSoundReq != false) {
375 p_emu->start_record_sound();
376 bStartRecordSoundReq = false;
379 if(bStopRecordSoundReq != false) {
380 p_emu->stop_record_sound();
381 bStopRecordSoundReq = false;
384 if(bUpdateConfigReq != false) {
385 p_emu->update_config();
386 bUpdateConfigReq = false;
389 if(bStartRecordMovieReq != false) {
390 if(!prevRecordReq && (record_fps > 0) && (record_fps < 75)) {
391 p_emu->start_record_video(record_fps);
392 prevRecordReq = true;
396 p_emu->stop_record_video();
398 prevRecordReq = false;
404 #if defined(USE_MOUSE) // Will fix
405 emit sig_is_enable_mouse(p_emu->is_mouse_enabled());
407 #if defined(USE_SOUND_VOLUME)
408 for(int ii = 0; ii < USE_SOUND_VOLUME; ii++) {
409 if(bUpdateVolumeReq[ii]) {
410 p_emu->set_sound_device_volume(ii, p_config->sound_volume_l[ii], p_config->sound_volume_r[ii]);
411 bUpdateVolumeReq[ii] = false;
415 if(p_config->romaji_to_kana) {
416 //FIFO *dmy = p_emu->get_auto_key_buffer();
418 // if(!dmy->empty()) {
419 // p_emu->stop_auto_key();
420 // p_emu->start_auto_key();
427 while(!is_empty_key_up()) {
432 p_emu->key_modifiers(sp.mod);
433 p_emu->key_up(sp.code, true); // need decicion of extend.
436 while(!is_empty_key_down()) {
438 dequeue_key_down(&sp);
439 if(p_config->romaji_to_kana) {
440 p_emu->key_modifiers(sp.mod);
441 p_emu->key_char(sp.code);
443 p_emu->key_modifiers(sp.mod);
444 p_emu->key_down(sp.code, true, sp.repeat);
448 run_frames = p_emu->run();
449 total_frames += run_frames;
450 #if defined(USE_MINIMUM_RENDERING)
451 req_draw |= p_emu->is_screen_changed();
455 #if defined(USE_KEY_LOCKED) && !defined(INDEPENDENT_CAPS_KANA_LED)
456 led_data = p_emu->get_caps_locked() ? 0x01 : 0x00;
457 led_data |= (p_emu->get_kana_locked() ? 0x02 : 0x00);
461 #if defined(USE_EXTRA_LEDS)
462 #if !defined(INDEPENDENT_CAPS_KANA_LED)
463 led_data <<= USE_EXTRA_LEDS;
465 led_data |= p_emu->get_extra_leds();
467 #if defined(USE_EXTRA_LEDS) || defined(USE_KEY_LOCKED)
468 if(led_data != led_data_old) {
469 emit sig_send_data_led((quint32)led_data);
470 led_data_old = led_data;
475 interval += get_interval();
476 now_skip = p_emu->is_frame_skippable() && !p_emu->is_video_recording();
477 if(config.full_speed) interval = 1;
478 if((prev_skip && !now_skip) || next_time == 0) {
479 next_time = tick_timer.elapsed();
482 next_time += interval;
484 prev_skip = now_skip;
485 //printf("p_emu::RUN Frames = %d SKIP=%d Interval = %d NextTime = %d\n", run_frames, now_skip, interval, next_time);
486 if(next_time > tick_timer.elapsed()) {
487 // update window if enough time
488 // draw_timing = false;
491 int count_limit = (int)(FRAMES_PER_SEC / 3);
492 #if defined(SUPPORT_TV_RENDER)
493 if(config.rendering_type == CONFIG_RENDER_TYPE_TV) {
497 if(no_draw_count > count_limit) {
503 //emit sig_draw_thread(true);
505 emit sig_draw_thread(req_draw);
508 // sleep 1 frame priod if need
509 current_time = tick_timer.elapsed();
510 if((int)(next_time - current_time) >= 10) {
511 sleep_period = next_time - current_time;
513 } else if(++skip_frames > MAX_SKIP_FRAMES) {
514 // update window at least once per 10 frames
515 // draw_timing = false;
516 emit sig_draw_thread(true);
519 qint64 tt = tick_timer.elapsed();
520 if(config.full_speed) {
523 next_time = tt + get_interval();
525 sleep_period = next_time - tt;
529 if(bRunThread == false){
532 if(sleep_period <= 0) sleep_period = 1;
533 msleep(sleep_period);
536 //emit quit_draw_thread();
537 csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
543 void EmuThreadClass::do_set_display_size(int w, int h, int ww, int wh)
546 p_emu->set_host_window_size(w, h, true);
549 void EmuThreadClass::print_framerate(int frames)
551 if(frames >= 0) draw_frames += frames;
553 qint64 current_time = tick_timer.elapsed();
554 if(update_fps_time <= current_time && update_fps_time != 0) {
557 //int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
559 if(MainWindow->GetPowerState() == false){
560 snprintf(buf, 255, _T("*Power OFF*"));
561 } else if(now_skip) {
562 int ratio = (int)(100.0 * (double)total_frames / emu->get_frame_rate() + 0.5);
563 snprintf(buf, 255, create_string(_T("%s - Skip Frames (%d %%)"), _T(DEVICE_NAME), ratio));
565 if(p_emu->message_count > 0) {
566 snprintf(buf, 255, _T("%s - %s"), DEVICE_NAME, p_emu->message);
567 p_emu->message_count--;
569 int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
570 snprintf(buf, 255, _T("%s - %d fps (%d %%)"), DEVICE_NAME, draw_frames, ratio);
573 if(romakana_conversion_mode) {
574 message = QString::fromUtf8("[R]");
575 message = message + QString::fromUtf8(buf);
579 emit message_changed(message);
580 emit window_title_changed(message);
581 update_fps_time += 1000;
582 total_frames = draw_frames = 0;
585 if(update_fps_time <= current_time) {
586 update_fps_time = current_time + 1000;
588 calc_message = false;