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)
50 , m_shaderCreatorFunc(shaderProgram)
52 LOG_DEBUG("GLESGraphicsystem", "creating GLESGraphicsystem");
55 bool GLESGraphicsystem::init(EGLNativeDisplayType display, EGLNativeWindowType NativeWindow)
57 m_nativeDisplay = display;
58 m_nativeWindow = NativeWindow;
60 EGLint iMajorVersion, iMinorVersion;
61 LOG_DEBUG("GLESGraphicsystem", "Getting EGL Display with native display " << m_nativeDisplay);
62 m_eglDisplay = eglGetDisplay(m_nativeDisplay);
64 if (m_eglDisplay == EGL_NO_DISPLAY){
65 LOG_ERROR("GLESGraphicsystem", "failed to Get EGL Display");
69 LOG_DEBUG("GLESGraphicsystem", "Initialising EGL");
70 if (!eglInitialize(m_eglDisplay, &iMajorVersion, &iMinorVersion))
72 LOG_ERROR("GLESGraphicsystem", "Initialising EGL failed");
76 LOG_DEBUG("GLESGraphicsystem", "Binding GLES API");
77 eglBindAPI(EGL_OPENGL_ES_API);
79 EGLint pi32ConfigAttribs[] = {
80 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE,
89 LOG_DEBUG("GLESGraphicsystem", "EGLChooseConfig");
91 if (!eglChooseConfig(m_eglDisplay, pi32ConfigAttribs, &m_eglConfig, 1, &iConfigs) || (iConfigs != 1))
93 LOG_DEBUG("GLESGraphicsystem", "Error: eglChooseConfig() failed.");
97 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_CONFIG_ID, &id);
99 EGLint windowsAttr[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
101 LOG_DEBUG("GLESGraphicsystem", "Config chosen:" << id);
102 LOG_DEBUG("GLESGraphicsystem", "Create Window surface");
104 m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_nativeWindow, windowsAttr);
107 EGLenum status = eglGetError();
108 LOG_ERROR("GLESGraphicsystem", "Window Surface creation failed with EGL Error Code: "<< status);
111 LOG_DEBUG("GLESGraphicsystem", "Window Surface creation successfull");
113 EGLint contextAttrs[] = {
114 EGL_CONTEXT_CLIENT_VERSION,
119 m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttrs);
122 LOG_ERROR("GLESGraphicsystem","EGL couldn't create context\n");
125 LOG_INFO("GLESGraphicsystem", "EGL make current ...");
126 // Make the context and surface current for rendering
127 EGLBoolean eglStatus = false;
128 eglStatus = eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
129 LOG_INFO("GLESGraphicsystem", "made current");
131 eglSwapInterval(m_eglDisplay, 1); // TODO: does not seem to work
133 if (!initOpenGLES(m_windowWidth, m_windowHeight))
140 void GLESGraphicsystem::clearBackground()
142 glClear(GL_COLOR_BUFFER_BIT);
145 void GLESGraphicsystem::swapBuffers()
147 eglSwapBuffers(m_eglDisplay, m_eglSurface);
150 void GLESGraphicsystem::beginLayer(Layer* currentLayer)
152 //LOG_DEBUG("GLESGraphicsystem", "Beginning to draw layer: " << currentLayer->getID());
153 m_currentLayer = currentLayer;
154 // TODO layer destination / source
157 void GLESGraphicsystem::checkRenderLayer()
159 SurfaceList surfaces = m_currentLayer->getAllSurfaces();
161 m_currentLayer->damaged = false;
163 if (!m_baseWindowSystem->m_damaged)
165 if (m_currentLayer->renderPropertyChanged)
167 m_currentLayer->damaged = true;
169 else if ((m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0)
171 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
173 if ((*currentS)->renderPropertyChanged)
175 m_currentLayer->damaged = true;
178 else if ((*currentS)->damaged && (*currentS)->visibility && (*currentS)->opacity>0.0f)
180 m_currentLayer->damaged = true;
187 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
189 (*currentS)->damaged = false;
190 (*currentS)->renderPropertyChanged = false;
193 m_currentLayer->renderPropertyChanged = false;
195 if (m_currentLayer->damaged)
197 m_baseWindowSystem->m_damaged = true;
201 void GLESGraphicsystem::renderLayer()
203 if ( (m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0 )
205 SurfaceList surfaces = m_currentLayer->getAllSurfaces();
206 for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
208 if ((*currentS)->visibility && (*currentS)->opacity>0.0f)
210 Surface* currentSurface = (Surface*)*currentS;
211 renderSurface(currentSurface);
217 void GLESGraphicsystem::endLayer()
219 //LOG_DEBUG("GLESGraphicsystem", "Done with rendering layer: " << m_currentLayer->getID());
220 m_currentLayer = NULL;
223 //this is a particularly simple function currently, but it will likely be expanded as more shaders and effects are implemented.
224 Shader *GLESGraphicsystem::pickOptimizedShader(Shader* currentShader, const ShaderProgram::CommonUniforms curUniforms)
226 Shader * retShader = currentShader;
228 if (currentShader == m_defaultShader && curUniforms.opacity == 1.0f)
230 //no need for multiply in shader, just use texture
231 retShader = m_defaultShaderNoUniformAlpha;
238 void GLESGraphicsystem::renderSurface(Surface* surface)
240 // LOG_DEBUG("GLESGraphicsystem", "renderSurface " << surface->getID());
243 IlmMatrix layerMatrix;
244 IlmMatrixIdentity(layerMatrix);
246 ShaderProgram::CommonUniforms uniforms;
247 #ifdef DRAW_LAYER_DEBUG
248 ShaderProgram::CommonUniforms layeruniforms;
250 Shader* layerShader = m_currentLayer->getShader();
253 // use default shader if no custom shader is assigned to this layer
254 layerShader = m_defaultShader;
256 Shader* shader = (surface)->getShader();
259 // use layer shader if no custom shader is assigned to this surface
260 shader = layerShader;
262 const Rectangle& layerDestinationRegion = (m_currentLayer)->getDestinationRegion();
263 const Rectangle& layerSourceRegion = (m_currentLayer)->getSourceRegion();
265 // these variables contain the current calculated values of the surface
266 Rectangle targetSurfaceSource = surface->getSourceRegion();
267 Rectangle targetSurfaceDestination = surface->getDestinationRegion();
269 ViewportTransform::applyLayerSource(layerSourceRegion, targetSurfaceSource, targetSurfaceDestination);
270 ViewportTransform::applyLayerDestination(layerDestinationRegion, layerSourceRegion, targetSurfaceDestination);
271 float* textureCoordinates = new float[4];
272 ViewportTransform::transformRectangleToTextureCoordinates(targetSurfaceSource, surface->OriginalSourceWidth, surface->OriginalSourceHeight, textureCoordinates);
274 glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
275 IlmMatrixRotateZ(layerMatrix, m_currentLayer->getOrientation() * 90.0f);
276 // update all common uniforms, scale values to display size
277 uniforms.x = (float)targetSurfaceDestination.x / m_displayWidth;
278 uniforms.y = (float)targetSurfaceDestination.y / m_displayHeight;;
279 uniforms.width = (float)targetSurfaceDestination.width / m_displayWidth;
280 uniforms.height = (float)targetSurfaceDestination.height / m_displayHeight;
281 uniforms.opacity = (surface)->getOpacity() * m_currentLayer->getOpacity();
282 uniforms.texRange[0] = (textureCoordinates[1]-textureCoordinates[0]);
283 uniforms.texRange[1] = (textureCoordinates[3]-textureCoordinates[2]);
284 uniforms.texOffset[0] = textureCoordinates[0];
285 uniforms.texOffset[1] = -textureCoordinates[2];
286 uniforms.texUnit = 0;
287 uniforms.matrix = &layerMatrix.f[0];
290 //We only know about specific Shaders, only do this if we start with the defaultShader
291 if (shader == m_defaultShader && uniforms.opacity == 1.0f)
293 if(!PixelFormatHasAlpha((surface)->getPixelFormat()))
295 //disable alpha blend completely
296 glDisable (GL_BLEND);
300 //make sure alpha blend is enabled
306 //make sure alpha blend is enabled
310 shader = pickOptimizedShader(shader, uniforms);
313 #ifdef DRAW_LAYER_DEBUG
314 layeruniforms.x = (float) layerDestinationRegion.x / m_displayWidth;
315 layeruniforms.y = (float) layerDestinationRegion.y / m_displayHeight;
316 layeruniforms.width = (float)layerDestinationRegion.width / m_displayWidth;
317 layeruniforms.height = (float)layerDestinationRegion.height / m_displayHeight;
318 layeruniforms.opacity = m_currentLayer->getOpacity();
319 layeruniforms.matrix = &layerMatrix.f[0];
320 m_layerShader->use();
321 m_layerShader->loadCommonUniforms(layeruniforms);
322 m_layerShader->loadUniforms();
324 glDrawArrays(GL_TRIANGLES, 0, 6);
328 /* load common uniforms */
329 shader->loadCommonUniforms(uniforms);
331 /* update all custom defined uniforms */
332 shader->loadUniforms();
333 /* Bind texture and set section */
334 glActiveTexture(GL_TEXTURE0);
335 if (false == m_binder->bindSurfaceTexture(surface))
337 // LOG_DEBUG("GLESGraphicsystem", "renderSurface not successfully bind " << surface->getID());
340 // LOG_DEBUG("GLESGraphicsystem", "renderSurface " << surface->getID());
343 /* rotated positions are saved sequentially in vbo
344 offset in multiples of 12 decide rotation */
345 /* Draw two triangles */
346 int orientation = (surface)->getOrientation();
348 index = orientation * 12;
349 surface->frameCounter++;
350 glDrawArrays(GL_TRIANGLES, index, 6);
352 glBindBuffer(GL_ARRAY_BUFFER, 0);
353 glGetError(); // TODO
355 delete textureCoordinates;
358 bool GLESGraphicsystem::initOpenGLES(EGLint displayWidth, EGLint displayHeight)
360 LOG_DEBUG("GLESGraphicsystem", "initEGL");
362 ShaderProgramFactory::setCreatorFunc(m_shaderCreatorFunc);
363 m_defaultShader = Shader::createShader("default", "default");
364 m_defaultShaderNoUniformAlpha = Shader::createShader("default", "default_no_uniform_alpha");
366 #ifdef DRAW_LAYER_DEBUG
367 m_layerShader = Shader::createShader("/usr/lib/layermanager/renderer/renderer_layer.glslv", "/usr/lib/layermanager/renderer/renderer_layer.glslf");
368 if (m_layerShader==0)
370 m_layerShader = Shader::createShader("/usr/local/lib/layermanager/renderer/renderer_layer.glslv", "/usr/local/lib/layermanager/renderer/renderer_layer.glslf");
374 !m_defaultShader || !m_defaultShaderNoUniformAlpha
375 #ifdef DRAW_LAYER_DEBUG
380 LOG_ERROR("GLESGraphicsystem", "Failed to create and link default shader program");
381 delete m_defaultShader;
386 LOG_INFO("GLESGraphicsystem", "Default Shader successfully applied");
387 glGenBuffers(1, &m_vbo);
388 glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
389 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
390 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
391 glEnableVertexAttribArray(0);
392 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*) (sizeof(float) * 12));
393 glEnableVertexAttribArray(1);
396 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
397 m_blendingStatus = true;
398 glClearColor(0.0, 0.0, 0.0, 0.0);
399 resize(displayWidth, displayHeight);
404 void GLESGraphicsystem::resize(EGLint displayWidth, EGLint displayHeight)
406 m_displayWidth = displayWidth;
407 m_displayHeight = displayHeight;
408 glViewport(0, 0, m_displayWidth, m_displayHeight);
411 void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
413 // clear error if any
414 int error = glGetError();
415 LOG_DEBUG("BaseGraphicSystem","taking screenshot and saving it to:" << fileToSave);
418 glGetIntegerv(GL_VIEWPORT, viewport); // x,y,width,height
419 error = glGetError();
420 if (error != GL_NO_ERROR)
422 LOG_DEBUG("BaseGraphicSystem","error getting dimensions");
424 int WINDOW_WIDTH = viewport[2];
425 int WINDOW_HEIGHT = viewport[3];
426 LOG_DEBUG("BaseGraphicSystem","Screenshot: " << WINDOW_WIDTH << " * " << WINDOW_HEIGHT);
427 char *buffer = (char *) malloc( WINDOW_WIDTH * WINDOW_HEIGHT * 4 * sizeof(char));
428 glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
429 error = glGetError();
430 if (error != GL_NO_ERROR)
432 LOG_DEBUG("BaseGraphicSystem","error reading pixels for screenshot: " << error);
434 // convert to RGB for bitmap
435 int pixelcount = WINDOW_WIDTH * WINDOW_HEIGHT;
436 char *rgbbuffer = (char *) malloc(pixelcount * 3 * sizeof(char));
437 for (int row = 0; row < WINDOW_HEIGHT; row++)
439 for (int col = 0; col < WINDOW_WIDTH; col++)
441 int offset = row * WINDOW_WIDTH + col;
442 rgbbuffer[offset * 3] = buffer[offset * 4 + 2];
443 rgbbuffer[offset * 3 + 1] = buffer[offset * 4 + 1];
444 rgbbuffer[offset * 3 + 2] = buffer[offset * 4];
448 writeBitmap(fileToSave, rgbbuffer, WINDOW_WIDTH, WINDOW_HEIGHT);