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