00bd2a4e8f316fb2854cb593721943eeada4553c
[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_nativeDisplay(0)
51 , m_nativeWindow(0)
52 , m_shaderCreatorFunc(shaderProgram)
53 , m_eglConfig(0)
54 , m_eglContext(0)
55 , m_eglSurface(0)
56 , m_eglDisplay(0)
57 , m_vbo(0)
58 , m_displayWidth(0)
59 , m_displayHeight(0)
60 , m_blendingStatus(false)
61 , m_defaultShader(0)
62 , m_defaultShaderNoUniformAlpha(0)
63 , m_currentLayer(0)
64 #ifdef DRAW_LAYER_DEBUG
65 , m_layerShader(0)
66 #endif
67 {
68     LOG_DEBUG("GLESGraphicsystem", "creating GLESGraphicsystem");
69 }
70
71 void GLESGraphicsystem::activateGraphicContext()
72 {
73     eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
74 }
75
76 void GLESGraphicsystem::releaseGraphicContext() 
77 {
78     eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
79 }
80
81 bool GLESGraphicsystem::init(EGLNativeDisplayType display, EGLNativeWindowType NativeWindow)
82 {
83     m_nativeDisplay = display;
84     m_nativeWindow = NativeWindow;
85
86     EGLint iMajorVersion, iMinorVersion;
87     LOG_DEBUG("GLESGraphicsystem", "Getting EGL Display with native display " << m_nativeDisplay);
88     m_eglDisplay = eglGetDisplay(m_nativeDisplay);
89
90     if (m_eglDisplay == EGL_NO_DISPLAY){
91         LOG_ERROR("GLESGraphicsystem", "failed to Get EGL Display");
92         return false;
93     }
94
95     LOG_DEBUG("GLESGraphicsystem", "Initialising EGL");
96     if (!eglInitialize(m_eglDisplay, &iMajorVersion, &iMinorVersion))
97     {
98         LOG_ERROR("GLESGraphicsystem", "Initialising EGL failed");
99         return false;
100     }
101
102     LOG_DEBUG("GLESGraphicsystem", "Binding GLES API");
103     eglBindAPI(EGL_OPENGL_ES_API);
104
105     EGLint pi32ConfigAttribs[] = {
106             EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE,
107             EGL_OPENGL_ES2_BIT,
108             EGL_RED_SIZE,
109             8,
110             EGL_ALPHA_SIZE,
111             8,
112             EGL_NONE
113     };
114
115     LOG_DEBUG("GLESGraphicsystem", "EGLChooseConfig");
116     int iConfigs;
117     if (!eglChooseConfig(m_eglDisplay, pi32ConfigAttribs, &m_eglConfig, 1, &iConfigs) || (iConfigs != 1))
118     {
119         LOG_DEBUG("GLESGraphicsystem", "Error: eglChooseConfig() failed.");
120         return false;
121     }
122     EGLint id = 0;
123     eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_CONFIG_ID, &id);
124
125     EGLint windowsAttr[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
126
127     LOG_DEBUG("GLESGraphicsystem", "Config chosen:" << id);
128     LOG_DEBUG("GLESGraphicsystem", "Create Window surface");
129
130     m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_nativeWindow, windowsAttr);
131     if (!m_eglSurface)
132     {
133         EGLenum status = eglGetError();
134         LOG_ERROR("GLESGraphicsystem", "Window Surface creation failed with EGL Error Code: "<< status);
135         return false;
136     }
137     LOG_DEBUG("GLESGraphicsystem", "Window Surface creation successfull");
138
139     EGLint contextAttrs[] = {
140             EGL_CONTEXT_CLIENT_VERSION,
141             2,
142             EGL_NONE
143     };
144
145     m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttrs);
146     if (!m_eglContext)
147     {
148         LOG_ERROR("GLESGraphicsystem","EGL couldn't create context\n");
149         return false;
150     }
151     LOG_INFO("GLESGraphicsystem", "EGL make current ...");
152     // Make the context and surface current for rendering
153     eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
154     LOG_INFO("GLESGraphicsystem", "made current");
155
156     eglSwapInterval(m_eglDisplay, 1);
157
158     if (!initOpenGLES(m_windowWidth, m_windowHeight))
159     {
160         return false;
161     }
162     return true;
163 }
164
165 void GLESGraphicsystem::clearBackground()
166 {
167     glClear(GL_COLOR_BUFFER_BIT);
168 }
169
170 void GLESGraphicsystem::swapBuffers()
171 {
172     eglSwapBuffers(m_eglDisplay, m_eglSurface);
173 }
174
175 void GLESGraphicsystem::beginLayer(Layer* currentLayer)
176 {
177     //LOG_DEBUG("GLESGraphicsystem", "Beginning to draw layer: " << currentLayer->getID());
178     m_currentLayer = currentLayer;
179     // TODO layer destination / source
180 }
181
182 void GLESGraphicsystem::checkRenderLayer()
183 {
184     SurfaceList surfaces = m_currentLayer->getAllSurfaces();
185
186     m_currentLayer->damaged = false;
187
188     if (!(m_baseWindowSystem->m_damaged && m_currentLayer->getLayerType() != Hardware))
189     {
190         if (m_currentLayer->renderPropertyChanged)
191         {
192             m_currentLayer->damaged = true;
193         }
194         else if ((m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0)
195         {
196             for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
197             {
198                 if ((*currentS)->renderPropertyChanged)
199                 {
200                     m_currentLayer->damaged = true;
201                     break;
202                 }
203                 else if ((*currentS)->hasNativeContent() && (*currentS)->damaged && (*currentS)->visibility && (*currentS)->opacity>0.0f)
204                 {
205                     m_currentLayer->damaged = true;
206                     break;
207                 }
208             }
209         }
210
211         // Preseve m_currentLayer->damaged for HW layers so that they can be updated independently
212         if (m_currentLayer->damaged && m_currentLayer->getLayerType() != Hardware)
213         {
214             m_baseWindowSystem->m_damaged = true;
215             m_currentLayer->damaged = false;
216         }
217     }
218
219     for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
220     {
221         (*currentS)->damaged = false;
222         (*currentS)->renderPropertyChanged = false;
223     }
224
225     m_currentLayer->renderPropertyChanged = false;
226 }
227
228 void GLESGraphicsystem::renderSWLayer()
229 {
230     if ( (m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0 )
231     {
232         SurfaceList surfaces = m_currentLayer->getAllSurfaces();
233         for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
234         {
235             if ((*currentS)->hasNativeContent() && (*currentS)->visibility && (*currentS)->opacity>0.0f)
236             {
237                 Surface* currentSurface = (Surface*)*currentS;
238                 renderSurface(currentSurface);
239             }
240         }
241     }
242 }
243
244 void GLESGraphicsystem::endLayer()
245 {
246     //LOG_DEBUG("GLESGraphicsystem", "Done with rendering layer: " << m_currentLayer->getID());
247     m_currentLayer = NULL;
248 }
249
250 //this is a particularly simple function currently, but it will likely be expanded as more shaders and effects are implemented.
251 Shader *GLESGraphicsystem::pickOptimizedShader(Shader* currentShader, const ShaderProgram::CommonUniforms& curUniforms)
252 {
253     Shader * retShader = currentShader;
254
255     if (currentShader == m_defaultShader && curUniforms.opacity == 1.0f)
256     {
257       //no need for multiply in shader, just use texture
258       retShader = m_defaultShaderNoUniformAlpha;
259     }
260
261     return retShader;
262
263 }
264
265 void GLESGraphicsystem::applyLayerMatrix(IlmMatrix& matrix)
266 {
267     IlmMatrixRotateZ(matrix, m_currentLayer->getOrientation() * 90.0f);
268 }
269
270 void GLESGraphicsystem::renderSurface(Surface* surface)
271 {
272 //  LOG_DEBUG("GLESGraphicsystem", "renderSurface " << surface->getID());
273     GLenum glErrorCode = GL_NO_ERROR;
274     // check if surface is cropped completely, if so then skip rendering
275     if (ViewportTransform::isFullyCropped(surface->getDestinationRegion(), m_currentLayer->getSourceRegion() ) )
276         return; // skip rendering of this surface, because it is cropped by layer source region
277
278     GLint index = 0;
279     IlmMatrix layerMatrix;
280     IlmMatrixIdentity(layerMatrix);
281
282     ShaderProgram::CommonUniforms uniforms;
283 #ifdef DRAW_LAYER_DEBUG
284     ShaderProgram::CommonUniforms layeruniforms;
285 #endif
286     Shader* layerShader = m_currentLayer->getShader();
287     if (!layerShader)
288     {
289         // use default shader if no custom shader is assigned to this layer
290         layerShader = m_defaultShader;
291     }
292     Shader* shader = (surface)->getShader();
293     if (!shader)
294     {
295         // use layer shader if no custom shader is assigned to this surface
296         shader = layerShader;
297     }
298
299     const FloatRectangle layerSourceRegion = m_currentLayer->getSourceRegion();
300     const FloatRectangle layerDestinationRegion = m_currentLayer->getDestinationRegion();
301
302     FloatRectangle targetSurfaceSource = surface->getSourceRegion();
303     FloatRectangle targetSurfaceDestination = surface->getDestinationRegion();
304
305     ViewportTransform::applyLayerSource(layerSourceRegion, targetSurfaceSource, targetSurfaceDestination);
306     ViewportTransform::applyLayerDestination(layerDestinationRegion, layerSourceRegion, targetSurfaceDestination);
307     float textureCoordinates[4];
308     ViewportTransform::transformRectangleToTextureCoordinates(targetSurfaceSource, surface->OriginalSourceWidth, surface->OriginalSourceHeight, textureCoordinates);
309
310     glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
311     applyLayerMatrix(layerMatrix);
312     // update all common uniforms, scale values to display size
313     // offsets are generated w.r.t lower left corner (following GL conventions)
314     uniforms.x = targetSurfaceDestination.x / m_displayWidth;
315     uniforms.y = 1.0f - (targetSurfaceDestination.y + targetSurfaceDestination.height) / m_displayHeight;;
316     uniforms.width = targetSurfaceDestination.width / m_displayWidth;
317     uniforms.height = targetSurfaceDestination.height / m_displayHeight;
318     uniforms.opacity = (surface)->getOpacity() * m_currentLayer->getOpacity();
319     uniforms.texRange[0] = (textureCoordinates[2]-textureCoordinates[0]);
320     uniforms.texRange[1] = (textureCoordinates[3]-textureCoordinates[1]);
321     uniforms.texOffset[0] = textureCoordinates[0];
322     uniforms.texOffset[1] = textureCoordinates[1];
323     uniforms.texUnit = 0;
324     uniforms.matrix = &layerMatrix.f[0];
325
326
327     //We only know about specific Shaders, only do this if we start with the defaultShader
328     if (shader == m_defaultShader && uniforms.opacity == 1.0f)
329     {
330         if(!PixelFormatHasAlpha((surface)->getPixelFormat()))
331         {
332             //disable alpha blend completely
333             glDisable (GL_BLEND);
334         }
335         else
336         {
337             //make sure alpha blend is enabled
338             glEnable (GL_BLEND);
339         }
340     }
341     else
342     {
343         //make sure alpha blend is enabled
344         glEnable (GL_BLEND);
345     }
346
347     shader = pickOptimizedShader(shader, uniforms);
348
349
350 #ifdef DRAW_LAYER_DEBUG
351     layeruniforms.x = (float) layerDestinationRegion.x / m_displayWidth;
352     layeruniforms.y = (float) layerDestinationRegion.y / m_displayHeight;
353     layeruniforms.width = (float)layerDestinationRegion.width / m_displayWidth;
354     layeruniforms.height = (float)layerDestinationRegion.height / m_displayHeight;
355     layeruniforms.opacity = m_currentLayer->getOpacity();
356     layeruniforms.matrix = &layerMatrix.f[0];
357     m_layerShader->use();
358     m_layerShader->loadCommonUniforms(layeruniforms);
359     m_layerShader->loadUniforms();
360
361     glDrawArrays(GL_TRIANGLES, 0, 6);
362 #endif
363     shader->use();
364
365     /* load common uniforms */
366     shader->loadCommonUniforms(uniforms);
367
368     /* update all custom defined uniforms */
369     shader->loadUniforms();
370     /* Bind texture and set section */
371     glActiveTexture(GL_TEXTURE0);
372     if (false == m_binder->bindSurfaceTexture(surface))
373     {
374         LOG_WARNING("GLESGraphicsystem", "Surface not successfully bind " << surface->getID());
375         return;
376     }
377
378     /* rotated positions are saved sequentially in vbo
379      offset in multiples of 12 decide rotation */
380     /* Draw two triangles */
381     int orientation = (surface)->getOrientation();
382     orientation %= 4;
383     index = orientation * 12;
384     surface->frameCounter++;
385     surface->drawCounter++;
386     glDrawArrays(GL_TRIANGLES, index, 6);
387
388     glBindBuffer(GL_ARRAY_BUFFER, 0);
389     m_binder->unbindSurfaceTexture(surface);
390     glErrorCode = glGetError();
391     if ( GL_NO_ERROR != glErrorCode )
392     {
393         LOG_ERROR("GLESGraphicsystem", "GL Error occured :" << glErrorCode );
394     };
395 }
396
397 bool GLESGraphicsystem::initOpenGLES(EGLint displayWidth, EGLint displayHeight)
398 {
399     LOG_DEBUG("GLESGraphicsystem", "initEGL");
400     bool result = true;
401     ShaderProgramFactory::setCreatorFunc(m_shaderCreatorFunc);
402     m_defaultShader = Shader::createShader("default", "default");
403     m_defaultShaderNoUniformAlpha = Shader::createShader("default", "default_no_uniform_alpha");
404
405 #ifdef DRAW_LAYER_DEBUG
406     m_layerShader = Shader::createShader("/usr/lib/layermanager/renderer/renderer_layer.glslv", "/usr/lib/layermanager/renderer/renderer_layer.glslf");
407     if (m_layerShader==0)
408     {
409         m_layerShader = Shader::createShader("/usr/local/lib/layermanager/renderer/renderer_layer.glslv", "/usr/local/lib/layermanager/renderer/renderer_layer.glslf");
410     }
411 #endif
412     if (
413       !m_defaultShader || !m_defaultShaderNoUniformAlpha
414 #ifdef DRAW_LAYER_DEBUG
415     || !m_layerShader
416 #endif
417     )
418     {
419         LOG_ERROR("GLESGraphicsystem", "Failed to create and link default shader program");
420         delete m_defaultShader;
421         result = false;
422     }
423     else
424     {
425         LOG_INFO("GLESGraphicsystem", "Default Shader successfully applied");
426         glGenBuffers(1, &m_vbo);
427         glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
428         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
429         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
430         glEnableVertexAttribArray(0);
431         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*) (sizeof(float) * 12));
432         glEnableVertexAttribArray(1);
433
434         glEnable(GL_BLEND);
435         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
436         m_blendingStatus = true;
437         glClearColor(0.0, 0.0, 0.0, 0.0);
438         resize(displayWidth, displayHeight);
439     }
440     return result;
441 }
442
443 void GLESGraphicsystem::resize(EGLint displayWidth, EGLint displayHeight)
444 {
445     m_displayWidth = displayWidth;
446     m_displayHeight = displayHeight;
447     glViewport(0, 0, m_displayWidth, m_displayHeight);
448 }
449
450 void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
451 {
452     // clear error if any
453     int error = glGetError();
454     LOG_DEBUG("GLESGraphicSystem","taking screenshot and saving it to:" << fileToSave);
455
456     LOG_DEBUG("GLESGraphicSystem","Screenshot: " << m_displayWidth << " * " << m_displayHeight);
457     char *buffer = (char *) malloc( m_displayWidth * m_displayHeight * 4 * sizeof(char));
458     glReadPixels(0, 0, m_displayWidth, m_displayHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
459     error = glGetError();
460     if (error != GL_NO_ERROR)
461     {
462         LOG_DEBUG("GLESGraphicSystem","error reading pixels for screenshot: " << error);
463     }
464     // convert to RGB for bitmap
465     int pixelcount = m_displayHeight * m_displayWidth;
466     char *rgbbuffer = (char *) malloc(pixelcount * 3 * sizeof(char));
467     for (int row = 0; row < m_displayHeight; row++)
468     {
469         for (int col = 0; col < m_displayWidth; col++)
470         {
471             int offset = row * m_displayWidth + col;
472             rgbbuffer[offset * 3] = buffer[offset * 4 + 2];
473             rgbbuffer[offset * 3 + 1] = buffer[offset * 4 + 1];
474             rgbbuffer[offset * 3 + 2] = buffer[offset * 4];
475         }
476     }
477
478     writeBitmap(fileToSave, rgbbuffer, m_displayWidth, m_displayHeight);
479     free(buffer);
480     free(rgbbuffer);
481 }
482