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"
26 #include "Transformation/ViewportTransform.h"
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,
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,
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,
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,
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,
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,
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,
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
47 GLESGraphicsystem::GLESGraphicsystem(int windowWidth, int windowHeight, PfnShaderProgramCreator shaderProgram)
48 : m_windowWidth(windowWidth)
49 , m_windowHeight(windowHeight)
52 , m_shaderCreatorFunc(shaderProgram)
60 , m_blendingStatus(false)
62 , m_defaultShaderNoUniformAlpha(0)
64 #ifdef DRAW_LAYER_DEBUG
68 LOG_DEBUG("GLESGraphicsystem", "creating GLESGraphicsystem");
71 void GLESGraphicsystem::activateGraphicContext()
73 eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
76 void GLESGraphicsystem::releaseGraphicContext()
78 eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
81 bool GLESGraphicsystem::init(EGLNativeDisplayType display, EGLNativeWindowType NativeWindow)
83 m_nativeDisplay = display;
84 m_nativeWindow = NativeWindow;
86 EGLint iMajorVersion, iMinorVersion;
87 LOG_DEBUG("GLESGraphicsystem", "Getting EGL Display with native display " << m_nativeDisplay);
88 m_eglDisplay = eglGetDisplay(m_nativeDisplay);
90 if (m_eglDisplay == EGL_NO_DISPLAY){
91 LOG_ERROR("GLESGraphicsystem", "failed to Get EGL Display");
95 LOG_DEBUG("GLESGraphicsystem", "Initialising EGL");
96 if (!eglInitialize(m_eglDisplay, &iMajorVersion, &iMinorVersion))
98 LOG_ERROR("GLESGraphicsystem", "Initialising EGL failed");
102 LOG_DEBUG("GLESGraphicsystem", "Binding GLES API");
103 eglBindAPI(EGL_OPENGL_ES_API);
105 EGLint pi32ConfigAttribs[] = {
106 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE,
115 LOG_DEBUG("GLESGraphicsystem", "EGLChooseConfig");
117 if (!eglChooseConfig(m_eglDisplay, pi32ConfigAttribs, &m_eglConfig, 1, &iConfigs) || (iConfigs != 1))
119 LOG_DEBUG("GLESGraphicsystem", "Error: eglChooseConfig() failed.");
123 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_CONFIG_ID, &id);
125 EGLint windowsAttr[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
127 LOG_DEBUG("GLESGraphicsystem", "Config chosen:" << id);
128 LOG_DEBUG("GLESGraphicsystem", "Create Window surface");
130 m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_nativeWindow, windowsAttr);
133 EGLenum status = eglGetError();
134 LOG_ERROR("GLESGraphicsystem", "Window Surface creation failed with EGL Error Code: "<< status);
137 LOG_DEBUG("GLESGraphicsystem", "Window Surface creation successfull");
139 EGLint contextAttrs[] = {
140 EGL_CONTEXT_CLIENT_VERSION,
145 m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttrs);
148 LOG_ERROR("GLESGraphicsystem","EGL couldn't create context\n");
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");
156 eglSwapInterval(m_eglDisplay, 1);
158 if (!initOpenGLES(m_windowWidth, m_windowHeight))
165 void GLESGraphicsystem::clearBackground()
167 glClear(GL_COLOR_BUFFER_BIT);
170 void GLESGraphicsystem::swapBuffers()
172 eglSwapBuffers(m_eglDisplay, m_eglSurface);
175 void GLESGraphicsystem::beginLayer(Layer* currentLayer)
177 //LOG_DEBUG("GLESGraphicsystem", "Beginning to draw layer: " << currentLayer->getID());
178 m_currentLayer = currentLayer;
179 // TODO layer destination / source
182 void GLESGraphicsystem::checkRenderLayer()
184 SurfaceList surfaces = m_currentLayer->getAllSurfaces();
186 m_currentLayer->damaged = false;
188 if (!(m_baseWindowSystem->m_damaged && m_currentLayer->getLayerType() != Hardware))
190 if (m_currentLayer->renderPropertyChanged)
192 m_currentLayer->damaged = true;
194 else if ((m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0)
196 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
198 if ((*currentS)->renderPropertyChanged)
200 m_currentLayer->damaged = true;
203 else if ((*currentS)->hasNativeContent() && (*currentS)->damaged && (*currentS)->visibility && (*currentS)->opacity>0.0f)
205 m_currentLayer->damaged = true;
211 // Preseve m_currentLayer->damaged for HW layers so that they can be updated independently
212 if (m_currentLayer->damaged && m_currentLayer->getLayerType() != Hardware)
214 m_baseWindowSystem->m_damaged = true;
215 m_currentLayer->damaged = false;
219 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
221 (*currentS)->damaged = false;
222 (*currentS)->renderPropertyChanged = false;
225 m_currentLayer->renderPropertyChanged = false;
228 void GLESGraphicsystem::renderSWLayer()
230 if ( (m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0 )
232 SurfaceList surfaces = m_currentLayer->getAllSurfaces();
233 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
235 if ((*currentS)->hasNativeContent() && (*currentS)->visibility && (*currentS)->opacity>0.0f)
237 Surface* currentSurface = (Surface*)*currentS;
238 renderSurface(currentSurface);
244 void GLESGraphicsystem::endLayer()
246 //LOG_DEBUG("GLESGraphicsystem", "Done with rendering layer: " << m_currentLayer->getID());
247 m_currentLayer = NULL;
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)
253 Shader * retShader = currentShader;
255 if (currentShader == m_defaultShader && curUniforms.opacity == 1.0f)
257 //no need for multiply in shader, just use texture
258 retShader = m_defaultShaderNoUniformAlpha;
265 void GLESGraphicsystem::applyLayerMatrix(IlmMatrix& matrix)
267 IlmMatrixRotateZ(matrix, m_currentLayer->getOrientation() * 90.0f);
270 void GLESGraphicsystem::renderSurface(Surface* surface)
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
279 IlmMatrix layerMatrix;
280 IlmMatrixIdentity(layerMatrix);
282 ShaderProgram::CommonUniforms uniforms;
283 #ifdef DRAW_LAYER_DEBUG
284 ShaderProgram::CommonUniforms layeruniforms;
286 Shader* layerShader = m_currentLayer->getShader();
289 // use default shader if no custom shader is assigned to this layer
290 layerShader = m_defaultShader;
292 Shader* shader = (surface)->getShader();
295 // use layer shader if no custom shader is assigned to this surface
296 shader = layerShader;
299 const FloatRectangle layerSourceRegion = m_currentLayer->getSourceRegion();
300 const FloatRectangle layerDestinationRegion = m_currentLayer->getDestinationRegion();
302 FloatRectangle targetSurfaceSource = surface->getSourceRegion();
303 FloatRectangle targetSurfaceDestination = surface->getDestinationRegion();
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);
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];
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)
330 if(!PixelFormatHasAlpha((surface)->getPixelFormat()))
332 //disable alpha blend completely
333 glDisable (GL_BLEND);
337 //make sure alpha blend is enabled
343 //make sure alpha blend is enabled
347 shader = pickOptimizedShader(shader, uniforms);
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();
361 glDrawArrays(GL_TRIANGLES, 0, 6);
365 /* load common uniforms */
366 shader->loadCommonUniforms(uniforms);
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))
374 LOG_WARNING("GLESGraphicsystem", "Surface not successfully bind " << surface->getID());
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();
383 index = orientation * 12;
384 surface->frameCounter++;
385 surface->drawCounter++;
386 glDrawArrays(GL_TRIANGLES, index, 6);
388 glBindBuffer(GL_ARRAY_BUFFER, 0);
389 m_binder->unbindSurfaceTexture(surface);
390 glErrorCode = glGetError();
391 if ( GL_NO_ERROR != glErrorCode )
393 LOG_ERROR("GLESGraphicsystem", "GL Error occured :" << glErrorCode );
397 bool GLESGraphicsystem::initOpenGLES(EGLint displayWidth, EGLint displayHeight)
399 LOG_DEBUG("GLESGraphicsystem", "initEGL");
401 ShaderProgramFactory::setCreatorFunc(m_shaderCreatorFunc);
402 m_defaultShader = Shader::createShader("default", "default");
403 m_defaultShaderNoUniformAlpha = Shader::createShader("default", "default_no_uniform_alpha");
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)
409 m_layerShader = Shader::createShader("/usr/local/lib/layermanager/renderer/renderer_layer.glslv", "/usr/local/lib/layermanager/renderer/renderer_layer.glslf");
413 !m_defaultShader || !m_defaultShaderNoUniformAlpha
414 #ifdef DRAW_LAYER_DEBUG
419 LOG_ERROR("GLESGraphicsystem", "Failed to create and link default shader program");
420 delete m_defaultShader;
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);
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);
443 void GLESGraphicsystem::resize(EGLint displayWidth, EGLint displayHeight)
445 m_displayWidth = displayWidth;
446 m_displayHeight = displayHeight;
447 glViewport(0, 0, m_displayWidth, m_displayHeight);
450 void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
452 // clear error if any
453 int error = glGetError();
454 LOG_DEBUG("GLESGraphicSystem","taking screenshot and saving it to:" << fileToSave);
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)
462 LOG_DEBUG("GLESGraphicSystem","error reading pixels for screenshot: " << error);
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++)
469 for (int col = 0; col < m_displayWidth; col++)
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];
478 writeBitmap(fileToSave, rgbbuffer, m_displayWidth, m_displayHeight);