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