OSDN Git Service

[Qt][DRAW_THREAD] New (more accurate) draw scheduler.
[csp-qt/common_source_project-fm7.git] / source / src / qt / gui / draw_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   : 2006.08.18 -
6         License : GPLv2
7         History : 2015.11.10 Split from qt_main.cpp
8         [ win32 main ] -> [ Qt main ] -> [Drawing]
9 */
10
11 #include <Qt>
12 #include <QApplication>
13 #include <QImage>
14 #include <QGuiApplication>
15 #include <QSemaphore>
16 #include <QScreen>
17 #include <QWaitCondition>
18 #include <QElapsedTimer>
19
20 #include "emu.h"
21 #include "osd.h"
22 #include "vm/vm.h"
23
24 #include "qt_main.h"
25 #include "csp_logger.h"
26 #include "mainwidget_base.h"
27 #include "draw_thread.h"
28 #include "gl2/qt_glutil_gl2_0.h"
29 #include "config.h"
30
31
32 DrawThreadClass::DrawThreadClass(OSD *o, CSP_Logger *logger,QObject *parent) : QThread(parent) {
33         MainWindow = (Ui_MainWindowBase *)parent;
34         glv = MainWindow->getGraphicsView();
35         p_osd = o;
36         csp_logger = logger;
37         using_flags = NULL;
38         if(p_osd != NULL) using_flags = p_osd->get_config_flags();
39         screen = QGuiApplication::primaryScreen();
40
41         is_shared_glcontext = false;
42         glContext = NULL;
43         draw_screen_buffer = NULL;
44         if(p_osd != NULL) {
45                 p_osd->set_glview(glv);
46                 //printf("OSD/Context sharing succeeded.ADDR=%08x GLES=%s\n", glContext, (glContext->isOpenGLES()) ? "YES" : "NO");
47         }
48         do_change_refresh_rate(screen->refreshRate());
49         connect(screen, SIGNAL(refreshRateChanged(qreal)), this, SLOT(do_change_refresh_rate(qreal)));
50         connect(this, SIGNAL(sig_update_screen(void *, bool)), glv, SLOT(update_screen(void *, bool)), Qt::QueuedConnection);
51         
52         connect(this, SIGNAL(sig_update_osd()), glv, SLOT(update_osd()), Qt::QueuedConnection);
53         connect(this, SIGNAL(sig_push_frames_to_avio(int, int, int)), glv->extfunc, SLOT(paintGL_OffScreen(int, int, int)));
54         
55         //connect(this, SIGNAL(sig_call_draw_screen()), p_osd, SLOT(draw_screen()));
56         //connect(this, SIGNAL(sig_call_no_draw_screen()), p_osd, SLOT(no_draw_screen()));
57         use_separate_thread_draw = true;
58         if(using_flags->get_config_ptr() != NULL) {
59                 use_separate_thread_draw = using_flags->get_config_ptr()->use_separate_thread_draw;
60         }
61         rec_frame_width = 640;
62         rec_frame_height = 480;
63         rec_frame_count = -1;
64         emu_frame_rate = 1000.0 / 30.0;
65         wait_count = emu_frame_rate;
66         wait_refresh = emu_frame_rate;
67         bDrawReq = true;
68         renderSemaphore = new QSemaphore(0);
69         textureMappingSemaphore = new QSemaphore(0);
70         mapping_status = false;
71         mapping_pointer = NULL;
72         mapping_width = 0;
73         mapping_height = 0;
74         mapped_drawn = false;
75 }
76
77 DrawThreadClass::~DrawThreadClass()
78 {
79         if(renderSemaphore != NULL) {
80                 while(renderSemaphore->available() <= 0) renderSemaphore->release(1);
81                 delete renderSemaphore;
82         }
83         if(textureMappingSemaphore != NULL) {
84                 while(textureMappingSemaphore->available() <= 0) textureMappingSemaphore->release(1);
85                 delete textureMappingSemaphore;
86         }
87
88 }
89
90 void DrawThreadClass::SetEmu(EMU *p)
91 {
92         //p_emu = p;
93         p_osd = p->get_osd();
94 }
95
96 void DrawThreadClass::do_set_frames_per_second(double fps)
97 {
98         double _n = 1000.0 / (fps * 2.0);
99         emu_frame_rate = _n;
100         wait_count += (_n * 1.0);
101 }
102
103 // Note: Mapping vram from draw_thread does'nt work well.
104 // This feature might be disable. 20180728 K.Ohta.
105 void DrawThreadClass::doDrawMain(bool flag)
106 {
107         //req_map_screen_texture();
108         p_osd->do_decode_movie(1);
109         if(flag) {
110                 draw_frames = p_osd->draw_screen();
111         } else {
112                 draw_frames = p_osd->no_draw_screen();
113         }
114         //req_unmap_screen_texture();
115
116         emit sig_draw_frames(draw_frames);
117 }
118 void DrawThreadClass::doDraw(bool flag)
119 {
120         bRecentRenderStatus = flag;
121         if(!use_separate_thread_draw) {
122                 doDrawMain(flag);
123         } else {
124                 if(renderSemaphore != NULL) renderSemaphore->release(1);
125         }
126 }
127
128 void DrawThreadClass::doExit(void)
129 {
130         //csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
131         //                                        "DrawThread : Exit.");
132         bRunThread = false;
133         if(renderSemaphore != NULL) {
134                 while(renderSemaphore->available() <= 0) renderSemaphore->release(1);
135         }
136 }
137
138 void DrawThreadClass::do_draw_one_turn(bool _req_draw)
139 {
140         if((_req_draw) && (draw_screen_buffer != NULL)) {
141                 emit sig_update_screen((void *)draw_screen_buffer, mapped_drawn);
142         } else {
143                 if(ncount == 0) emit sig_update_osd();
144         }
145         ncount++;
146         if(ncount >= 8) ncount = 0; 
147         if(rec_frame_count > 0) {
148                 emit sig_push_frames_to_avio(rec_frame_count,
149                                                                          rec_frame_width, rec_frame_height);
150                 rec_frame_count = -1;
151         }
152         mapped_drawn = false;
153 }
154
155 void DrawThreadClass::doWork(const QString &param)
156 {
157         ncount = 0;
158         bRunThread = true;
159         double _rate = 1000.0 / 30.0;
160         bDrawReq = false;
161         QElapsedTimer tick_timer;
162         tick_timer.start();
163         quint64 elapsed = (quint64)_rate;
164         double drate;
165         if(renderSemaphore == NULL) {
166                 QSemaphore *s = new QSemaphore(0);
167                 if(s == NULL) goto __exit;
168                 renderSemaphore = s;
169         }
170         
171         do {
172                 //_rate = (wait_refresh < emu_frame_rate) ? emu_frame_rate : wait_refresh;
173                 _rate = 1.0e3 / p_osd->vm_frame_rate(); // FPS to msec
174                 drate = (double)elapsed / 1.0e6; // nsec to msec
175                 if(_rate >= drate) {
176                         wait_factor = (int)nearbyint(_rate - drate) + 3;
177                 } else {
178                         wait_factor = 3;
179                 }
180                 //printf("RATE:%f ELAPSED: %f WAIT_FACTOR:%d\n", _rate, drate,  wait_factor);
181                 if(renderSemaphore->tryAcquire(1, wait_factor)) { // Success
182                         if(!bRunThread) goto __exit;
183                         volatile bool _b = bRecentRenderStatus;
184                         bRecentRenderStatus = false;
185                         doDrawMain(_b);
186                 }
187                 if(!bRunThread) goto __exit;
188                 volatile bool _d = bDrawReq;
189                 if(draw_screen_buffer == NULL) _d = false;
190                 if((_d) && (draw_screen_buffer != NULL)) bDrawReq = false;
191                 do_draw_one_turn(_d);
192                 elapsed = tick_timer.nsecsElapsed();
193                 tick_timer.start();
194         } while(bRunThread);
195 __exit:
196         csp_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_GENERAL,
197                                                   "DrawThread : Exit.");
198         this->exit(0);
199 }
200
201 void DrawThreadClass::do_change_refresh_rate(qreal rate)
202 {
203         refresh_rate = rate;    
204         wait_refresh = 1000.0 / (refresh_rate * 2.0);
205         wait_count += (wait_refresh * 1.0);
206 }
207
208 void DrawThreadClass::do_update_screen(void *p, bool is_mapped)
209 {
210         draw_screen_buffer = (bitmap_t*)p;
211         bDrawReq = true;
212         mapped_drawn = is_mapped;
213 }
214         
215 void DrawThreadClass::do_req_encueue_video(int count, int width, int height)
216 {
217         rec_frame_width = width;
218         rec_frame_height = height;
219         rec_frame_count = count;
220 }
221 // Note: Mapping vram from draw_thread does'nt work well.
222 // This feature might be disable. 20180728 K.Ohta.
223 void DrawThreadClass::req_map_screen_texture()
224 {
225         mapping_status = false;
226         mapping_pointer = NULL;
227         mapping_width = 0;
228         mapping_height = 0;
229         if(glv->is_ready_to_map_vram_texture()) {
230                 textureMappingSemaphore->acquire();
231                 //mapping_pointer = (scrntype_t *)(glv->do_map_vram_texture(&mapping_width, &mapping_height));
232                 //if(mapping_pointer == NULL) {
233                 //      mapping_status = false;
234                 //      mapping_pointer = NULL;
235                 //      mapping_width = 0;
236                 //      mapping_height = 0;
237                 //} else {
238                 //      mapping_status = true;
239                 //}
240                 //p_osd->do_set_screen_map_texture_address(mapping_pointer, mapping_width, mapping_height);
241         }
242 }
243
244 void DrawThreadClass::req_unmap_screen_texture()
245 {
246         if(mapping_status) {
247                 if(glv->is_ready_to_map_vram_texture()) {
248                                 emit sig_unmap_texture();
249                                 textureMappingSemaphore->acquire();
250                                 
251                                 //glv->do_unmap_vram_texture();
252                                 //mapping_status = false;
253                                 //mapping_pointer = NULL;
254                                 //mapping_width = 0;
255                                 //mapping_height = 0;
256                                 //p_osd->do_set_screen_map_texture_address(mapping_pointer, mapping_width, mapping_height);
257                 }
258         }
259 }
260