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