2 Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
\r
4 This file is part of VOMP.
\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
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
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
22 #include "osdopengl.h"
\r
24 #include "videovpeogl.h"
\r
25 #include "surfaceopengl.h"
\r
28 #include "message.h"
\r
29 #include "command.h"
\r
32 #define BACKBUFFER_WIDTH 1280
\r
33 #define BACKBUFFER_HEIGHT 720
\r
41 OsdOpenGL::OsdOpenGL()
\r
45 external_driving=false;
\r
47 lastrendertime=getTimeMS();
\r
51 #ifdef BENCHMARK_FPS
\r
52 last_benchmark_time=getTimeMS();
\r
53 num_benchmark_frames=0;
\r
59 OsdOpenGL::~OsdOpenGL()
\r
72 int OsdOpenGL::getFD()
\r
74 if (!initted) return 0;
\r
78 Surface * OsdOpenGL::createNewSurface() {
\r
79 return (Surface*)new SurfaceOpenGL();
\r
82 int OsdOpenGL::init(void* device)
\r
84 if (initted) return 0;
\r
85 Video* video = Video::getInstance();
\r
86 //window=*((HWND*)device);
\r
88 // May be this device specific part should go to a device specific child class
\r
90 //init broadcom chipset (Move to video?)
\r
93 //First get connection to egl
\r
94 egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);
\r
96 if (egl_display==EGL_NO_DISPLAY) {
\r
97 Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());
\r
104 if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {
\r
105 Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());
\r
110 const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);
\r
111 if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
\r
112 else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
\r
113 query_str=eglQueryString(egl_display,EGL_EXTENSIONS);
\r
114 if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
\r
115 else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
\r
117 const EGLint attributs[]={
\r
118 EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,
\r
119 EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
\r
120 EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
\r
122 }; // Here, we might have to select the resolution!
\r
127 if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {
\r
128 Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());
\r
133 const EGLint attr_context[]={
\r
134 EGL_CONTEXT_CLIENT_VERSION,2,
\r
138 egl_context=eglCreateContext(egl_display,egl_ourconfig,EGL_NO_CONTEXT,attr_context);
\r
139 if (egl_context==EGL_NO_CONTEXT) {
\r
140 Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());
\r
145 // warning broadcom specific, get display size!
\r
146 display_width=display_height=0;
\r
147 if (graphics_get_display_size(0, &display_width, &display_height)<0) {
\r
148 Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");
\r
152 Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);
\r
153 VC_RECT_T dst_rect ={0,0,display_width,display_height};
\r
154 VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};
\r
155 DISPMANX_DISPLAY_HANDLE_T bcm_display;
\r
156 DISPMANX_ELEMENT_HANDLE_T bcm_element;
\r
157 DISPMANX_UPDATE_HANDLE_T bcm_update;
\r
160 bcm_display=vc_dispmanx_display_open(0);
\r
161 bcm_update=vc_dispmanx_update_start(0);
\r
162 bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,
\r
164 &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);
\r
166 vc_dispmanx_update_submit_sync(bcm_update);
\r
167 static EGL_DISPMANX_WINDOW_T nativewindow;
\r
168 nativewindow.element=bcm_element;
\r
169 nativewindow.height=BACKBUFFER_HEIGHT;
\r
170 nativewindow.width=BACKBUFFER_WIDTH;
\r
172 egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );
\r
173 if (egl_surface==EGL_NO_SURFACE) {
\r
174 Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");
\r
179 if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
\r
180 Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");
\r
186 query_str=(const char*)glGetString(GL_VERSION) ;
\r
187 if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
\r
188 else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
\r
190 query_str=(const char*)glGetString(GL_VENDOR) ;
\r
191 if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
\r
192 else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
\r
194 query_str=(const char*)glGetString(GL_RENDERER) ;
\r
195 if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
\r
196 else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
\r
198 query_str=(const char*)glGetString(GL_EXTENSIONS) ;
\r
199 if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
\r
200 else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
\r
205 //Now we will create the Screen
\r
206 screen = (Surface*) new SurfaceOpenGL(Surface::SCREEN);
\r
208 screen->create(video->getScreenWidth(), video->getScreenHeight());
\r
210 initted = 1; // must set this here or create surface won't work
\r
212 //glGenBuffers(1, &vB);
\r
213 //glGenBuffers(1, &iB);
\r
215 //Preparing the Shaders
\r
217 if (!osd_shader.init()) {
\r
218 Log::getInstance()->log("OSD", Log::WARN, "Init Osd Shader failed");
\r
222 if (!yuv400_shader.init()) {
\r
223 Log::getInstance()->log("OSD", Log::WARN, "Init Yuv400 Shader failed");
\r
228 if (!yuv444_shader.init()) {
\r
229 Log::getInstance()->log("OSD", Log::WARN, "Init Yuv444 Shader failed");
\r
236 glClearColor(0.0f,0.0f,0.0f,1.f);
\r
237 eglSwapInterval(egl_display, 1 );
\r
239 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
\r
241 if (((VideoVPEOGL*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init opengl stuff
\r
256 void OsdOpenGL::InitVertexBuffer(float scalex,float scaley)
\r
258 Video* video=Video::getInstance();
\r
261 OSDCOLOR osdcolor={1.f,1.f,1.f,1.f};
\r
263 // osdvertices[0].c=osdcolor;
\r
264 osdvertices[0].x= (scalex);
\r
265 osdvertices[0].y=-scaley;
\r
266 osdvertices[0].z=0.5;
\r
267 osdvertices[0].u=texx;
\r
268 osdvertices[0].v=texy;
\r
269 // osdvertices[1].c=osdcolor;
\r
270 osdvertices[1].x=(scalex);
\r
271 osdvertices[1].y=(scaley);
\r
272 osdvertices[1].z=0.5f;
\r
273 osdvertices[1].u=texx;
\r
274 osdvertices[1].v=0.f;
\r
275 // osdvertices[0].c=osdcolor;
\r
276 osdvertices[2].x=(-scalex);
\r
277 osdvertices[2].y=-scaley;
\r
278 osdvertices[2].z=0.5f;
\r
279 osdvertices[2].u=0.f;
\r
280 osdvertices[2].v=texy;
\r
281 // osdvertices[3].c=osdcolor;
\r
282 osdvertices[3].x=-scalex;
\r
283 osdvertices[3].y=(scaley);
\r
284 osdvertices[3].z=0.5f;
\r
285 osdvertices[3].u=0.f;
\r
286 osdvertices[3].v=0.f;
\r
298 int OsdOpenGL::shutdown()
\r
300 if (!initted) return 0;
\r
303 (((VideoVPEOGL*)Video::getInstance())->shutdownUsingOSDObjects());
\r
306 osd_shader.deinit();
\r
307 yuv400_shader.deinit();
\r
308 yuv444_shader.deinit();
\r
310 glClear(GL_COLOR_BUFFER_BIT);
\r
311 eglSwapBuffers(egl_display, egl_surface);
\r
312 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
\r
313 eglDestroySurface(egl_display,egl_surface);
\r
314 eglDestroyContext(egl_display,egl_context);
\r
315 eglTerminate(egl_display );
\r
320 void OsdOpenGL::screenShot(const char* fileName)
\r
322 screen->screenShot(fileName);
\r
325 void OsdOpenGL::threadMethod()
\r
327 // We have to claim the gl context for this thread
\r
330 //glmutex.Unlock();
\r
331 VPEOGLFrame *frame=NULL;
\r
333 VideoVPEOGL* video =(VideoVPEOGL*) Video::getInstance();
\r
337 unsigned int waittime=10;
\r
340 #ifdef VPE_LIBAV_SUPPORT
\r
341 if (!frame) frame=video->getReadyOGLFrame();
\r
343 InternalRendering(frame);
\r
344 // MILLISLEEP(1000);
\r
345 lastrendertime=getTimeMS();
\r
346 video->returnOGLFrame(frame); //please recycle it
\r
353 long long time1=getTimeMS();
\r
354 if ((time1-lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing
\r
355 InternalRendering(NULL);
\r
356 lastrendertime=getTimeMS();
\r
359 #ifdef VPE_LIBAV_SUPPORT
\r
360 frame=video->getReadyOGLFrame();
\r
368 struct timespec target_time;
\r
369 clock_gettime(CLOCK_REALTIME,&target_time);
\r
370 target_time.tv_nsec+=1000000LL*ts;
\r
371 if (target_time.tv_nsec>999999999) {
\r
372 target_time.tv_nsec-=1000000000L;
\r
373 target_time.tv_sec+=1;
\r
375 threadWaitForSignalTimed(&target_time);
\r
379 //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
\r
383 void OsdOpenGL::threadPostStopCleanup()
\r
391 void OsdOpenGL::InternalRendering(VPEOGLFrame* frame){
\r
396 //InitVertexBuffer(display_width,display_height);
\r
397 InitVertexBuffer(1.f,1.f);
\r
400 glViewport(0, 0, BACKBUFFER_WIDTH ,BACKBUFFER_HEIGHT);
\r
402 glClearColor(0.0f,0.0f,0.0f,1.f);
\r
403 glClear(GL_COLOR_BUFFER_BIT);
\r
406 switch (frame->type) {
\r
408 yuv400_shader.PrepareRendering(frame->textures[0],frame->textures[1],frame->textures[2]);break;
\r
410 yuv444_shader.PrepareRendering(frame->textures[0]);break;
\r
416 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), osdvertices);
\r
417 glEnableVertexAttribArray(0);
\r
418 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), &(osdvertices[0].u));
\r
419 glEnableVertexAttribArray(1);
\r
422 //Log::getInstance()->log("OSD", Log::WARN, "mark8 glerror %x %x",glGetError(),osd_sampler_loc);
\r
426 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
\r
434 osd_shader.PrepareRendering(((SurfaceOpenGL*)screen)->getTexture());
\r
436 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), osdvertices);
\r
437 glEnableVertexAttribArray(0);
\r
438 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), &(osdvertices[0].u));
\r
439 glEnableVertexAttribArray(1);
\r
442 if (frame!=NULL) { //This is ok for ffmpeg rendering not OMX
\r
443 glEnable(GL_BLEND);
\r
444 glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ZERO,GL_ONE);
\r
447 glDisable(GL_BLEND);
\r
451 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
\r
455 //Show it to the user!
\r
456 eglSwapBuffers(egl_display, egl_surface);
\r
459 #ifdef BENCHMARK_FPS
\r
460 num_benchmark_frames++;
\r
461 if (getTimeMS()-last_benchmark_time>4000) {
\r
462 float fps=1000./(float)(getTimeMS()-last_benchmark_time);
\r
463 fps*=((float)num_benchmark_frames);
\r
464 num_benchmark_frames=0;
\r
465 Log::getInstance()->log("OSD", Log::NOTICE, "Current FPS %g", fps);
\r
466 last_benchmark_time=getTimeMS();
\r
479 void OsdOpenGL::BeginPainting() {//We synchronize calls to d3d between different threads
\r
482 if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
\r
483 Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %d",eglGetError());
\r
489 void OsdOpenGL::EndPainting() {
\r
490 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
\r
496 void OsdOpenGL::Blank() {
\r
498 glClearColor(0.15f, 0.25f, 0.35f, 1.0f); // change this to black after testing
\r
499 glClear( GL_COLOR_BUFFER_BIT );
\r
500 glClear( GL_DEPTH_BUFFER_BIT );
\r