1 /***************************************************************************
3 * Copyright 2010,2011 BMW Car IT GmbH
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 ****************************************************************************/
20 #include "GraphicSystems/GLESGraphicSystem.h"
21 #include "IlmMatrix.h"
24 #include "GLES2/gl2.h"
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,
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,
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,
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,
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,
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,
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,
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
46 GLESGraphicsystem::GLESGraphicsystem(int windowWidth, int windowHeight, PfnShaderProgramCreator shaderProgram)
47 : m_windowWidth(windowWidth)
48 , m_windowHeight(windowHeight)
49 , m_shaderCreatorFunc(shaderProgram)
51 LOG_DEBUG("GLESGraphicsystem", "creating GLESGraphicsystem");
54 bool GLESGraphicsystem::init(EGLNativeDisplayType display, EGLNativeWindowType NativeWindow)
56 m_nativeDisplay = display;
57 m_nativeWindow = NativeWindow;
59 EGLint iMajorVersion, iMinorVersion;
60 LOG_DEBUG("GLESGraphicsystem", "Getting EGL Display with native display " << m_nativeDisplay);
61 m_eglDisplay = eglGetDisplay(m_nativeDisplay);
63 LOG_DEBUG("GLESGraphicsystem", "Initialising EGL");
64 if (!eglInitialize(m_eglDisplay, &iMajorVersion, &iMinorVersion))
66 LOG_ERROR("GLESGraphicsystem", "Initialising EGL failed");
70 LOG_DEBUG("GLESGraphicsystem", "Binding GLES API");
71 eglBindAPI(EGL_OPENGL_ES_API);
73 EGLint pi32ConfigAttribs[] = {
74 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE,
83 LOG_DEBUG("GLESGraphicsystem", "EGLChooseConfig");
85 if (!eglChooseConfig(m_eglDisplay, pi32ConfigAttribs, &m_eglConfig, 1, &iConfigs) || (iConfigs != 1))
87 LOG_DEBUG("GLESGraphicsystem", "Error: eglChooseConfig() failed.");
91 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_CONFIG_ID, &id);
93 EGLint windowsAttr[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
95 LOG_DEBUG("GLESGraphicsystem", "Config chosen:" << id);
96 LOG_DEBUG("GLESGraphicsystem", "Create Window surface");
98 m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_nativeWindow, windowsAttr);
101 EGLenum status = eglGetError();
102 LOG_ERROR("GLESGraphicsystem", "Window Surface creation failed with EGL Error Code: "<< status);
105 LOG_DEBUG("GLESGraphicsystem", "Window Surface creation successfull");
107 EGLint contextAttrs[] = {
108 EGL_CONTEXT_CLIENT_VERSION,
113 m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttrs);
116 LOG_ERROR("GLESGraphicsystem","EGL couldn't create context\n");
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");
125 eglSwapInterval(m_eglDisplay, 1); // TODO: does not seem to work
127 if (!initOpenGLES(m_windowWidth, m_windowHeight))
134 void GLESGraphicsystem::clearBackground()
136 glClear(GL_COLOR_BUFFER_BIT);
139 void GLESGraphicsystem::swapBuffers()
141 eglSwapBuffers(m_eglDisplay, m_eglSurface);
144 void GLESGraphicsystem::beginLayer(Layer* currentLayer)
146 //LOG_DEBUG("GLESGraphicsystem", "Beginning to draw layer: " << currentLayer->getID());
147 m_currentLayer = currentLayer;
148 // TODO layer destination / source
151 void GLESGraphicsystem::checkRenderLayer()
153 SurfaceList surfaces = m_currentLayer->getAllSurfaces();
155 m_currentLayer->damaged = false;
157 if (!m_baseWindowSystem->m_damaged)
159 if (m_currentLayer->renderPropertyChanged)
161 m_currentLayer->damaged = true;
163 else if ((m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0)
165 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
167 if ((*currentS)->renderPropertyChanged)
169 m_currentLayer->damaged = true;
172 else if ((*currentS)->damaged && (*currentS)->visibility && (*currentS)->opacity>0.0f)
174 m_currentLayer->damaged = true;
181 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
183 (*currentS)->damaged = false;
184 (*currentS)->renderPropertyChanged = false;
187 m_currentLayer->renderPropertyChanged = false;
189 if (m_currentLayer->damaged)
191 m_baseWindowSystem->m_damaged = true;
195 void GLESGraphicsystem::renderLayer()
197 SurfaceList surfaces = m_currentLayer->getAllSurfaces();
198 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
200 if ((*currentS)->visibility && (*currentS)->opacity>0.0f)
202 Surface* currentSurface = (Surface*)*currentS;
203 renderSurface(currentSurface);
208 void GLESGraphicsystem::endLayer()
210 //LOG_DEBUG("GLESGraphicsystem", "Done with rendering layer: " << m_currentLayer->getID());
211 m_currentLayer = NULL;
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)
217 Shader * retShader = currentShader;
219 if (currentShader == m_defaultShader && curUniforms.opacity == 1.0f)
221 //no need for multiply in shader, just use texture
222 retShader = m_defaultShaderNoUniformAlpha;
229 void GLESGraphicsystem::renderSurface(Surface* surface)
231 // LOG_DEBUG("GLESGraphicsystem", "renderSurface " << surface->getID());
234 IlmMatrix layerMatrix;
235 IlmMatrixIdentity(layerMatrix);
236 Rectangle layerdest = (m_currentLayer)->getDestinationRegion();
237 Rectangle layersrc = (m_currentLayer)->getSourceRegion();
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;
245 Shader* layerShader = m_currentLayer->getShader();
248 // use default shader if no custom shader is assigned to this layer
249 layerShader = m_defaultShader;
251 Shader* shader = (surface)->getShader();
254 // use layer shader if no custom shader is assigned to this surface
255 shader = layerShader;
258 Rectangle dest = (surface)->getDestinationRegion();
259 Rectangle src = (surface)->getSourceRegion();
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;
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;
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];
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)
289 if(!PixelFormatHasAlpha((surface)->getPixelFormat()))
291 //disable alpha blend completely
292 glDisable (GL_BLEND);
296 //make sure alpha blend is enabled
302 //make sure alpha blend is enabled
306 shader = pickOptimizedShader(shader, uniforms);
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();
320 glDrawArrays(GL_TRIANGLES, 0, 6);
324 /* load common uniforms */
325 shader->loadCommonUniforms(uniforms);
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))
333 /* skip render surface if not bind successfully */
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();
342 index = orientation * 12;
344 glDrawArrays(GL_TRIANGLES, index, 6);
346 glBindBuffer(GL_ARRAY_BUFFER, NULL);
347 glGetError(); // TODO
350 bool GLESGraphicsystem::initOpenGLES(EGLint displayWidth, EGLint displayHeight)
352 LOG_DEBUG("GLESGraphicsystem", "initEGL");
354 ShaderProgramFactory::setCreatorFunc(m_shaderCreatorFunc);
355 m_defaultShader = Shader::createShader("default", "default");
356 m_defaultShaderNoUniformAlpha = Shader::createShader("default", "default_no_uniform_alpha");
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)
362 m_layerShader = Shader::createShader("/usr/local/lib/layermanager/renderer/renderer_layer.glslv", "/usr/local/lib/layermanager/renderer/renderer_layer.glslf");
366 !m_defaultShader || !m_defaultShaderNoUniformAlpha
367 #ifdef DRAW_LAYER_DEBUG
372 LOG_ERROR("GLESGraphicsystem", "Failed to create and link default shader program");
373 delete m_defaultShader;
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);
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);
396 void GLESGraphicsystem::resize(EGLint displayWidth, EGLint displayHeight)
398 m_displayWidth = displayWidth;
399 m_displayHeight = displayHeight;
400 glViewport(0, 0, m_displayWidth, m_displayHeight);
403 void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
405 // clear error if any
406 int error = glGetError();
407 LOG_DEBUG("BaseGraphicSystem","taking screenshot and saving it to:" << fileToSave);
410 glGetIntegerv(GL_VIEWPORT, viewport); // x,y,width,height
411 error = glGetError();
412 if (error != GL_NO_ERROR)
414 LOG_DEBUG("BaseGraphicSystem","error getting dimensions");
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)
424 LOG_DEBUG("BaseGraphicSystem","error reading pixels for screenshot: " << error);
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++)
431 for (int col = 0; col < WINDOW_WIDTH; col++)
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];
440 writeBitmap(fileToSave, rgbbuffer, WINDOW_WIDTH, WINDOW_HEIGHT);