]> git.vomp.tv Git - vompclient-marten.git/blob - osdopengl.cc
Fix segfault in OsdOpenGL shutdown
[vompclient-marten.git] / osdopengl.cc
1 /*\r
2     Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19 */\r
20 \r
21 \r
22 #include "osdopengl.h"\r
23 #include "mtd.h"\r
24 #include "videoomx.h"\r
25 #include "surfaceopengl.h"\r
26 \r
27 \r
28 #include "message.h"\r
29 #include "command.h"\r
30 \r
31 \r
32 #define  BACKBUFFER_WIDTH 1280\r
33 #define  BACKBUFFER_HEIGHT 720\r
34 \r
35 \r
36 \r
37 \r
38 \r
39 \r
40 \r
41 OsdOpenGL::OsdOpenGL()\r
42 {\r
43   glmutex.Lock();\r
44 \r
45   external_driving=false;\r
46 \r
47   lastrendertime=getTimeMS();\r
48   display_height=0;\r
49   display_width=0;\r
50 \r
51 #ifdef BENCHMARK_FPS\r
52         last_benchmark_time=getTimeMS();\r
53         num_benchmark_frames=0;\r
54 #endif\r
55 \r
56   \r
57 }\r
58 \r
59 OsdOpenGL::~OsdOpenGL()\r
60 {\r
61 \r
62   if (initted) \r
63   {\r
64           threadStop();\r
65                 shutdown();\r
66   }\r
67 \r
68 \r
69   glmutex.Unlock();\r
70 }\r
71 \r
72 int OsdOpenGL::getFD()\r
73 {\r
74   if (!initted) return 0;\r
75   return fdOsd;\r
76 }\r
77 \r
78 Surface * OsdOpenGL::createNewSurface() {\r
79         return (Surface*)new SurfaceOpenGL();\r
80 }\r
81 \r
82 int OsdOpenGL::init(void* device)\r
83 {\r
84   if (initted) return 0;\r
85   Video* video = Video::getInstance();\r
86    //window=*((HWND*)device);\r
87   \r
88    // May be this device specific part should go to a device specific child class\r
89 \r
90    //init broadcom chipset (Move to video?)\r
91 \r
92 \r
93    //First get connection to egl\r
94    egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);\r
95 \r
96    if (egl_display==EGL_NO_DISPLAY) {\r
97            Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());\r
98            glmutex.Unlock();\r
99            return 0;\r
100    }\r
101 \r
102 \r
103 \r
104    if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {\r
105            Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());\r
106            glmutex.Unlock();\r
107            return 0;\r
108    }\r
109 \r
110    const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);\r
111    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
112    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());\r
113    query_str=eglQueryString(egl_display,EGL_EXTENSIONS);\r
114    if (query_str)    Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
115    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());\r
116 \r
117    const EGLint attributs[]={\r
118                  EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,\r
119          EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,\r
120          EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,\r
121          EGL_NONE\r
122    }; // Here, we might have to select the resolution!\r
123 \r
124 \r
125    EGLint number;\r
126 \r
127    if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {\r
128            Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());\r
129            glmutex.Unlock();\r
130            return 0;\r
131    }\r
132 \r
133    const EGLint attr_context[]={\r
134                    EGL_CONTEXT_CLIENT_VERSION,2,\r
135           EGL_NONE\r
136       };\r
137 \r
138    egl_context=eglCreateContext(egl_display,egl_ourconfig,EGL_NO_CONTEXT,attr_context);\r
139    if (egl_context==EGL_NO_CONTEXT) {\r
140            Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());\r
141            glmutex.Unlock();\r
142            return 0;\r
143    }\r
144 \r
145    // warning broadcom specific, get display size!\r
146    display_width=display_height=0;\r
147    if (graphics_get_display_size(0, &display_width, &display_height)<0) {\r
148            Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");\r
149            glmutex.Unlock();\r
150            return 0;\r
151    }\r
152    Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);\r
153    VC_RECT_T dst_rect ={0,0,display_width,display_height};\r
154    VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};\r
155    DISPMANX_DISPLAY_HANDLE_T bcm_display;\r
156    DISPMANX_ELEMENT_HANDLE_T bcm_element;\r
157    DISPMANX_UPDATE_HANDLE_T  bcm_update;\r
158 \r
159 \r
160    bcm_display=vc_dispmanx_display_open(0);\r
161    bcm_update=vc_dispmanx_update_start(0);\r
162    bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,\r
163          2,&dst_rect, 0,\r
164          &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);\r
165 \r
166    vc_dispmanx_update_submit_sync(bcm_update);\r
167    static EGL_DISPMANX_WINDOW_T nativewindow;\r
168    nativewindow.element=bcm_element;\r
169    nativewindow.height=BACKBUFFER_HEIGHT;\r
170    nativewindow.width=BACKBUFFER_WIDTH;\r
171 \r
172    egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );\r
173    if (egl_surface==EGL_NO_SURFACE) {\r
174            Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");\r
175            glmutex.Unlock();\r
176            return 0;\r
177    }\r
178 \r
179    if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
180            Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");\r
181            glmutex.Unlock();\r
182                    return 0;\r
183    }\r
184    // Test stuff\r
185 \r
186    query_str=(const char*)glGetString(GL_VERSION) ;\r
187    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
188    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
189 \r
190    query_str=(const char*)glGetString(GL_VENDOR) ;\r
191    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
192    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
193 \r
194    query_str=(const char*)glGetString(GL_RENDERER) ;\r
195    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
196    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
197 \r
198    query_str=(const char*)glGetString(GL_EXTENSIONS) ;\r
199    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
200    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
201 \r
202 \r
203 \r
204 \r
205   //Now we will create the Screen\r
206   screen = (Surface*) new SurfaceOpenGL(Surface::SCREEN);\r
207 \r
208   screen->create(video->getScreenWidth(), video->getScreenHeight());\r
209   screen->display();\r
210   initted = 1; // must set this here or create surface won't work\r
211 \r
212   //glGenBuffers(1, &vB);\r
213   //glGenBuffers(1, &iB);\r
214 \r
215   //Preparing the Shaders\r
216 \r
217   if (!osd_shader.init()) {\r
218           Log::getInstance()->log("OSD", Log::WARN, "Init Osd Shader failed");\r
219           glmutex.Unlock();\r
220           return 0;\r
221   }\r
222 \r
223 \r
224 \r
225 \r
226   glClearColor(0.0f,0.0f,0.0f,1.f);\r
227   eglSwapInterval(egl_display, 1 );\r
228 \r
229   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
230 \r
231   if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init opengl stuff\r
232           return 0;\r
233   }\r
234 \r
235 \r
236   glmutex.Unlock();\r
237   threadStart();\r
238 \r
239   return 1;\r
240 }\r
241 \r
242 \r
243 \r
244 \r
245         \r
246 void OsdOpenGL::InitVertexBuffer(float  scalex,float scaley)\r
247 {\r
248   Video* video=Video::getInstance();\r
249   float texx=1.f;\r
250   float texy=1.f;\r
251   OSDCOLOR osdcolor={1.f,1.f,1.f,1.f};\r
252 \r
253  // osdvertices[0].c=osdcolor;\r
254   osdvertices[0].x= (scalex);\r
255   osdvertices[0].y=-scaley;\r
256   osdvertices[0].z=0.5;\r
257   osdvertices[0].u=texx;\r
258   osdvertices[0].v=texy;\r
259  // osdvertices[1].c=osdcolor;\r
260   osdvertices[1].x=(scalex);\r
261   osdvertices[1].y=(scaley);\r
262   osdvertices[1].z=0.5f;\r
263   osdvertices[1].u=texx;\r
264   osdvertices[1].v=0.f;\r
265   //  osdvertices[0].c=osdcolor;\r
266   osdvertices[2].x=(-scalex);\r
267   osdvertices[2].y=-scaley;\r
268   osdvertices[2].z=0.5f;\r
269   osdvertices[2].u=0.f;\r
270   osdvertices[2].v=texy;\r
271  // osdvertices[3].c=osdcolor;\r
272   osdvertices[3].x=-scalex;\r
273   osdvertices[3].y=(scaley);\r
274   osdvertices[3].z=0.5f;\r
275   osdvertices[3].u=0.f;\r
276   osdvertices[3].v=0.f;\r
277   \r
278   osdindices[0]=0;\r
279   osdindices[1]=1;\r
280   osdindices[2]=2;\r
281   osdindices[3]=0;\r
282   osdindices[4]=2;\r
283   osdindices[5]=3;\r
284 \r
285   return;\r
286 }\r
287 \r
288 int OsdOpenGL::shutdown()\r
289 {\r
290   if (!initted) return 0;\r
291   initted = 0;\r
292   threadStop();\r
293 \r
294   (((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());\r
295 \r
296 \r
297   osd_shader.deinit();\r
298 \r
299   glClear(GL_COLOR_BUFFER_BIT);\r
300   eglSwapBuffers(egl_display, egl_surface);\r
301   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
302   eglDestroySurface(egl_display,egl_surface);\r
303   eglDestroyContext(egl_display,egl_context);\r
304   eglTerminate(egl_display );\r
305 \r
306   return 1;\r
307 }\r
308 \r
309 void OsdOpenGL::screenShot(const char* fileName)\r
310 {\r
311   screen->screenShot(fileName);\r
312 }\r
313 \r
314 void OsdOpenGL::threadMethod()\r
315 {\r
316         // We have to claim the gl context for this thread\r
317         //glmutex.Lock();\r
318 \r
319         //glmutex.Unlock();\r
320         int ts=0;\r
321         while (true)\r
322         {\r
323                 ts=10;\r
324                 unsigned int waittime=10;\r
325 \r
326                 if (initted) {\r
327 \r
328                         long long time1 = getTimeMS();\r
329                         if ((time1 - lastrendertime) > 200) {//5 fps for OSD updates are enough, avoids tearing\r
330                                 InternalRendering();\r
331                                 lastrendertime = getTimeMS();\r
332 \r
333                         }\r
334                 }\r
335 \r
336                 threadCheckExit();\r
337                 if (ts!=0) {\r
338                         struct timespec target_time;\r
339                         clock_gettime(CLOCK_REALTIME,&target_time);\r
340                         target_time.tv_nsec+=1000000LL*ts;\r
341                         if (target_time.tv_nsec>999999999) {\r
342                                 target_time.tv_nsec-=1000000000L;\r
343                                 target_time.tv_sec+=1;\r
344                         }\r
345                         threadWaitForSignalTimed(&target_time);\r
346                 }\r
347                 //Sleep(1);\r
348         }\r
349         //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
350 }\r
351 \r
352 \r
353 void OsdOpenGL::threadPostStopCleanup()\r
354 {\r
355         //Doing nothing\r
356         //goo;\r
357 }\r
358 \r
359 \r
360 \r
361 void OsdOpenGL::InternalRendering(){\r
362 \r
363     BeginPainting();\r
364 \r
365 \r
366 \r
367 \r
368         //InitVertexBuffer(display_width,display_height);\r
369     InitVertexBuffer(1.f,1.f);\r
370 \r
371 \r
372         glViewport(0, 0, BACKBUFFER_WIDTH ,BACKBUFFER_HEIGHT);\r
373 \r
374         glClearColor(0.0f,0.0f,0.0f,1.f);\r
375         glClear(GL_COLOR_BUFFER_BIT);\r
376 \r
377         osd_shader.PrepareRendering(((SurfaceOpenGL*)screen)->getTexture());\r
378 \r
379         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), osdvertices);\r
380         glEnableVertexAttribArray(0);\r
381         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), &(osdvertices[0].u));\r
382         glEnableVertexAttribArray(1);\r
383 \r
384 \r
385 \r
386         glDisable(GL_BLEND);\r
387 \r
388 \r
389 \r
390         glDrawArrays(GL_TRIANGLE_STRIP, 0,  4);\r
391 \r
392 \r
393 \r
394         //Show it to the user!\r
395         eglSwapBuffers(egl_display, egl_surface);\r
396 \r
397         EndPainting();\r
398 \r
399 #ifdef BENCHMARK_FPS\r
400         num_benchmark_frames++;\r
401         if (getTimeMS()-last_benchmark_time>4000) {\r
402                 float fps=1000./(float)(getTimeMS()-last_benchmark_time);\r
403                 fps*=((float)num_benchmark_frames);\r
404                 num_benchmark_frames=0;\r
405                 Log::getInstance()->log("OSD", Log::NOTICE, "Current FPS %g", fps);\r
406                 last_benchmark_time=getTimeMS();\r
407 \r
408         }\r
409 \r
410 #endif\r
411 \r
412         \r
413 \r
414 }\r
415 \r
416 \r
417 \r
418 \r
419 void OsdOpenGL::BeginPainting() {//We synchronize calls to d3d between different threads\r
420         glmutex.Lock();\r
421         if (initted) {\r
422                 if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
423                         Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %d",eglGetError());\r
424                         return;\r
425                 }\r
426         }\r
427 }\r
428 \r
429 void OsdOpenGL::EndPainting() {\r
430         eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
431         glmutex.Unlock();\r
432 }\r
433 \r
434 \r
435 \r
436 void OsdOpenGL::Blank() {\r
437         BeginPainting();\r
438         glClearColor(0.15f, 0.25f, 0.35f, 1.0f); // change this to black after testing\r
439         glClear( GL_COLOR_BUFFER_BIT );\r
440         glClear( GL_DEPTH_BUFFER_BIT );\r
441         EndPainting();\r
442 }\r