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++) {
128 if(p_emu->is_floppy_disk_inserted(i)) {
129 if(i == (access_drv - 1)) {
130 alamp = QString::fromUtf8("<FONT COLOR=RED>●</FONT> ");
132 alamp = QString::fromUtf8("○ ");
135 tmpstr = tmpstr + QString::fromUtf8(" ");
136 if(emu->d88_file[i].bank_num > 0) {
137 iname = QString::fromUtf8(emu->d88_file[i].disk_name[emu->d88_file[i].cur_bank]);
139 iname = QString::fromUtf8("*Inserted*");
141 tmpstr = tmpstr + iname;
143 tmpstr = QString::fromUtf8("× ");
145 if(tmpstr != fd_text[i]) {
146 emit sig_change_osd(CSP_DockDisks_Domain_FD, i, tmpstr);
154 void EmuThreadClass::get_qd_string(void)
161 uint32_t access_drv = 0;
162 access_drv = p_emu->is_quick_disk_accessed();
163 for(i = 0; i < using_flags->get_max_qd(); i++) {
164 if(p_emu->is_quick_disk_inserted(i)) {
165 if(i == (access_drv - 1)) {
166 alamp = QString::fromUtf8("● ");
168 alamp = QString::fromUtf8("○ ");
171 tmpstr = tmpstr + QString::fromUtf8(" ");
172 iname = QString::fromUtf8("*Inserted*");
173 tmpstr = tmpstr + iname;
175 tmpstr = QString::fromUtf8("× ");
177 if(tmpstr != qd_text[i]) {
178 emit sig_change_osd(CSP_DockDisks_Domain_QD, i, tmpstr);
185 void EmuThreadClass::get_tape_string()
189 #if defined(USE_TAPE1) && !defined(TAPE_BINARY_ONLY)
190 for(int i = 0; i < MAX_TAPE; i++) {
191 if(p_emu->is_tape_inserted(i)) {
192 const _TCHAR *ts = p_emu->get_tape_message(i);
194 tmpstr = QString::fromUtf8(ts);
197 tmpstr = QString::fromUtf8(" EMPTY ");
199 if(tmpstr != cmt_text) {
200 emit sig_change_osd(CSP_DockDisks_Domain_CMT, i, tmpstr);
207 void EmuThreadClass::get_cd_string(void)
209 #if defined(USE_COMPACT_DISC)
211 if(p_emu->is_compact_disc_inserted()) {
212 tmpstr = QString::fromUtf8("○");
214 tmpstr = QString::fromUtf8("Not Inserted");
216 if(tmpstr != cdrom_text) {
217 emit sig_change_osd(CSP_DockDisks_Domain_CD, 0, tmpstr);
223 void EmuThreadClass::get_bubble_string(void)
225 #if defined(USE_BUBBLE1)
230 for(i = 0; i < using_flags->get_max_bubble() ; i++) {
231 if(p_emu->is_bubble_casette_inserted(i)) {
232 alamp = QString::fromUtf8("● ");
233 tmpstr = alamp + QString::fromUtf8(" ");
235 tmpstr = QString::fromUtf8("×");
236 tmpstr = tmpstr + QString::fromUtf8(" ");
238 if(tmpstr != bubble_text[i]) {
239 emit sig_change_osd(CSP_DockDisks_Domain_Bubble, i, tmpstr);
240 bubble_text[i] = tmpstr;
246 void EmuThreadClass::doWork(const QString ¶ms)
248 int interval = 0, sleep_period = 0;
253 uint32_t led_data = 0x00000000;
254 uint32_t led_data_old = 0x00000000;
259 bool req_draw = true;
260 bool vert_line_bak = using_flags->get_config_ptr()->opengl_scanline_vert;
261 bool horiz_line_bak = using_flags->get_config_ptr()->opengl_scanline_horiz;
262 bool gl_crt_filter_bak = using_flags->get_config_ptr()->use_opengl_filters;
263 int opengl_filter_num_bak = using_flags->get_config_ptr()->opengl_filter_num;
264 //uint32_t key_mod_old = 0xffffffff;
265 int no_draw_count = 0;
266 bool prevRecordReq = false;
268 doing_debug_command = false;
270 // draw_timing = false;
272 bSpecialResetReq = false;
273 bLoadStateReq = false;
274 bSaveStateReq = false;
275 bUpdateConfigReq = false;
276 bStartRecordSoundReq = false;
277 bStopRecordSoundReq = false;
278 bStartRecordMovieReq = false;
286 //key_up_queue.clear();
287 //key_down_queue.clear();
290 for(int i = 0; i < using_flags->get_max_drive(); i++) qd_text[i].clear();
291 for(int i = 0; i < using_flags->get_max_drive(); i++) fd_text[i].clear();
294 for(int i = 0; i < using_flags->get_max_bubble(); i++) bubble_text[i].clear();
297 //p_emu->SetHostCpus(this->idealThreadCount());
298 if(MainWindow == NULL) {
299 if(bRunThread == false){
306 if(using_flags->get_use_led_device() > 0) emit sig_send_data_led((quint32)led_data);
314 if(bLoadStateReq != false) {
315 if(!sStateFile.isEmpty()) {
316 p_emu->load_state(sStateFile.toLocal8Bit().constData());
319 bLoadStateReq = false;
323 if(bResetReq != false) {
328 #ifdef USE_SPECIAL_RESET
329 if(bSpecialResetReq != false) {
330 p_emu->special_reset();
331 bSpecialResetReq = false;
335 if(bSaveStateReq != false) {
336 if(!sStateFile.isEmpty()) {
337 p_emu->save_state(sStateFile.toLocal8Bit().constData());
340 bSaveStateReq = false;
343 #if defined(USE_MINIMUM_RENDERING)
344 if((vert_line_bak != p_config->opengl_scanline_vert) ||
345 (horiz_line_bak != p_config->opengl_scanline_horiz) ||
346 (gl_crt_filter_bak != p_config->use_opengl_filters) ||
347 (opengl_filter_num_bak != p_config->opengl_filter_num)) req_draw = true;
348 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;
353 if(bStartRecordSoundReq != false) {
354 p_emu->start_record_sound();
355 bStartRecordSoundReq = false;
358 if(bStopRecordSoundReq != false) {
359 p_emu->stop_record_sound();
360 bStopRecordSoundReq = false;
363 if(bUpdateConfigReq != false) {
364 p_emu->update_config();
365 bUpdateConfigReq = false;
368 if(bStartRecordMovieReq != false) {
369 if(!prevRecordReq && (record_fps > 0) && (record_fps < 75)) {
370 p_emu->start_record_video(record_fps);
371 prevRecordReq = true;
375 p_emu->stop_record_video();
377 prevRecordReq = false;
383 #if defined(USE_MOUSE) // Will fix
384 emit sig_is_enable_mouse(p_emu->is_mouse_enabled());
386 #if defined(USE_SOUND_VOLUME)
387 for(int ii = 0; ii < USE_SOUND_VOLUME; ii++) {
388 if(bUpdateVolumeReq[ii]) {
389 p_emu->set_sound_device_volume(ii, p_config->sound_volume_l[ii], p_config->sound_volume_r[ii]);
390 bUpdateVolumeReq[ii] = false;
394 if(p_config->romaji_to_kana) {
395 //FIFO *dmy = p_emu->get_auto_key_buffer();
397 // if(!dmy->empty()) {
398 // p_emu->stop_auto_key();
399 // p_emu->start_auto_key();
404 if(!roma_kana_queue.isEmpty()) {
405 #if defined(USE_AUTO_KEY)
406 FIFO *dmy = emu->get_auto_key_buffer();
409 QString tmps = roma_kana_queue.dequeue();
410 this->do_start_auto_key(tmps);
414 roma_kana_queue.clear();
417 if(roma_kana_queue.isEmpty()) {
418 roma_kana_conv = false;
424 while(!is_empty_key_up()) {
429 p_emu->key_modifiers(sp.mod);
430 p_emu->key_up(sp.code, true); // need decicion of extend.
433 while(!is_empty_key_down()) {
435 dequeue_key_down(&sp);
436 if(p_config->romaji_to_kana) {
437 p_emu->key_modifiers(sp.mod);
438 p_emu->key_char(sp.code);
440 p_emu->key_modifiers(sp.mod);
441 p_emu->key_down(sp.code, true, sp.repeat);
445 run_frames = p_emu->run();
446 total_frames += run_frames;
447 #if defined(USE_MINIMUM_RENDERING)
448 req_draw |= p_emu->is_screen_changed();
452 #ifdef USE_LED_DEVICE
453 led_data = p_emu->get_led_status();
454 if(led_data != led_data_old) {
455 emit sig_send_data_led((quint32)led_data);
456 led_data_old = led_data;
461 interval += get_interval();
462 now_skip = p_emu->is_frame_skippable() && !p_emu->is_video_recording();
463 if(config.full_speed) interval = 1;
464 if((prev_skip && !now_skip) || next_time == 0) {
465 next_time = tick_timer.elapsed();
468 next_time += interval;
470 prev_skip = now_skip;
471 //printf("p_emu::RUN Frames = %d SKIP=%d Interval = %d NextTime = %d\n", run_frames, now_skip, interval, next_time);
472 if(next_time > tick_timer.elapsed()) {
473 // update window if enough time
474 // draw_timing = false;
477 int count_limit = (int)(FRAMES_PER_SEC / 3);
478 #if defined(SUPPORT_TV_RENDER)
479 if(config.rendering_type == CONFIG_RENDER_TYPE_TV) {
483 if(no_draw_count > count_limit) {
489 //emit sig_draw_thread(true);
491 emit sig_draw_thread(req_draw);
494 // sleep 1 frame priod if need
495 current_time = tick_timer.elapsed();
496 if((int)(next_time - current_time) >= 10) {
497 sleep_period = next_time - current_time;
499 } else if(++skip_frames > MAX_SKIP_FRAMES) {
500 // update window at least once per 10 frames
501 // draw_timing = false;
502 emit sig_draw_thread(true);
505 qint64 tt = tick_timer.elapsed();
506 if(config.full_speed) {
509 next_time = tt + get_interval();
511 sleep_period = next_time - tt;
515 if(bRunThread == false){
518 if(sleep_period <= 0) sleep_period = 1;
519 msleep(sleep_period);
522 //emit quit_draw_thread();
523 csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
529 void EmuThreadClass::do_set_display_size(int w, int h, int ww, int wh)
532 //p_emu->set_vm_screen_size(w, h, -1, -1, ww, wh);
533 p_emu->set_host_window_size(w, h, true);
536 void EmuThreadClass::print_framerate(int frames)
538 if(frames >= 0) draw_frames += frames;
540 qint64 current_time = tick_timer.elapsed();
541 if(update_fps_time <= current_time && update_fps_time != 0) {
544 //int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
546 if(MainWindow->GetPowerState() == false){
547 snprintf(buf, 255, _T("*Power OFF*"));
548 } else if(now_skip) {
549 int ratio = (int)(100.0 * (double)total_frames / emu->get_frame_rate() + 0.5);
550 snprintf(buf, 255, create_string(_T("%s - Skip Frames (%d %%)"), _T(DEVICE_NAME), ratio));
552 if(p_emu->message_count > 0) {
553 snprintf(buf, 255, _T("%s - %s"), DEVICE_NAME, p_emu->message);
554 p_emu->message_count--;
556 int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
557 snprintf(buf, 255, _T("%s - %d fps (%d %%)"), DEVICE_NAME, draw_frames, ratio);
560 if(romakana_conversion_mode) {
561 message = QString::fromUtf8("[R]");
562 message = message + QString::fromUtf8(buf);
566 emit message_changed(message);
567 emit window_title_changed(message);
568 update_fps_time += 1000;
569 total_frames = draw_frames = 0;
572 if(update_fps_time <= current_time) {
573 update_fps_time = current_time + 1000;
575 calc_message = false;