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