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