OSDN Git Service

[EMU][GL] TV-Rendering: Adjust draw timing.
[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
19 #include "qt_gldraw.h"
20 #include "csp_logger.h"
21 #include "menu_flags.h"
22
23 // buttons
24 #ifdef MAX_BUTTONS
25 #define MAX_FONT_SIZE 32
26 #endif
27 #define MAX_SKIP_FRAMES 10
28
29 EmuThreadClass::EmuThreadClass(META_MainWindow *rootWindow, EMU *pp_emu, USING_FLAGS *p, QObject *parent)
30         : EmuThreadClassBase(rootWindow, pp_emu, p, parent)
31 {
32 }
33
34 EmuThreadClass::~EmuThreadClass()
35 {
36 }
37
38 int EmuThreadClass::get_interval(void)
39 {
40         static int accum = 0;
41         accum += p_emu->get_frame_interval();
42         int interval = accum >> 10;
43         accum -= interval << 10;
44         return interval;
45 }
46
47 void EmuThreadClass::moved_mouse(int x, int y)
48 {
49         mouse_x = x;
50         mouse_y = y;
51 #if defined(USE_MOUSE)   
52         p_emu->set_mouse_pointer(x, y);
53 #endif   
54 }
55
56 void EmuThreadClass::button_pressed_mouse_sub(Qt::MouseButton button)
57 {
58 #if defined(USE_MOUSE)   
59         int stat = p_emu->get_mouse_button();
60         bool flag = p_emu->is_mouse_enabled();
61         switch(button) {
62         case Qt::LeftButton:
63                 stat |= 0x01;
64                 break;
65         case Qt::RightButton:
66                 stat |= 0x02;
67                 break;
68         case Qt::MiddleButton:
69                 flag = !flag;
70                 emit sig_mouse_enable(flag);
71                 break;
72                 }
73         p_emu->set_mouse_button(stat);
74 #endif     
75 }       
76
77 void EmuThreadClass::button_released_mouse_sub(Qt::MouseButton button)
78 {
79 #if defined(USE_MOUSE)   
80                 int stat = p_emu->get_mouse_button();
81                 switch(button) {
82                 case Qt::LeftButton:
83                         stat &= 0x7ffffffe;
84                         break;
85                 case Qt::RightButton:
86                         stat &= 0x7ffffffd;
87                         break;
88                 case Qt::MiddleButton:
89                         //emit sig_mouse_enable(false);
90                         break;
91                 }
92                 p_emu->set_mouse_button(stat);
93 #endif
94 }
95
96 void EmuThreadClass::get_fd_string(void)
97 {
98 #if defined(USE_FD1)
99         int i;
100         QString tmpstr;
101         QString iname;
102         QString alamp;
103         uint32_t access_drv = 0;
104 #if defined(USE_ACCESS_LAMP) && defined(USE_FD1)
105         access_drv = p_emu->get_access_lamp_status();
106 #endif  
107         {
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> ");
113                                         } else {
114                                                 alamp = QString::fromUtf8("○ ");
115                                         }
116                                         tmpstr = QString::fromUtf8("FD");
117                                         tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
118                                 } else {
119                                         tmpstr = QString::fromUtf8("FD");
120                                         tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
121                                 }
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]);
124                                 } else {
125                                         iname = QString::fromUtf8("*Inserted*");
126                                 }
127                                 tmpstr = tmpstr + iname;
128                         } else {
129                                 tmpstr = QString::fromUtf8("× FD") + QString::number(i) + QString::fromUtf8(":");
130                                 tmpstr = tmpstr + QString::fromUtf8(" ");
131                         }
132                         if(tmpstr != fd_text[i]) {
133                                 emit sig_change_osd_fd(i, tmpstr);
134                                 fd_text[i] = tmpstr;
135                         }
136                 }
137         }
138 #endif
139 }
140
141 void EmuThreadClass::get_qd_string(void)
142 {
143 #if defined(USE_QD1)
144         int i;
145         QString iname;
146         QString alamp;
147         QString tmpstr;
148         uint32_t access_drv = 0;
149 # if defined(USE_ACCESS_LAMP)
150         access_drv = p_emu->get_access_lamp_status();
151 # endif
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("● ");
157                                 } else {
158                                         alamp = QString::fromUtf8("○ ");
159                                 }
160                                 tmpstr = QString::fromUtf8("QD");
161                                 tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
162                         } else {
163                                 tmpstr = QString::fromUtf8("QD");
164                                 tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
165                         }
166                         iname = QString::fromUtf8("*Inserted*");
167                         tmpstr = tmpstr + iname;
168                 } else {
169                         tmpstr = QString::fromUtf8("× QD") + QString::number(i) + QString::fromUtf8(":");
170                         tmpstr = tmpstr + QString::fromUtf8(" ");
171                 }
172                 if(tmpstr != qd_text[i]) {
173                         emit sig_change_osd_qd(i, tmpstr);
174                         qd_text[i] = tmpstr;
175                 }
176         }
177 #endif
178 }       
179
180 void EmuThreadClass::get_tape_string()
181 {
182         QString tmpstr = QString::fromUtf8("");
183         
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>");
192                 } else {
193                         tmpstr = QString::fromUtf8("<FONT COLOR=BLACK>■ </FONT>");
194                 }
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("%");
199                 } else {
200                         tmpstr = tmpstr + QString::fromUtf8("TOP");
201                 }
202         } else {
203                 tmpstr = QString::fromUtf8("EMPTY");
204         }
205         if(tmpstr != cmt_text) {
206                 emit sig_change_osd_cmt(tmpstr);
207                 cmt_text = tmpstr;
208         }
209 #endif
210 }
211
212 void EmuThreadClass::get_cd_string(void)
213 {
214 #if defined(USE_COMPACT_DISC)
215         QString tmpstr;
216         if(p_emu->is_compact_disc_inserted()) {
217                 tmpstr = QString::fromUtf8("○");
218         } else {
219                 tmpstr = QString::fromUtf8("Not Inserted");
220         }
221         if(tmpstr != cdrom_text) {
222                 emit sig_change_osd_cdrom(tmpstr);
223                 cdrom_text = tmpstr;
224         }
225 #endif
226 }
227
228 void EmuThreadClass::get_bubble_string(void)
229 {
230 #if defined(USE_BUBBLE1)
231         uint32_t access_drv;
232         int i;
233         QString alamp;
234         QString tmpstr;
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(":");
240                 } else {
241                         tmpstr = QString::fromUtf8("× BUB") + QString::number(i) + QString::fromUtf8(":");
242                         tmpstr = tmpstr + QString::fromUtf8(" ");
243                 }
244                 if(tmpstr != bubble_text[i]) {
245                         emit sig_change_osd_bubble(i, tmpstr);
246                         bubble_text[i] = tmpstr;
247                 }
248         }
249 #endif
250 }
251
252 void EmuThreadClass::doWork(const QString &params)
253 {
254         int interval = 0, sleep_period = 0;
255         int run_frames;
256         bool now_skip;
257         qint64 current_time;
258         bool first = true;
259         // LED
260         uint32_t led_data = 0x00000000;
261         uint32_t led_data_old = 0x00000000;
262         // Tape
263         bool tape_flag;
264         int tpos;
265         // DIG_RESOLUTION
266         int width, height;
267         //
268         QString ctext;
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;  
276         bool prevRecordReq;
277
278         doing_debug_command = false;
279         
280         ctext.clear();
281 //      draw_timing = false;
282         bResetReq = false;
283         bSpecialResetReq = false;
284         bLoadStateReq = false;
285         bSaveStateReq = false;
286         bUpdateConfigReq = false;
287         bStartRecordSoundReq = false;
288         bStopRecordSoundReq = false;
289         bStartRecordMovieReq = false;
290         record_fps = -1;
291
292         next_time = 0;
293         mouse_flag = false;
294
295         key_mod = 0;
296         //key_up_queue.clear();
297         //key_down_queue.clear();
298         clear_key_queue();
299
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();
302         cmt_text.clear();
303         cdrom_text.clear();
304         for(int i = 0; i < using_flags->get_max_bubble(); i++) bubble_text[i].clear();
305         
306         do {
307                 //p_emu->SetHostCpus(this->idealThreadCount());
308                 if(MainWindow == NULL) {
309                         if(bRunThread == false){
310                                 goto _exit;
311                         }
312                         msleep(10);
313                         continue;
314                 }
315                 if(first) {
316                         if(using_flags->get_use_led_device() > 0) emit sig_send_data_led((quint32)led_data);
317                         first = false;
318                 }
319                 interval = 0;
320                 sleep_period = 0;
321                 if(p_emu) {
322                         // drive machine
323 #ifdef USE_STATE
324                         if(bLoadStateReq != false) {
325                                 p_emu->load_state();
326                                 bLoadStateReq = false;
327                                 req_draw = true;
328                         }
329 #endif                  
330                         if(bResetReq != false) {
331                                 p_emu->reset();
332                                 bResetReq = false;
333                                 req_draw = true;
334                         }
335 #ifdef USE_SPECIAL_RESET
336                         if(bSpecialResetReq != false) {
337                                 p_emu->special_reset();
338                                 bSpecialResetReq = false;
339                         }
340 #endif
341 #ifdef USE_STATE
342                         if(bSaveStateReq != false) {
343                                 p_emu->save_state();
344                                 bSaveStateReq = false;
345                         }
346 #endif
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;
356 #endif
357                         if(bStartRecordSoundReq != false) {
358                                 p_emu->start_record_sound();
359                                 bStartRecordSoundReq = false;
360                                 req_draw = true;
361                         }
362                         if(bStopRecordSoundReq != false) {
363                                 p_emu->stop_record_sound();
364                                 bStopRecordSoundReq = false;
365                                 req_draw = true;
366                         }
367                         if(bUpdateConfigReq != false) {
368                                 p_emu->update_config();
369                                 bUpdateConfigReq = false;
370                                 req_draw = true;
371                         }
372                         if(bStartRecordMovieReq != false) {
373                                 if(!prevRecordReq && (record_fps > 0) && (record_fps < 75)) {           
374                                         p_emu->start_record_video(record_fps);
375                                         prevRecordReq = true;
376                                 }
377                         } else {
378                                 if(prevRecordReq) {
379                                         p_emu->stop_record_video();
380                                         record_fps = -1;
381                                         prevRecordReq = false;
382                                 }
383                         }
384                    
385                    
386
387 #if defined(USE_MOUSE)  // Will fix
388                         emit sig_is_enable_mouse(p_emu->is_mouse_enabled());
389 #endif                  
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;
395                                 }
396                         }
397 #endif
398                         if(roma_kana_conv) {
399                                 if(!roma_kana_queue.isEmpty()) {
400 #if defined(USE_AUTO_KEY)
401                                         FIFO *dmy = emu->get_auto_key_buffer();
402                                         if(dmy != NULL) {
403                                                 if(dmy->empty()) {
404                                                         QString tmps = roma_kana_queue.dequeue();
405                                                         this->do_start_auto_key(tmps);
406                                                 }
407                                         }
408 #else
409                                                 roma_kana_queue.clear();
410 #endif
411                                 }
412                                 if(roma_kana_queue.isEmpty()) {
413                                         roma_kana_conv = false;
414                                 }
415                         }
416                         // else
417                         {
418                                 while(!is_empty_key_up()) {
419                                         key_queue_t sp;
420                                         dequeue_key_up(&sp);
421                                         key_mod = sp.mod;
422                                         p_emu->key_modifiers(sp.mod);
423                                         p_emu->key_up(sp.code);
424                                 }
425                                 while(!is_empty_key_down()) {
426                                         key_queue_t sp;
427                                         dequeue_key_down(&sp);
428                                         p_emu->key_modifiers(sp.mod);
429                                         p_emu->key_down(sp.code, sp.repeat);
430                                 }
431                         }
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();
436 #else
437                         req_draw = true;
438 #endif                  
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;
444                         }
445 #endif
446                         sample_access_drv();
447
448                         interval += get_interval();
449                         now_skip = p_emu->is_frame_skippable() && !p_emu->is_video_recording();
450
451                         if((prev_skip && !now_skip) || next_time == 0) {
452                                 next_time = tick_timer.elapsed();
453                         }
454                         if(!now_skip) {
455                                 next_time += interval;
456                         }
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;
462                                 if(!req_draw) {
463                                         no_draw_count++;
464                                         int count_limit = (int)(FRAMES_PER_SEC / 3);
465 #if defined(SUPPORT_TV_RENDER)
466                                         if(config.rendering_type == CONFIG_RENDER_TYPE_TV) {
467                                                 count_limit = 0;
468                                         }
469 #endif
470                                         if(no_draw_count > count_limit) {
471                                                 req_draw = true;
472                                                 no_draw_count = 0;
473                                         }
474                                 } else {
475                                         no_draw_count = 0;
476                                         //emit sig_draw_thread(true);
477                                 }
478                                 emit sig_draw_thread(req_draw);
479                                 skip_frames = 0;
480                         
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;
485                                 }
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);
490                                 no_draw_count = 0;
491                                 skip_frames = 0;
492                                 qint64 tt = tick_timer.elapsed();
493                                 next_time = tt + get_interval();
494                                 sleep_period = next_time - tt;
495                         }
496                 }
497                 req_draw = false;
498                 if(bRunThread == false){
499                         goto _exit;
500                 }
501                 if(sleep_period <= 0) sleep_period = 1;
502                 msleep(sleep_period);
503         } while(1);
504 _exit:
505         //emit quit_draw_thread();
506         csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
507                                                   "EmuThread : EXIT");
508         emit sig_finished();
509         this->quit();
510 }
511
512 void EmuThreadClass::doSetDisplaySize(int w, int h, int ww, int wh)
513 {
514         p_emu->suspend();
515         //p_emu->set_vm_screen_size(w, h, -1, -1, ww, wh);
516         p_emu->set_host_window_size(w, h, true);
517 }
518
519 void EmuThreadClass::print_framerate(int frames)
520 {
521         if(frames >= 0) draw_frames += frames;
522         if(calc_message) {
523                 qint64 current_time = tick_timer.elapsed();
524                 if(update_fps_time <= current_time && update_fps_time != 0) {
525                         _TCHAR buf[256];
526                         QString message;
527                         int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
528
529                                 if(MainWindow->GetPowerState() == false){        
530                                         snprintf(buf, 255, _T("*Power OFF*"));
531                                 } else {
532                                         if(p_emu->message_count > 0) {
533                                                 snprintf(buf, 255, _T("%s - %s"), DEVICE_NAME, p_emu->message);
534                                                 p_emu->message_count--;
535                                         } else {
536                                                 snprintf(buf, 255, _T("%s - %d fps (%d %%)"), DEVICE_NAME, draw_frames, ratio);
537                                         }
538                                 }
539                                 if(romakana_conversion_mode) {
540                                         message = QString::fromUtf8("[R]");
541                                         message = message + QString::fromUtf8(buf);
542                                 } else {
543                                         message = buf;
544                                 }
545                                 emit message_changed(message);
546                                 emit window_title_changed(message);
547                                 update_fps_time += 1000;
548                                 total_frames = draw_frames = 0;
549                                 
550                         }
551                         if(update_fps_time <= current_time) {
552                                 update_fps_time = current_time + 1000;
553                         }
554                         calc_message = false;  
555                 } else {
556                         calc_message = true;
557                 }
558 }