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;
257 Rectangle dest = (surface)->getDestinationRegion();
258 Rectangle src = (surface)->getSourceRegion();
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;
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;
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];
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)
288 if(!PixelFormatHasAlpha((surface)->getPixelFormat()))
290 //disable alpha blend completely
291 glDisable (GL_BLEND);
295 //make sure alpha blend is enabled
301 //make sure alpha blend is enabled
305 shader = pickOptimizedShader(shader, uniforms);
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();
319 glDrawArrays(GL_TRIANGLES, 0, 6);
323 /* load common uniforms */
324 shader->loadCommonUniforms(uniforms);
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))
332 /* skip render surface if not bind successfully */
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();
341 index = orientation * 12;
343 glDrawArrays(GL_TRIANGLES, index, 6);
345 glBindBuffer(GL_ARRAY_BUFFER, NULL);
346 glGetError(); // TODO
349 bool GLESGraphicsystem::initOpenGLES(EGLint displayWidth, EGLint displayHeight)
351 LOG_DEBUG("GLESGraphicsystem", "initEGL");
353 ShaderProgramFactory::setCreatorFunc(m_shaderCreatorFunc);
354 m_defaultShader = Shader::createShader("default", "default");
355 m_defaultShaderNoUniformAlpha = Shader::createShader("default", "default_no_uniform_alpha");
357 #ifdef DRAW_LAYER_DEBUG
358 m_layerShader = Shader::createShader("/usr/lib/layermanager/renderer/renderer_layer.glslv", "/usr/lib/layermanager/renderer/renderer_layer.glslf");
361 !m_defaultShader || !m_defaultShaderNoUniformAlpha
362 #ifdef DRAW_LAYER_DEBUG
367 LOG_ERROR("GLESGraphicsystem", "Failed to create and link default shader program");
368 delete m_defaultShader;
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);
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);
391 void GLESGraphicsystem::resize(EGLint displayWidth, EGLint displayHeight)
393 m_displayWidth = displayWidth;
394 m_displayHeight = displayHeight;
395 glViewport(0, 0, m_displayWidth, m_displayHeight);
398 void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
400 // clear error if any
401 int error = glGetError();
402 LOG_DEBUG("BaseGraphicSystem","taking screenshot and saving it to:" << fileToSave);
405 glGetIntegerv(GL_VIEWPORT, viewport); // x,y,width,height
406 error = glGetError();
407 if (error != GL_NO_ERROR)
409 LOG_DEBUG("BaseGraphicSystem","error getting dimensions");
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)
419 LOG_DEBUG("BaseGraphicSystem","error reading pixels for screenshot: " << error);
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++)
426 for (int col = 0; col < WINDOW_WIDTH; col++)
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];
435 writeBitmap(fileToSave, rgbbuffer, WINDOW_WIDTH, WINDOW_HEIGHT);