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