OSDN Git Service

[UI][Qt] Update to upstream 2017-06-22.Some parts are temporally.
[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                         if(p_emu->is_floppy_disk_inserted(i)) {
129                                 if(i == (access_drv - 1)) {
130                                         alamp = QString::fromUtf8("<FONT COLOR=RED>●</FONT> ");
131                                 } else {
132                                         alamp = QString::fromUtf8("○ ");
133                                 }
134                                 tmpstr = alamp;
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]);
138                                 } else {
139                                         iname = QString::fromUtf8("*Inserted*");
140                                 }
141                                 tmpstr = tmpstr + iname;
142                         } else {
143                                 tmpstr = QString::fromUtf8("× ");
144                         }
145                         if(tmpstr != fd_text[i]) {
146                                 emit sig_change_osd(CSP_DockDisks_Domain_FD, i, tmpstr);
147                                 fd_text[i] = tmpstr;
148                         }
149                 }
150         }
151 #endif
152 }
153
154 void EmuThreadClass::get_qd_string(void)
155 {
156 #if defined(USE_QD1)
157         int i;
158         QString iname;
159         QString alamp;
160         QString tmpstr;
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("● ");
167                         } else {
168                                 alamp = QString::fromUtf8("○ ");
169                         }
170                         tmpstr = alamp;
171                         tmpstr = tmpstr + QString::fromUtf8(" ");
172                         iname = QString::fromUtf8("*Inserted*");
173                         tmpstr = tmpstr + iname;
174                 } else {
175                         tmpstr = QString::fromUtf8("× ");
176                 }
177                 if(tmpstr != qd_text[i]) {
178                         emit sig_change_osd(CSP_DockDisks_Domain_QD, i, tmpstr);
179                         qd_text[i] = tmpstr;
180                 }
181         }
182 #endif
183 }       
184
185 void EmuThreadClass::get_tape_string()
186 {
187         QString tmpstr;
188         
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);
193                         if(ts != NULL) {
194                                 tmpstr = QString::fromUtf8(ts);
195                         }
196                 } else {
197                         tmpstr = QString::fromUtf8("   EMPTY   ");
198                 }
199                 if(tmpstr != cmt_text) {
200                         emit sig_change_osd(CSP_DockDisks_Domain_CMT, i, tmpstr);
201                         cmt_text = tmpstr;
202                 }
203         }
204 #endif
205 }
206
207 void EmuThreadClass::get_cd_string(void)
208 {
209 #if defined(USE_COMPACT_DISC)
210         QString tmpstr;
211         if(p_emu->is_compact_disc_inserted()) {
212                 tmpstr = QString::fromUtf8("○");
213         } else {
214                 tmpstr = QString::fromUtf8("Not Inserted");
215         }
216         if(tmpstr != cdrom_text) {
217                 emit sig_change_osd(CSP_DockDisks_Domain_CD, 0, tmpstr);
218                 cdrom_text = tmpstr;
219         }
220 #endif
221 }
222
223 void EmuThreadClass::get_bubble_string(void)
224 {
225 #if defined(USE_BUBBLE1)
226         uint32_t access_drv;
227         int i;
228         QString alamp;
229         QString tmpstr;
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(" ");
234                 } else {
235                         tmpstr = QString::fromUtf8("×");
236                         tmpstr = tmpstr + QString::fromUtf8(" ");
237                 }
238                 if(tmpstr != bubble_text[i]) {
239                         emit sig_change_osd(CSP_DockDisks_Domain_Bubble, i, tmpstr);
240                         bubble_text[i] = tmpstr;
241                 }
242         }
243 #endif
244 }
245
246 void EmuThreadClass::doWork(const QString &params)
247 {
248         int interval = 0, sleep_period = 0;
249         int run_frames;
250         qint64 current_time;
251         bool first = true;
252         // LED
253         uint32_t led_data = 0x00000000;
254         uint32_t led_data_old = 0x00000000;
255         // Tape
256         // DIG_RESOLUTION
257         //
258         QString ctext;
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;
267
268         doing_debug_command = false;
269         ctext.clear();
270 //      draw_timing = false;
271         bResetReq = false;
272         bSpecialResetReq = false;
273         bLoadStateReq = false;
274         bSaveStateReq = false;
275         bUpdateConfigReq = false;
276         bStartRecordSoundReq = false;
277         bStopRecordSoundReq = false;
278         bStartRecordMovieReq = false;
279         sStateFile.clear();
280         record_fps = -1;
281
282         next_time = 0;
283         mouse_flag = false;
284
285         key_mod = 0;
286         //key_up_queue.clear();
287         //key_down_queue.clear();
288         clear_key_queue();
289
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();
292         cmt_text.clear();
293         cdrom_text.clear();
294         for(int i = 0; i < using_flags->get_max_bubble(); i++) bubble_text[i].clear();
295         
296         do {
297                 //p_emu->SetHostCpus(this->idealThreadCount());
298                 if(MainWindow == NULL) {
299                         if(bRunThread == false){
300                                 goto _exit;
301                         }
302                         msleep(10);
303                         continue;
304                 }
305                 if(first) {
306                         if(using_flags->get_use_led_device() > 0) emit sig_send_data_led((quint32)led_data);
307                         first = false;
308                 }
309                 interval = 0;
310                 sleep_period = 0;
311                 if(p_emu) {
312                         // drive machine
313 #ifdef USE_STATE
314                         if(bLoadStateReq != false) {
315                                 if(!sStateFile.isEmpty()) {
316                                         p_emu->load_state(sStateFile.toLocal8Bit().constData());
317                                         sStateFile.clear();
318                                 }
319                                 bLoadStateReq = false;
320                                 req_draw = true;
321                         }
322 #endif                  
323                         if(bResetReq != false) {
324                                 p_emu->reset();
325                                 bResetReq = false;
326                                 req_draw = true;
327                         }
328 #ifdef USE_SPECIAL_RESET
329                         if(bSpecialResetReq != false) {
330                                 p_emu->special_reset();
331                                 bSpecialResetReq = false;
332                         }
333 #endif
334 #ifdef USE_STATE
335                         if(bSaveStateReq != false) {
336                                 if(!sStateFile.isEmpty()) {
337                                         p_emu->save_state(sStateFile.toLocal8Bit().constData());
338                                         sStateFile.clear();
339                                 }
340                                 bSaveStateReq = false;
341                         }
342 #endif
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;
352 #endif
353                         if(bStartRecordSoundReq != false) {
354                                 p_emu->start_record_sound();
355                                 bStartRecordSoundReq = false;
356                                 req_draw = true;
357                         }
358                         if(bStopRecordSoundReq != false) {
359                                 p_emu->stop_record_sound();
360                                 bStopRecordSoundReq = false;
361                                 req_draw = true;
362                         }
363                         if(bUpdateConfigReq != false) {
364                                 p_emu->update_config();
365                                 bUpdateConfigReq = false;
366                                 req_draw = true;
367                         }
368                         if(bStartRecordMovieReq != false) {
369                                 if(!prevRecordReq && (record_fps > 0) && (record_fps < 75)) {           
370                                         p_emu->start_record_video(record_fps);
371                                         prevRecordReq = true;
372                                 }
373                         } else {
374                                 if(prevRecordReq) {
375                                         p_emu->stop_record_video();
376                                         record_fps = -1;
377                                         prevRecordReq = false;
378                                 }
379                         }
380                    
381                    
382
383 #if defined(USE_MOUSE)  // Will fix
384                         emit sig_is_enable_mouse(p_emu->is_mouse_enabled());
385 #endif                  
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;
391                                 }
392                         }
393 #endif
394                         if(p_config->romaji_to_kana) {
395                                 //FIFO *dmy = p_emu->get_auto_key_buffer();
396                                 //if(dmy != NULL) {
397                                 //      if(!dmy->empty()) {
398                                 //              p_emu->stop_auto_key();         
399                                 //              p_emu->start_auto_key();
400                                 //      }
401                                 //}
402                            
403 #if 0
404                                 if(!roma_kana_queue.isEmpty()) {
405 #if defined(USE_AUTO_KEY)
406                                         FIFO *dmy = emu->get_auto_key_buffer();
407                                         if(dmy != NULL) {
408                                                 if(dmy->empty()) {
409                                                         QString tmps = roma_kana_queue.dequeue();
410                                                         this->do_start_auto_key(tmps);
411                                                 }
412                                         }
413 #else
414                                                 roma_kana_queue.clear();
415 #endif
416                                 }
417                                 if(roma_kana_queue.isEmpty()) {
418                                         roma_kana_conv = false;
419                                 }
420 #endif
421                         }
422                         // else
423                         {
424                                 while(!is_empty_key_up()) {
425                                         key_queue_t sp;
426                                         dequeue_key_up(&sp);
427                                         key_mod = sp.mod;
428                                         {
429                                                 p_emu->key_modifiers(sp.mod);
430                                                 p_emu->key_up(sp.code, true); // need decicion of extend.
431                                         }
432                                 }
433                                 while(!is_empty_key_down()) {
434                                         key_queue_t sp;
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);
439                                         } else {
440                                                 p_emu->key_modifiers(sp.mod);
441                                                 p_emu->key_down(sp.code, true, sp.repeat);
442                                         }
443                                 }
444                         }
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();
449 #else
450                         req_draw = true;
451 #endif                  
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;
457                         }
458 #endif
459                         sample_access_drv();
460
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();
466                         }
467                         if(!now_skip) {
468                                 next_time += interval;
469                         }
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;
475                                 if(!req_draw) {
476                                         no_draw_count++;
477                                         int count_limit = (int)(FRAMES_PER_SEC / 3);
478 #if defined(SUPPORT_TV_RENDER)
479                                         if(config.rendering_type == CONFIG_RENDER_TYPE_TV) {
480                                                 count_limit = 0;
481                                         }
482 #endif
483                                         if(no_draw_count > count_limit) {
484                                                 req_draw = true;
485                                                 no_draw_count = 0;
486                                         }
487                                 } else {
488                                         no_draw_count = 0;
489                                         //emit sig_draw_thread(true);
490                                 }
491                                 emit sig_draw_thread(req_draw);
492                                 skip_frames = 0;
493                         
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;
498                                 }
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);
503                                 no_draw_count = 0;
504                                 skip_frames = 0;
505                                 qint64 tt = tick_timer.elapsed();
506                                 if(config.full_speed) {
507                                         next_time = tt + 1;
508                                 } else {
509                                         next_time = tt + get_interval();
510                                 }
511                                 sleep_period = next_time - tt;
512                         }
513                 }
514                 req_draw = false;
515                 if(bRunThread == false){
516                         goto _exit;
517                 }
518                 if(sleep_period <= 0) sleep_period = 1;
519                 msleep(sleep_period);
520         } while(1);
521 _exit:
522         //emit quit_draw_thread();
523         csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
524                                                   "EmuThread : EXIT");
525         emit sig_finished();
526         this->quit();
527 }
528
529 void EmuThreadClass::do_set_display_size(int w, int h, int ww, int wh)
530 {
531         p_emu->suspend();
532         //p_emu->set_vm_screen_size(w, h, -1, -1, ww, wh);
533         p_emu->set_host_window_size(w, h, true);
534 }
535
536 void EmuThreadClass::print_framerate(int frames)
537 {
538         if(frames >= 0) draw_frames += frames;
539         if(calc_message) {
540                 qint64 current_time = tick_timer.elapsed();
541                 if(update_fps_time <= current_time && update_fps_time != 0) {
542                         _TCHAR buf[256];
543                         QString message;
544                         //int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
545
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));
551                                 } else {
552                                         if(p_emu->message_count > 0) {
553                                                 snprintf(buf, 255, _T("%s - %s"), DEVICE_NAME, p_emu->message);
554                                                 p_emu->message_count--;
555                                         } else {
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);
558                                         }
559                                 }
560                                 if(romakana_conversion_mode) {
561                                         message = QString::fromUtf8("[R]");
562                                         message = message + QString::fromUtf8(buf);
563                                 } else {
564                                         message = buf;
565                                 }
566                                 emit message_changed(message);
567                                 emit window_title_changed(message);
568                                 update_fps_time += 1000;
569                                 total_frames = draw_frames = 0;
570                                 
571                         }
572                         if(update_fps_time <= current_time) {
573                                 update_fps_time = current_time + 1000;
574                         }
575                         calc_message = false;  
576                 } else {
577                         calc_message = true;
578                 }
579 }