OSDN Git Service

3da2f82e0f22fd4e61c9f5659e3955dbfe61bfed
[csp-qt/common_source_project-fm7.git] / source / src / qt / common / emu_thread.cpp
1 /*
2         Skelton for retropc emulator
3         Author : Takeda.Toshiya
4     Port to Qt : K.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2015.11.10
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]
9 */
10
11 #include <QString>
12 #include <QTextCodec>
13 #include <QWaitCondition>
14
15 #include <SDL.h>
16
17 #include "emu_thread.h"
18 #include "../gui/dock_disks.h"
19
20 #include "qt_gldraw.h"
21 #include "csp_logger.h"
22 #include "menu_flags.h"
23
24 // buttons
25 #ifdef MAX_BUTTONS
26 #define MAX_FONT_SIZE 32
27 #endif
28 #define MAX_SKIP_FRAMES 10
29
30 extern EMU *emu;
31 extern CSP_Logger *csp_logger;
32 EmuThreadClass::EmuThreadClass(META_MainWindow *rootWindow, USING_FLAGS *p, QObject *parent)
33         : EmuThreadClassBase(rootWindow, p, parent)
34 {
35         emu = new EMU(rMainWindow, rMainWindow->getGraphicsView(), using_flags);
36         p_emu = emu;
37         p->set_emu(emu);
38         p->set_osd(emu->get_osd());
39         emu->get_osd()->moveToThread(this);
40 }
41
42 EmuThreadClass::~EmuThreadClass()
43 {
44 }
45
46 void EmuThreadClass::set_romakana(void)
47 {
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);
52 #endif
53 }
54
55 int EmuThreadClass::get_interval(void)
56 {
57         static int accum = 0;
58         accum += p_emu->get_frame_interval();
59         int interval = accum >> 10;
60         accum -= interval << 10;
61         return interval;
62 }
63
64 void EmuThreadClass::moved_mouse(int x, int y)
65 {
66         mouse_x = x;
67         mouse_y = y;
68 #if defined(USE_MOUSE)   
69         p_emu->set_mouse_pointer(x, y);
70 #endif   
71 }
72
73 void EmuThreadClass::button_pressed_mouse_sub(Qt::MouseButton button)
74 {
75 #if defined(USE_MOUSE)   
76         int stat = p_emu->get_mouse_button();
77         bool flag = p_emu->is_mouse_enabled();
78         switch(button) {
79         case Qt::LeftButton:
80                 stat |= 0x01;
81                 break;
82         case Qt::RightButton:
83                 stat |= 0x02;
84                 break;
85         case Qt::MiddleButton:
86                 flag = !flag;
87                 emit sig_mouse_enable(flag);
88                 break;
89         default:
90                 break;
91         }
92         p_emu->set_mouse_button(stat);
93 #endif     
94 }       
95
96 void EmuThreadClass::button_released_mouse_sub(Qt::MouseButton button)
97 {
98 #if defined(USE_MOUSE)   
99                 int stat = p_emu->get_mouse_button();
100                 switch(button) {
101                 case Qt::LeftButton:
102                         stat &= 0x7ffffffe;
103                         break;
104                 case Qt::RightButton:
105                         stat &= 0x7ffffffd;
106                         break;
107                 case Qt::MiddleButton:
108                         //emit sig_mouse_enable(false);
109                         break;
110                 default:
111                         break;
112                 }
113                 p_emu->set_mouse_button(stat);
114 #endif
115 }
116
117 void EmuThreadClass::get_fd_string(void)
118 {
119 #if defined(USE_FD1)
120         int i;
121         QString tmpstr;
122         QString iname;
123         QString alamp;
124         uint32_t access_drv = 0;
125         access_drv = p_emu->is_floppy_disk_accessed();
126         {
127                 for(i = 0; i < (int)using_flags->get_max_drive(); i++) {
128                         tmpstr.clear();
129                         alamp.clear();
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
134                                 } else {
135                                         emit sig_set_access_lamp(i + 10, false);
136                                         alamp = QString::fromUtf8("<FONT COLOR=BLUE>○</FONT>"); // ðŸ’ŸU+1F4BE Floppy Disk
137                                 }
138                                 //tmpstr = alamp;
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]);
143                                 } else {
144                                         iname = QString::fromUtf8("*Inserted*");
145                                 }
146                                 tmpstr = iname;
147                         } else {
148                                 tmpstr.clear();
149                                 alamp = QString::fromUtf8("×");
150                         }
151                         if(alamp != fd_lamp[i]) {
152                                 emit sig_change_access_lamp(CSP_DockDisks_Domain_FD, i, alamp);
153                                 fd_lamp[i] = alamp;
154                         }
155                         if(tmpstr != fd_text[i]) {
156                                 emit sig_change_osd(CSP_DockDisks_Domain_FD, i, tmpstr);
157                                 fd_text[i] = tmpstr;
158                         }
159                 }
160         }
161 #endif
162 }
163
164 void EmuThreadClass::get_qd_string(void)
165 {
166 #if defined(USE_QD1)
167         int i;
168         QString iname;
169         QString alamp;
170         QString tmpstr;
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++) {
174                 tmpstr.clear();
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
178                         } else {
179                                 alamp = QString::fromUtf8("<FONT COLOR=BLUE>○</FONT>"); // ðŸ’œU+1F4BD MiniDisc
180                         }
181                         tmpstr = alamp;
182                         //tmpstr = tmpstr + QString::fromUtf8(" ");
183                         //iname = QString::fromUtf8("*Inserted*");
184                         //tmpstr = tmpstr + iname;
185                 } else {
186                         tmpstr = QString::fromUtf8("×");
187                 }
188                 if(tmpstr != qd_text[i]) {
189                         emit sig_change_access_lamp(CSP_DockDisks_Domain_QD, i, tmpstr);
190                         qd_text[i] = tmpstr;
191                 }
192         }
193 #endif
194 }       
195
196 void EmuThreadClass::get_tape_string()
197 {
198         QString tmpstr;
199         
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)) {
203                         tmpstr.clear();
204                         const _TCHAR *ts = p_emu->get_tape_message(i);
205                         if(ts != NULL) {
206                                 tmpstr = QString::fromUtf8(ts);
207                                 tmpstr = QString::fromUtf8("<FONT COLOR=RED>") + tmpstr + QString::fromUtf8("</FONT>");
208                         }
209                 } else {
210                         tmpstr = QString::fromUtf8("<FONT COLOR=BLUE>   EMPTY   </FONT>");
211                 }
212                 if(tmpstr != cmt_text[i]) {
213                         emit sig_change_osd(CSP_DockDisks_Domain_CMT, i, tmpstr);
214                         cmt_text[i] = tmpstr;
215                 }
216         }
217 #endif
218 }
219
220 void EmuThreadClass::get_cd_string(void)
221 {
222 #if defined(USE_COMPACT_DISC)
223         QString tmpstr;
224         if(p_emu->is_compact_disc_inserted()) {
225                 tmpstr = QString::fromUtf8("<FONT COLOR=BLUE>💿</FONT>");  // U+1F4BF OPTICAL DISC
226         } else {
227                 tmpstr = QString::fromUtf8("×");
228         }
229         if(tmpstr != cdrom_text) {
230                 emit sig_change_access_lamp(CSP_DockDisks_Domain_CD, 0, tmpstr);
231                 cdrom_text = tmpstr;
232         }
233 #endif
234 }
235
236 void EmuThreadClass::get_bubble_string(void)
237 {
238 #if defined(USE_BUBBLE1)
239         uint32_t access_drv;
240         int i;
241         QString alamp;
242         QString tmpstr;
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(" ");
247                 } else {
248                         tmpstr = QString::fromUtf8("×");
249                         //tmpstr = tmpstr + QString::fromUtf8(" ");
250                 }
251                 if(alamp != bubble_text[i]) {
252                         emit sig_change_access_lamp(CSP_DockDisks_Domain_Bubble, i, tmpstr);
253                         bubble_text[i] = alamp;
254                 }
255         }
256 #endif
257 }
258
259 void EmuThreadClass::doWork(const QString &params)
260 {
261         int interval = 0, sleep_period = 0;
262         int run_frames;
263         qint64 current_time;
264         bool first = true;
265         // LED
266         uint32_t led_data = 0x00000000;
267         uint32_t led_data_old = 0x00000000;
268         // Tape
269         // DIG_RESOLUTION
270         //
271         QString ctext;
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;
280
281         doing_debug_command = false;
282         ctext.clear();
283 //      draw_timing = false;
284         bResetReq = false;
285         bSpecialResetReq = false;
286         bLoadStateReq = false;
287         bSaveStateReq = false;
288         bUpdateConfigReq = false;
289         bStartRecordSoundReq = false;
290         bStopRecordSoundReq = false;
291         bStartRecordMovieReq = false;
292         sStateFile.clear();
293         record_fps = -1;
294
295         next_time = 0;
296         mouse_flag = false;
297
298         key_mod = 0;
299         //key_up_queue.clear();
300         //key_down_queue.clear();
301         clear_key_queue();
302
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++) {
305                 fd_text[i].clear();
306                 fd_lamp[i] = QString::fromUtf8("×");
307         }
308         for(int i = 0; i < using_flags->get_max_tape(); i++) {
309                 cmt_text[i].clear();
310         }
311         cdrom_text.clear();
312         for(int i = 0; i < using_flags->get_max_bubble(); i++) bubble_text[i].clear();
313         
314         do {
315                 //p_emu->SetHostCpus(this->idealThreadCount());
316                 if(MainWindow == NULL) {
317                         if(bRunThread == false){
318                                 goto _exit;
319                         }
320                         msleep(10);
321                         continue;
322                 }
323                 if(first) {
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]);
327                         }
328                         first = false;
329                 }
330                 interval = 0;
331                 sleep_period = 0;
332                 if(p_emu) {
333                         // drive machine
334 #ifdef USE_STATE
335                         if(bLoadStateReq != false) {
336                                 if(!sStateFile.isEmpty()) {
337                                         p_emu->load_state(sStateFile.toLocal8Bit().constData());
338                                         sStateFile.clear();
339                                 }
340                                 bLoadStateReq = false;
341                                 req_draw = true;
342                         }
343 #endif                  
344                         if(bResetReq != false) {
345                                 p_emu->reset();
346                                 bResetReq = false;
347                                 req_draw = true;
348                         }
349 #ifdef USE_SPECIAL_RESET
350                         if(bSpecialResetReq != false) {
351                                 p_emu->special_reset();
352                                 bSpecialResetReq = false;
353                         }
354 #endif
355 #ifdef USE_STATE
356                         if(bSaveStateReq != false) {
357                                 if(!sStateFile.isEmpty()) {
358                                         p_emu->save_state(sStateFile.toLocal8Bit().constData());
359                                         sStateFile.clear();
360                                 }
361                                 bSaveStateReq = false;
362                         }
363 #endif
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;
373 #endif
374                         if(bStartRecordSoundReq != false) {
375                                 p_emu->start_record_sound();
376                                 bStartRecordSoundReq = false;
377                                 req_draw = true;
378                         }
379                         if(bStopRecordSoundReq != false) {
380                                 p_emu->stop_record_sound();
381                                 bStopRecordSoundReq = false;
382                                 req_draw = true;
383                         }
384                         if(bUpdateConfigReq != false) {
385                                 p_emu->update_config();
386                                 bUpdateConfigReq = false;
387                                 req_draw = true;
388                         }
389                         if(bStartRecordMovieReq != false) {
390                                 if(!prevRecordReq && (record_fps > 0) && (record_fps < 75)) {           
391                                         p_emu->start_record_video(record_fps);
392                                         prevRecordReq = true;
393                                 }
394                         } else {
395                                 if(prevRecordReq) {
396                                         p_emu->stop_record_video();
397                                         record_fps = -1;
398                                         prevRecordReq = false;
399                                 }
400                         }
401                    
402                    
403
404 #if defined(USE_MOUSE)  // Will fix
405                         emit sig_is_enable_mouse(p_emu->is_mouse_enabled());
406 #endif                  
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;
412                                 }
413                         }
414 #endif
415                         if(p_config->romaji_to_kana) {
416                                 //FIFO *dmy = p_emu->get_auto_key_buffer();
417                                 //if(dmy != NULL) {
418                                 //      if(!dmy->empty()) {
419                                 //              p_emu->stop_auto_key();         
420                                 //              p_emu->start_auto_key();
421                                 //      }
422                                 //}
423                            
424                         }
425                         // else
426                         {
427                                 while(!is_empty_key_up()) {
428                                         key_queue_t sp;
429                                         dequeue_key_up(&sp);
430                                         key_mod = sp.mod;
431                                         {
432                                                 p_emu->key_modifiers(sp.mod);
433                                                 p_emu->key_up(sp.code, true); // need decicion of extend.
434                                         }
435                                 }
436                                 while(!is_empty_key_down()) {
437                                         key_queue_t sp;
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);
442                                         } else {
443                                                 p_emu->key_modifiers(sp.mod);
444                                                 p_emu->key_down(sp.code, true, sp.repeat);
445                                         }
446                                 }
447                         }
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();
452 #else
453                         req_draw = true;
454 #endif
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);
458 #else
459                         led_data = 0x00;
460 #endif
461 #if defined(USE_EXTRA_LEDS)
462   #if !defined(INDEPENDENT_CAPS_KANA_LED)
463                         led_data <<= USE_EXTRA_LEDS;
464   #endif
465                         led_data |= p_emu->get_extra_leds();
466 #endif
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;
471                         }
472 #endif
473                         sample_access_drv();
474
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();
480                         }
481                         if(!now_skip) {
482                                 next_time += interval;
483                         }
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;
489                                 if(!req_draw) {
490                                         no_draw_count++;
491                                         int count_limit = (int)(FRAMES_PER_SEC / 3);
492 #if defined(SUPPORT_TV_RENDER)
493                                         if(config.rendering_type == CONFIG_RENDER_TYPE_TV) {
494                                                 count_limit = 0;
495                                         }
496 #endif
497                                         if(no_draw_count > count_limit) {
498                                                 req_draw = true;
499                                                 no_draw_count = 0;
500                                         }
501                                 } else {
502                                         no_draw_count = 0;
503                                         //emit sig_draw_thread(true);
504                                 }
505                                 emit sig_draw_thread(req_draw);
506                                 skip_frames = 0;
507                         
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;
512                                 }
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);
517                                 no_draw_count = 0;
518                                 skip_frames = 0;
519                                 qint64 tt = tick_timer.elapsed();
520                                 if(config.full_speed) {
521                                         next_time = tt + 1;
522                                 } else {
523                                         next_time = tt + get_interval();
524                                 }
525                                 sleep_period = next_time - tt;
526                         }
527                 }
528                 req_draw = false;
529                 if(bRunThread == false){
530                         goto _exit;
531                 }
532                 if(sleep_period <= 0) sleep_period = 1;
533                 msleep(sleep_period);
534         } while(1);
535 _exit:
536         //emit quit_draw_thread();
537         csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
538                                                   "EmuThread : EXIT");
539         emit sig_finished();
540         this->quit();
541 }
542
543 void EmuThreadClass::do_set_display_size(int w, int h, int ww, int wh)
544 {
545         p_emu->suspend();
546         p_emu->set_host_window_size(w, h, true);
547 }
548
549 void EmuThreadClass::print_framerate(int frames)
550 {
551         if(frames >= 0) draw_frames += frames;
552         if(calc_message) {
553                 qint64 current_time = tick_timer.elapsed();
554                 if(update_fps_time <= current_time && update_fps_time != 0) {
555                         _TCHAR buf[256];
556                         QString message;
557                         //int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
558
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));
564                                 } else {
565                                         if(p_emu->message_count > 0) {
566                                                 snprintf(buf, 255, _T("%s - %s"), DEVICE_NAME, p_emu->message);
567                                                 p_emu->message_count--;
568                                         } else {
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);
571                                         }
572                                 }
573                                 if(romakana_conversion_mode) {
574                                         message = QString::fromUtf8("[R]");
575                                         message = message + QString::fromUtf8(buf);
576                                 } else {
577                                         message = buf;
578                                 }
579                                 emit message_changed(message);
580                                 emit window_title_changed(message);
581                                 update_fps_time += 1000;
582                                 total_frames = draw_frames = 0;
583                                 
584                         }
585                         if(update_fps_time <= current_time) {
586                                 update_fps_time = current_time + 1000;
587                         }
588                         calc_message = false;  
589                 } else {
590                         calc_message = true;
591                 }
592 }