Compilation fix for DRAW_LAYER_DEBUG mode
[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
258     Rectangle dest = (surface)->getDestinationRegion();
259     Rectangle src = (surface)->getSourceRegion();
260
261     float surfaceXOfScreen = (float) dest.x / (float) layerdest.width + (float) layerdest.x / m_displayWidth;
262     float surfaceYOfScreen = (float) dest.y / (float) layerdest.height + (float) layerdest.y / m_displayHeight;
263     float surfaceWidthOfScreen = ((float) dest.width / m_displayWidth) * scalex;
264     float surfaceHeightOfScreen = ((float) dest.height / m_displayHeight) * scaley;
265
266     float sourceViewportWidthPercent = (float) src.width / (surface)->OriginalSourceWidth;
267     float sourceViewportHeightpercent = (float) src.height / (surface)->OriginalSourceHeight;
268     float sourceViewportXPercent = (float) src.x / (surface)->OriginalSourceWidth;
269     float sourceViewportYPercent = (float) src.y / (surface)->OriginalSourceHeight;
270
271     glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
272     IlmMatrixRotateZ(layerMatrix, m_currentLayer->getOrientation() * 90.0f);
273     /* update all common uniforms */
274     uniforms.x = surfaceXOfScreen;
275     uniforms.y = surfaceYOfScreen;
276     uniforms.width = surfaceWidthOfScreen;
277     uniforms.height = surfaceHeightOfScreen;
278     uniforms.opacity = (surface)->getOpacity() * m_currentLayer->getOpacity();
279     uniforms.texRange[0] = sourceViewportWidthPercent;
280     uniforms.texRange[1] = sourceViewportHeightpercent;
281     uniforms.texOffset[0] = sourceViewportXPercent;
282     uniforms.texOffset[1] = -sourceViewportYPercent;
283     uniforms.texUnit = 0;
284     uniforms.matrix = &layerMatrix.f[0];
285
286     //We only know about specific Shaders, only do this if we start with the defaultShader
287     if (shader == m_defaultShader && uniforms.opacity == 1.0f)
288     {
289         if(!PixelFormatHasAlpha((surface)->getPixelFormat()))
290         {
291             //disable alpha blend completely
292             glDisable (GL_BLEND);
293         }
294         else
295         {
296             //make sure alpha blend is enabled
297             glEnable (GL_BLEND);
298         }
299     }
300     else
301     {
302         //make sure alpha blend is enabled
303         glEnable (GL_BLEND);
304     }
305
306     shader = pickOptimizedShader(shader, uniforms);
307
308
309 #ifdef DRAW_LAYER_DEBUG
310     layeruniforms.x = (float) layerdest.x / m_displayWidth;
311     layeruniforms.y = (float) layerdest.y / m_displayHeight;
312     layeruniforms.width = (float)layerdest.width / m_displayWidth;
313     layeruniforms.height = (float)layerdest.height / m_displayHeight;
314     layeruniforms.opacity = m_currentLayer->getOpacity();
315     layeruniforms.matrix = &layerMatrix.f[0];
316     m_layerShader->use();
317     m_layerShader->loadCommonUniforms(layeruniforms);
318     m_layerShader->loadUniforms();
319
320     glDrawArrays(GL_TRIANGLES, 0, 6);
321 #endif
322     shader->use();
323
324     /* load common uniforms */
325     shader->loadCommonUniforms(uniforms);
326
327     /* update all custom defined uniforms */
328     shader->loadUniforms();
329     /* Bind texture and set section */
330     glActiveTexture(GL_TEXTURE0);
331     if (false == m_binder->bindSurfaceTexture(surface)) 
332     {   
333         /* skip render surface if not bind successfully */        
334         return;
335     }
336
337     /* rotated positions are saved sequentially in vbo
338      offset in multiples of 12 decide rotation */
339     /* Draw two triangles */
340     int orientation = (surface)->getOrientation();
341     orientation %= 4;
342     index = orientation * 12;
343
344     glDrawArrays(GL_TRIANGLES, index, 6);
345
346     glBindBuffer(GL_ARRAY_BUFFER, NULL);
347     glGetError(); // TODO
348 }
349
350 bool GLESGraphicsystem::initOpenGLES(EGLint displayWidth, EGLint displayHeight)
351 {
352     LOG_DEBUG("GLESGraphicsystem", "initEGL");
353     bool result = true;
354     ShaderProgramFactory::setCreatorFunc(m_shaderCreatorFunc);
355     m_defaultShader = Shader::createShader("default", "default");
356     m_defaultShaderNoUniformAlpha = Shader::createShader("default", "default_no_uniform_alpha");
357
358 #ifdef DRAW_LAYER_DEBUG
359     m_layerShader = Shader::createShader("/usr/lib/layermanager/renderer/renderer_layer.glslv", "/usr/lib/layermanager/renderer/renderer_layer.glslf");
360     if (m_layerShader==0)
361     {
362         m_layerShader = Shader::createShader("/usr/local/lib/layermanager/renderer/renderer_layer.glslv", "/usr/local/lib/layermanager/renderer/renderer_layer.glslf");
363     }
364 #endif
365     if (
366       !m_defaultShader || !m_defaultShaderNoUniformAlpha
367 #ifdef DRAW_LAYER_DEBUG
368     || !m_layerShader
369 #endif
370     )
371     {
372         LOG_ERROR("GLESGraphicsystem", "Failed to create and link default shader program");
373         delete m_defaultShader;
374         result = false;
375     }
376     else
377     {
378         LOG_INFO("GLESGraphicsystem", "Default Shader successfully applied");
379         glGenBuffers(1, &m_vbo);
380         glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
381         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
382         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
383         glEnableVertexAttribArray(0);
384         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*) (sizeof(float) * 12));
385         glEnableVertexAttribArray(1);
386
387         glEnable(GL_BLEND);
388         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
389         m_blendingStatus = true;
390         glClearColor(0.0, 0.0, 0.0, 1.0);
391         resize(displayWidth, displayHeight);
392     }
393     return result;
394 }
395
396 void GLESGraphicsystem::resize(EGLint displayWidth, EGLint displayHeight)
397 {
398     m_displayWidth = displayWidth;
399     m_displayHeight = displayHeight;
400     glViewport(0, 0, m_displayWidth, m_displayHeight);
401 }
402
403 void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
404 {
405     // clear error if any
406     int error = glGetError();
407     LOG_DEBUG("BaseGraphicSystem","taking screenshot and saving it to:" << fileToSave);
408
409     GLint viewport[4];
410     glGetIntegerv(GL_VIEWPORT, viewport); // x,y,width,height
411     error = glGetError();
412     if (error != GL_NO_ERROR)
413     {
414         LOG_DEBUG("BaseGraphicSystem","error getting dimensions");
415     }
416     int WINDOW_WIDTH = viewport[2];
417     int WINDOW_HEIGHT = viewport[3];
418     LOG_DEBUG("BaseGraphicSystem","Screenshot: " << WINDOW_WIDTH << " * " << WINDOW_HEIGHT);
419     char *buffer = (char *) malloc( WINDOW_WIDTH * WINDOW_HEIGHT * 4 * sizeof(char));
420     glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
421     error = glGetError();
422     if (error != GL_NO_ERROR)
423     {
424         LOG_DEBUG("BaseGraphicSystem","error reading pixels for screenshot: " << error);
425     }
426     // convert to RGB for bitmap
427     int pixelcount = WINDOW_WIDTH * WINDOW_HEIGHT;
428     char *rgbbuffer = (char *) malloc(pixelcount * 3 * sizeof(char));
429     for (int row = 0; row < WINDOW_HEIGHT; row++)
430     {
431         for (int col = 0; col < WINDOW_WIDTH; col++)
432         {
433             int offset = row * WINDOW_WIDTH + col;
434             rgbbuffer[offset * 3] = buffer[offset * 4 + 2];
435             rgbbuffer[offset * 3 + 1] = buffer[offset * 4 + 1];
436             rgbbuffer[offset * 3 + 2] = buffer[offset * 4];
437         }
438     }
439
440     writeBitmap(fileToSave, rgbbuffer, WINDOW_WIDTH, WINDOW_HEIGHT);
441     free(buffer);
442     free(rgbbuffer);
443 }
444