Bugfix : Moving the framecounter inside of graphic system
[profile/ivi/layer-management.git] / LayerManagerPlugins / Renderers / Graphic / src / GraphicSystems / GLESGraphicSystem.cpp
1 /***************************************************************************
2  *
3  * Copyright 2010,2011 BMW Car IT GmbH
4  *
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  ****************************************************************************/
19
20 #include "GraphicSystems/GLESGraphicSystem.h"
21 #include "IlmMatrix.h"
22 #include "string.h"
23 #include "EGL/egl.h"
24 #include "GLES2/gl2.h"
25 #include "Bitmap.h"
26 #include "Transformation/ViewportTransform.h"
27
28 static const float vertices[8 * 12] =
29 { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
30
31 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
32
33 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
34
35 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
36
37 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
38
39 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
40
41 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
42
43 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0
44
45 };
46
47 GLESGraphicsystem::GLESGraphicsystem(int windowWidth, int windowHeight, PfnShaderProgramCreator shaderProgram)
48 : m_windowWidth(windowWidth)
49 , m_windowHeight(windowHeight)
50 , m_shaderCreatorFunc(shaderProgram)
51 {
52     LOG_DEBUG("GLESGraphicsystem", "creating GLESGraphicsystem");
53 }
54
55 bool GLESGraphicsystem::init(EGLNativeDisplayType display, EGLNativeWindowType NativeWindow)
56 {
57     m_nativeDisplay = display;
58     m_nativeWindow = NativeWindow;
59
60     EGLint iMajorVersion, iMinorVersion;
61     LOG_DEBUG("GLESGraphicsystem", "Getting EGL Display with native display " << m_nativeDisplay);
62     m_eglDisplay = eglGetDisplay(m_nativeDisplay);
63
64     if (m_eglDisplay == EGL_NO_DISPLAY){
65         LOG_ERROR("GLESGraphicsystem", "failed to Get EGL Display");
66         return false;
67     }
68
69     LOG_DEBUG("GLESGraphicsystem", "Initialising EGL");
70     if (!eglInitialize(m_eglDisplay, &iMajorVersion, &iMinorVersion))
71     {
72         LOG_ERROR("GLESGraphicsystem", "Initialising EGL failed");
73         return false;
74     }
75
76     LOG_DEBUG("GLESGraphicsystem", "Binding GLES API");
77     eglBindAPI(EGL_OPENGL_ES_API);
78
79     EGLint pi32ConfigAttribs[] = {
80             EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE,
81             EGL_OPENGL_ES2_BIT,
82             EGL_RED_SIZE,
83             8,
84             EGL_ALPHA_SIZE,
85             8,
86             EGL_NONE
87     };
88
89     LOG_DEBUG("GLESGraphicsystem", "EGLChooseConfig");
90     int iConfigs;
91     if (!eglChooseConfig(m_eglDisplay, pi32ConfigAttribs, &m_eglConfig, 1, &iConfigs) || (iConfigs != 1))
92     {
93         LOG_DEBUG("GLESGraphicsystem", "Error: eglChooseConfig() failed.");
94         return false;
95     }
96     EGLint id = 0;
97     eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_CONFIG_ID, &id);
98
99     EGLint windowsAttr[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
100
101     LOG_DEBUG("GLESGraphicsystem", "Config chosen:" << id);
102     LOG_DEBUG("GLESGraphicsystem", "Create Window surface");
103
104     m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_nativeWindow, windowsAttr);
105     if (!m_eglSurface)
106     {
107         EGLenum status = eglGetError();
108         LOG_ERROR("GLESGraphicsystem", "Window Surface creation failed with EGL Error Code: "<< status);
109         return false;
110     }
111     LOG_DEBUG("GLESGraphicsystem", "Window Surface creation successfull");
112
113     EGLint contextAttrs[] = {
114             EGL_CONTEXT_CLIENT_VERSION,
115             2,
116             EGL_NONE
117     };
118
119     m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttrs);
120     if (!m_eglContext)
121     {
122         LOG_ERROR("GLESGraphicsystem","EGL couldn't create context\n");
123         return false;
124     }
125     LOG_INFO("GLESGraphicsystem", "EGL make current ...");
126     // Make the context and surface current for rendering
127     EGLBoolean eglStatus = false;
128     eglStatus = eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
129     LOG_INFO("GLESGraphicsystem", "made current");
130
131     eglSwapInterval(m_eglDisplay, 1); // TODO: does not seem to work
132
133     if (!initOpenGLES(m_windowWidth, m_windowHeight))
134     {
135         return false;
136     }
137     return true;
138 }
139
140 void GLESGraphicsystem::clearBackground()
141 {
142     glClear(GL_COLOR_BUFFER_BIT);
143 }
144
145 void GLESGraphicsystem::swapBuffers()
146 {
147     eglSwapBuffers(m_eglDisplay, m_eglSurface);
148 }
149
150 void GLESGraphicsystem::beginLayer(Layer* currentLayer)
151 {
152     //LOG_DEBUG("GLESGraphicsystem", "Beginning to draw layer: " << currentLayer->getID());
153     m_currentLayer = currentLayer;
154     // TODO layer destination / source
155 }
156
157 void GLESGraphicsystem::checkRenderLayer()
158 {
159         SurfaceList surfaces = m_currentLayer->getAllSurfaces();
160
161         m_currentLayer->damaged = false;
162
163         if (!m_baseWindowSystem->m_damaged)
164         {
165                 if (m_currentLayer->renderPropertyChanged)
166                 {
167                         m_currentLayer->damaged = true;
168                 }
169                 else if ((m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0)
170                 {
171                         for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
172                         {
173                                 if ((*currentS)->renderPropertyChanged)
174                                 {
175                                         m_currentLayer->damaged = true;
176                                         break;
177                                 }
178                                 else if ((*currentS)->damaged && (*currentS)->visibility && (*currentS)->opacity>0.0f)
179                                 {
180                                         m_currentLayer->damaged = true;
181                                         break;
182                                 }
183                         }
184                 }
185         }
186
187         for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
188         {
189                 (*currentS)->damaged = false;
190                 (*currentS)->renderPropertyChanged = false;
191         }
192
193         m_currentLayer->renderPropertyChanged = false;
194
195         if (m_currentLayer->damaged)
196         {
197                 m_baseWindowSystem->m_damaged = true;
198         }
199 }
200
201 void GLESGraphicsystem::renderLayer()
202 {
203         if ( (m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0 ) 
204     {
205         SurfaceList surfaces = m_currentLayer->getAllSurfaces();
206         for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
207         {
208             if ((*currentS)->visibility && (*currentS)->opacity>0.0f)
209             {
210                 Surface* currentSurface = (Surface*)*currentS;
211                 renderSurface(currentSurface);
212             }
213         }
214     }
215 }
216
217 void GLESGraphicsystem::endLayer()
218 {
219     //LOG_DEBUG("GLESGraphicsystem", "Done with rendering layer: " << m_currentLayer->getID());
220     m_currentLayer = NULL;
221 }
222
223 //this is a particularly simple function currently, but it will likely be expanded as more shaders and effects are implemented.
224 Shader *GLESGraphicsystem::pickOptimizedShader(Shader* currentShader, const ShaderProgram::CommonUniforms curUniforms)
225 {
226     Shader * retShader = currentShader;
227
228     if (currentShader == m_defaultShader && curUniforms.opacity == 1.0f)
229     {
230       //no need for multiply in shader, just use texture
231       retShader = m_defaultShaderNoUniformAlpha;
232     }
233
234     return retShader;
235
236 }
237
238 void GLESGraphicsystem::renderSurface(Surface* surface)
239 {
240 //  LOG_DEBUG("GLESGraphicsystem", "renderSurface " << surface->getID());
241
242     GLint index = 0;
243     IlmMatrix layerMatrix;
244     IlmMatrixIdentity(layerMatrix);
245
246     ShaderProgram::CommonUniforms uniforms;
247 #ifdef DRAW_LAYER_DEBUG
248     ShaderProgram::CommonUniforms layeruniforms;
249 #endif
250     Shader* layerShader = m_currentLayer->getShader();
251     if (!layerShader)
252     {
253         // use default shader if no custom shader is assigned to this layer
254         layerShader = m_defaultShader;
255     }
256     Shader* shader = (surface)->getShader();
257     if (!shader)
258     {
259         // use layer shader if no custom shader is assigned to this surface
260         shader = layerShader;
261     }
262     const Rectangle& layerDestinationRegion = (m_currentLayer)->getDestinationRegion();
263     const Rectangle& layerSourceRegion = (m_currentLayer)->getSourceRegion();
264
265     // these variables contain the current calculated values of the surface
266     Rectangle targetSurfaceSource = surface->getSourceRegion();
267     Rectangle targetSurfaceDestination = surface->getDestinationRegion();
268
269     ViewportTransform::applyLayerSource(layerSourceRegion, targetSurfaceSource, targetSurfaceDestination);
270     ViewportTransform::applyLayerDestination(layerDestinationRegion, layerSourceRegion, targetSurfaceDestination);
271     float* textureCoordinates = new float[4];
272     ViewportTransform::transformRectangleToTextureCoordinates(targetSurfaceSource, surface->OriginalSourceWidth, surface->OriginalSourceHeight, textureCoordinates);
273
274     glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
275     IlmMatrixRotateZ(layerMatrix, m_currentLayer->getOrientation() * 90.0f);
276     // update all common uniforms, scale values to display size
277     uniforms.x = (float)targetSurfaceDestination.x / m_displayWidth;
278     uniforms.y = (float)targetSurfaceDestination.y / m_displayHeight;;
279     uniforms.width = (float)targetSurfaceDestination.width / m_displayWidth;
280     uniforms.height = (float)targetSurfaceDestination.height / m_displayHeight;
281     uniforms.opacity = (surface)->getOpacity() * m_currentLayer->getOpacity();
282     uniforms.texRange[0] = (textureCoordinates[1]-textureCoordinates[0]);
283     uniforms.texRange[1] = (textureCoordinates[3]-textureCoordinates[2]);
284     uniforms.texOffset[0] = textureCoordinates[0];
285     uniforms.texOffset[1] = -textureCoordinates[2];
286     uniforms.texUnit = 0;
287     uniforms.matrix = &layerMatrix.f[0];
288
289
290     //We only know about specific Shaders, only do this if we start with the defaultShader
291     if (shader == m_defaultShader && uniforms.opacity == 1.0f)
292     {
293         if(!PixelFormatHasAlpha((surface)->getPixelFormat()))
294         {
295             //disable alpha blend completely
296             glDisable (GL_BLEND);
297         }
298         else
299         {
300             //make sure alpha blend is enabled
301             glEnable (GL_BLEND);
302         }
303     }
304     else
305     {
306         //make sure alpha blend is enabled
307         glEnable (GL_BLEND);
308     }
309
310     shader = pickOptimizedShader(shader, uniforms);
311
312
313 #ifdef DRAW_LAYER_DEBUG
314     layeruniforms.x = (float) layerDestinationRegion.x / m_displayWidth;
315     layeruniforms.y = (float) layerDestinationRegion.y / m_displayHeight;
316     layeruniforms.width = (float)layerDestinationRegion.width / m_displayWidth;
317     layeruniforms.height = (float)layerDestinationRegion.height / m_displayHeight;
318     layeruniforms.opacity = m_currentLayer->getOpacity();
319     layeruniforms.matrix = &layerMatrix.f[0];
320     m_layerShader->use();
321     m_layerShader->loadCommonUniforms(layeruniforms);
322     m_layerShader->loadUniforms();
323
324     glDrawArrays(GL_TRIANGLES, 0, 6);
325 #endif
326     shader->use();
327
328     /* load common uniforms */
329     shader->loadCommonUniforms(uniforms);
330
331     /* update all custom defined uniforms */
332     shader->loadUniforms();
333     /* Bind texture and set section */
334     glActiveTexture(GL_TEXTURE0);
335     if (false == m_binder->bindSurfaceTexture(surface)) 
336     {   
337 //        LOG_DEBUG("GLESGraphicsystem", "renderSurface not successfully bind " << surface->getID());
338         return;
339     } else {
340 //        LOG_DEBUG("GLESGraphicsystem", "renderSurface " << surface->getID());
341     }
342
343     /* rotated positions are saved sequentially in vbo
344      offset in multiples of 12 decide rotation */
345     /* Draw two triangles */
346     int orientation = (surface)->getOrientation();
347     orientation %= 4;
348     index = orientation * 12;
349     surface->frameCounter++;
350     glDrawArrays(GL_TRIANGLES, index, 6);
351
352     glBindBuffer(GL_ARRAY_BUFFER, 0);
353     glGetError(); // TODO
354
355     delete textureCoordinates;
356 }
357
358 bool GLESGraphicsystem::initOpenGLES(EGLint displayWidth, EGLint displayHeight)
359 {
360     LOG_DEBUG("GLESGraphicsystem", "initEGL");
361     bool result = true;
362     ShaderProgramFactory::setCreatorFunc(m_shaderCreatorFunc);
363     m_defaultShader = Shader::createShader("default", "default");
364     m_defaultShaderNoUniformAlpha = Shader::createShader("default", "default_no_uniform_alpha");
365
366 #ifdef DRAW_LAYER_DEBUG
367     m_layerShader = Shader::createShader("/usr/lib/layermanager/renderer/renderer_layer.glslv", "/usr/lib/layermanager/renderer/renderer_layer.glslf");
368     if (m_layerShader==0)
369     {
370         m_layerShader = Shader::createShader("/usr/local/lib/layermanager/renderer/renderer_layer.glslv", "/usr/local/lib/layermanager/renderer/renderer_layer.glslf");
371     }
372 #endif
373     if (
374       !m_defaultShader || !m_defaultShaderNoUniformAlpha
375 #ifdef DRAW_LAYER_DEBUG
376     || !m_layerShader
377 #endif
378     )
379     {
380         LOG_ERROR("GLESGraphicsystem", "Failed to create and link default shader program");
381         delete m_defaultShader;
382         result = false;
383     }
384     else
385     {
386         LOG_INFO("GLESGraphicsystem", "Default Shader successfully applied");
387         glGenBuffers(1, &m_vbo);
388         glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
389         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
390         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
391         glEnableVertexAttribArray(0);
392         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*) (sizeof(float) * 12));
393         glEnableVertexAttribArray(1);
394
395         glEnable(GL_BLEND);
396         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
397         m_blendingStatus = true;
398         glClearColor(0.0, 0.0, 0.0, 0.0);
399         resize(displayWidth, displayHeight);
400     }
401     return result;
402 }
403
404 void GLESGraphicsystem::resize(EGLint displayWidth, EGLint displayHeight)
405 {
406     m_displayWidth = displayWidth;
407     m_displayHeight = displayHeight;
408     glViewport(0, 0, m_displayWidth, m_displayHeight);
409 }
410
411 void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
412 {
413     // clear error if any
414     int error = glGetError();
415     LOG_DEBUG("BaseGraphicSystem","taking screenshot and saving it to:" << fileToSave);
416
417     GLint viewport[4];
418     glGetIntegerv(GL_VIEWPORT, viewport); // x,y,width,height
419     error = glGetError();
420     if (error != GL_NO_ERROR)
421     {
422         LOG_DEBUG("BaseGraphicSystem","error getting dimensions");
423     }
424     int WINDOW_WIDTH = viewport[2];
425     int WINDOW_HEIGHT = viewport[3];
426     LOG_DEBUG("BaseGraphicSystem","Screenshot: " << WINDOW_WIDTH << " * " << WINDOW_HEIGHT);
427     char *buffer = (char *) malloc( WINDOW_WIDTH * WINDOW_HEIGHT * 4 * sizeof(char));
428     glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
429     error = glGetError();
430     if (error != GL_NO_ERROR)
431     {
432         LOG_DEBUG("BaseGraphicSystem","error reading pixels for screenshot: " << error);
433     }
434     // convert to RGB for bitmap
435     int pixelcount = WINDOW_WIDTH * WINDOW_HEIGHT;
436     char *rgbbuffer = (char *) malloc(pixelcount * 3 * sizeof(char));
437     for (int row = 0; row < WINDOW_HEIGHT; row++)
438     {
439         for (int col = 0; col < WINDOW_WIDTH; col++)
440         {
441             int offset = row * WINDOW_WIDTH + col;
442             rgbbuffer[offset * 3] = buffer[offset * 4 + 2];
443             rgbbuffer[offset * 3 + 1] = buffer[offset * 4 + 1];
444             rgbbuffer[offset * 3 + 2] = buffer[offset * 4];
445         }
446     }
447
448     writeBitmap(fileToSave, rgbbuffer, WINDOW_WIDTH, WINDOW_HEIGHT);
449     free(buffer);
450     free(rgbbuffer);
451 }
452