WindowSystem: Forced composition should also redraw HW layers
[profile/ivi/layer-management.git] / LayerManagerPlugins / Renderers / Graphic / src / GraphicSystems / GLXGraphicSystem.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/GLXGraphicsystem.h"
21 #include <string.h>
22 #include "TextureBinders/X11CopyGLX.h"
23 #include "TextureBinders/X11TextureFromPixmap.h"
24 #include "Transformation/ViewportTransform.h"
25
26 #include "Bitmap.h"
27
28 GLXGraphicsystem::GLXGraphicsystem(int WindowWidth, int WindowHeight)
29 : m_windowWidth(WindowWidth)
30 , m_windowHeight(WindowHeight)
31 , m_x11display(0)
32 , m_window(0)
33 , m_context(0)
34 , m_currentLayer(0)
35 , m_zerocopy(false)
36
37 {
38     LOG_DEBUG("GLXGraphicsystem", "creating GLXGraphicsystem");
39 }
40
41 GLXGraphicsystem::~GLXGraphicsystem()
42 {
43     if (m_binder)
44     {
45         delete m_binder;
46     }
47 }
48
49 XVisualInfo* GLXGraphicsystem::GetMatchingVisual(Display *dpy)
50 {
51     int screen = DefaultScreen(dpy);
52     XVisualInfo *visinfo;
53     int attribs[] = {
54             GLX_RGBA,
55             GLX_ALPHA_SIZE,8,
56             GLX_RED_SIZE, 1,
57             GLX_GREEN_SIZE, 1,
58             GLX_BLUE_SIZE, 1,
59             GLX_DEPTH_SIZE,8,
60             GLX_BUFFER_SIZE,32,
61             GLX_DOUBLEBUFFER,
62             None
63     };
64
65     visinfo = glXChooseVisual(dpy, screen, attribs);
66     if (!visinfo)
67     {
68         LOG_ERROR("GLXGraphicsystem", "Unable to find RGB, double-buffered visual");
69     }
70     return visinfo;
71 }
72 bool GLXGraphicsystem::CheckConfigMask(Display *curDisplay,GLXFBConfig currentConfig, int attribute, int expectedValue)
73 {
74     bool result = true;
75     int returnedValue = 0;
76
77     glXGetFBConfigAttrib(curDisplay,currentConfig,attribute,&returnedValue);
78     if (!(returnedValue & expectedValue))
79     {
80         result = false;
81     }
82     return result;
83 }
84
85 bool GLXGraphicsystem::CheckConfigValue(Display *curDisplay,GLXFBConfig currentConfig, int attribute, int expectedValue)
86 {
87     bool result = true;
88     int returnedValue = 0;
89
90     glXGetFBConfigAttrib(curDisplay,currentConfig,attribute,&returnedValue);
91     if ((returnedValue != expectedValue))
92     {
93         result = false;
94     }
95     return result;
96 }
97
98 void GLXGraphicsystem::activateGraphicContext()
99 {
100     glXMakeCurrent(m_x11display, m_window, m_context);   
101 }
102
103 void GLXGraphicsystem::releaseGraphicContext() 
104 {
105     glXMakeCurrent(m_x11display, None, NULL);
106 }
107
108 GLXFBConfig* GLXGraphicsystem::GetMatchingPixmapConfig(Display *curDisplay)
109 {
110     int neededMaskAttribute[] =
111     {
112         GLX_DRAWABLE_TYPE,GLX_PIXMAP_BIT,
113         GLX_DRAWABLE_TYPE,GLX_WINDOW_BIT,
114         GLX_BIND_TO_TEXTURE_TARGETS_EXT,GLX_TEXTURE_2D_BIT_EXT,
115         None
116     };
117     int neededValueAttribute[] =
118     {
119         GLX_BUFFER_SIZE,32,
120         GLX_ALPHA_SIZE,8,
121         GLX_BIND_TO_TEXTURE_RGBA_EXT,True,
122         None
123     };
124     LOG_DEBUG("GLXGraphicsystem", "Choose pixmap GL configuration");
125     int screen = DefaultScreen(curDisplay);
126     GLXFBConfig *currentFBconfigs;
127     int i = 0;
128     int j = 0;
129     int nConfigs = 0;
130
131     currentFBconfigs = glXGetFBConfigs(curDisplay, screen, &nConfigs);
132     for (i = 0; i < nConfigs; i++)
133     {
134         GLXFBConfig config = currentFBconfigs[i];
135         bool result = true;
136         /* check first all mask values */
137         j = 0;
138         while ( neededMaskAttribute[j] != None && result == true )
139         {
140            result = CheckConfigMask(curDisplay,config, neededMaskAttribute[j], neededMaskAttribute[j+1]);
141            j += 2;
142         }
143         /* no matching found in needed mask attribute, skip config take next */
144         if (result == false )
145         {
146             continue;
147         }
148         /* check all fixed values */
149
150         /* reset attribute counter */
151         j = 0;
152         /* check all fixed values */
153         while ( neededValueAttribute[j] != None && result == true )
154         {
155            result = CheckConfigValue(curDisplay,config, neededValueAttribute[j], neededValueAttribute[j+1]);
156            j += 2;
157         }
158         /* no matching found in needed fixed value attribute, skip config take next */
159
160         if (result == false )
161         {
162             continue;
163         }
164         break;
165     }
166
167     if (i == nConfigs)
168     {
169         LOG_ERROR("GLXGraphicsystem", "Unable to find FBconfig for texturing");
170         return NULL;
171     }
172
173     LOG_DEBUG("GLXGraphicsystem", "Done choosing GL Pixmap configuration");
174     return &currentFBconfigs[i];
175 }
176
177 bool GLXGraphicsystem::init(Display* x11Display, Window x11Window)
178 {
179     LOG_DEBUG("GLXGraphicsystem", "init");
180     m_x11display = x11Display;
181     m_window = x11Window;
182
183     if (!m_x11display)
184     {
185         LOG_ERROR("GLXGraphicsystem", "given display is null");
186         return false;
187     }
188
189     if (!m_window)
190     {
191         LOG_ERROR("GLXGraphicsystem", "given windowid is 0");
192         return false;
193     }
194
195     XVisualInfo* windowVis = GetMatchingVisual(m_x11display);
196
197     LOG_DEBUG("GLXGraphicsystem", "Initialising opengl");
198     m_context = glXCreateContext(m_x11display, windowVis, 0, GL_TRUE);
199     if (!m_context)
200     {
201         LOG_ERROR("GLXGraphicsystem", "Couldn't create GLX context!");
202         return false;
203     }
204     LOG_DEBUG("GLXGraphicsystem", "Make GLX Context current");
205     glXMakeCurrent(m_x11display, m_window, m_context);
206     glEnable (GL_BLEND);
207     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
208     glClearColor(0.0, 0.0, 0.0, 1.0);
209     glEnable(GL_TEXTURE_2D);
210     glMatrixMode(GL_MODELVIEW);
211     const char *ext;
212     ext = glXQueryExtensionsString(m_x11display, 0);
213     if (!strstr(ext, "GLX_EXT_texture_from_pixmap") )
214     {
215         m_zerocopy = false;
216     }
217     else
218     {
219         m_zerocopy = true;
220     }
221
222     LOG_DEBUG("GLXGraphicsystem", "Initialised");
223     return true;
224 }
225
226
227 void GLXGraphicsystem::clearBackground()
228 {
229     glClear(GL_COLOR_BUFFER_BIT);
230 }
231
232 void GLXGraphicsystem::swapBuffers()
233 {
234     glXSwapBuffers(m_x11display, m_window);
235 }
236
237 void GLXGraphicsystem::beginLayer(Layer* currentLayer)
238 {
239     m_currentLayer = currentLayer;
240
241     /* Load Identity Matrix for each Layer */
242     glLoadIdentity();
243
244     /* set layer Transformations */
245 /*    const Rectangle& layerDestination = m_currentLayer->getDestinationRegion(); */
246     // TODO: unused? const Rectangle& layerSource = m_currentLayer->getSourceRegion();
247
248 /*    glTranslatef(layerDestination.x, layerDestination.y, 0.0); */
249 }
250
251 void GLXGraphicsystem::checkRenderLayer()
252 {
253     SurfaceList surfaces = m_currentLayer->getAllSurfaces();
254
255     m_currentLayer->damaged = false;
256
257     if (!m_baseWindowSystem->m_forceComposition && (!m_baseWindowSystem->m_damaged || m_currentLayer->getLayerType() == Hardware))
258     {
259         if (m_currentLayer->renderPropertyChanged)
260         {
261             m_currentLayer->damaged = true;
262         }
263         else if ((m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0)
264         {
265             for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
266             {
267                 if ((*currentS)->renderPropertyChanged)
268                 {
269                     m_currentLayer->damaged = true;
270                     break;
271                 }
272                 else if ((*currentS)->hasNativeContent() && (*currentS)->damaged && (*currentS)->visibility && (*currentS)->opacity>0.0f)
273                 {
274                     m_currentLayer->damaged = true;
275                     break;
276                 }
277             }
278         }
279
280         // Preseve m_currentLayer->damaged for HW layers so that they can be updated independently
281         if (m_currentLayer->damaged && m_currentLayer->getLayerType() != Hardware)
282         {
283             m_baseWindowSystem->m_damaged = true;
284             m_currentLayer->damaged = false;
285         }
286     }
287
288     for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
289     {
290         (*currentS)->damaged = false;
291         (*currentS)->renderPropertyChanged = false;
292     }
293
294     m_currentLayer->renderPropertyChanged = false;
295 }
296
297 void GLXGraphicsystem::renderSWLayer()
298 {
299     if ( (m_currentLayer)->visibility && (m_currentLayer)->opacity > 0.0 )
300     {
301         SurfaceList surfaces = m_currentLayer->getAllSurfaces();
302         for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
303         {
304             if ((*currentS)->hasNativeContent() && (*currentS)->visibility && (*currentS)->opacity>0.0f)
305             {
306                 Surface* currentSurface = (Surface*)*currentS;
307                 renderSurface(currentSurface);
308             }
309         }
310     }
311 }
312
313 void GLXGraphicsystem::endLayer()
314 {
315     m_currentLayer = NULL;
316 }
317
318 void GLXGraphicsystem::renderSurface(Surface* currentSurface)
319 {
320 //    LOG_DEBUG("GLXGraphicsystem", "renderSurface " << currentSurface->getID() );
321     GLenum glErrorCode = GL_NO_ERROR;
322
323     // check if surface is cropped completely, if so then skip rendering
324     if (ViewportTransform::isFullyCropped(currentSurface->getDestinationRegion(), m_currentLayer->getSourceRegion() ) )
325         return; // skip rendering of this surface, because it is cropped by layer source region
326
327     const FloatRectangle layerSourceRegion = m_currentLayer->getSourceRegion();
328     const FloatRectangle layerDestinationRegion = m_currentLayer->getDestinationRegion();
329
330     FloatRectangle targetSurfaceSource = currentSurface->getSourceRegion();
331     FloatRectangle targetSurfaceDestination = currentSurface->getDestinationRegion();
332
333     ViewportTransform::applyLayerSource(layerSourceRegion, targetSurfaceSource, targetSurfaceDestination);
334     ViewportTransform::applyLayerDestination(layerDestinationRegion, layerSourceRegion, targetSurfaceDestination);
335     float textureCoordinates[4];
336     ViewportTransform::transformRectangleToTextureCoordinates(targetSurfaceSource, currentSurface->OriginalSourceWidth, currentSurface->OriginalSourceHeight, textureCoordinates);
337
338     glPushMatrix();
339     if (false == m_binder->bindSurfaceTexture(currentSurface))
340     {
341         /* skip render surface if not bind successfully */
342         return;
343     }
344 //    glPushMatrix();
345     glColor4f(1.0f,1.0f,1.0f,currentSurface->opacity*(m_currentLayer)->opacity);
346
347     glBegin(GL_QUADS);
348
349 //    LOG_DEBUG("GLXGraphicsystem","rendersurface: src" << src.x << " " << src.y << " " << src.width << " " << src.height );
350 //    LOG_DEBUG("GLXGraphicsystem","rendersurface: dest" << dest.x << " " << dest.y << " " << dest.width << " " << dest.height );
351 //    LOG_DEBUG("GLXGraphicsystem","orig: " << currentSurface->OriginalSourceWidth << " " << currentSurface->OriginalSourceHeight  );
352 //    LOG_DEBUG("GLXGraphicsystem","window: " << m_windowWidth << " " << m_windowHeight  );
353
354     //bottom left
355     glTexCoord2d(textureCoordinates[0],textureCoordinates[3]);
356     glVertex2d((float)targetSurfaceDestination.x/m_windowWidth*2-1,  1-(float)(targetSurfaceDestination.y+targetSurfaceDestination.height)/m_windowHeight*2);
357
358     // bottom right
359     glTexCoord2f(textureCoordinates[2],textureCoordinates[3]);
360     glVertex2d( (float)(targetSurfaceDestination.x+targetSurfaceDestination.width)/m_windowWidth*2-1, 1-(float)(targetSurfaceDestination.y+targetSurfaceDestination.height)/m_windowHeight*2);
361
362     // top right
363     glTexCoord2f(textureCoordinates[2], textureCoordinates[1]);
364     glVertex2d((float)(targetSurfaceDestination.x+targetSurfaceDestination.width)/m_windowWidth*2-1, 1-(float)targetSurfaceDestination.y/m_windowHeight*2);
365
366     // top left
367     glTexCoord2f(textureCoordinates[0], textureCoordinates[1]);
368     glVertex2d((float)targetSurfaceDestination.x/m_windowWidth*2-1 ,  1-(float)targetSurfaceDestination.y/m_windowHeight*2);
369     glEnd();
370
371     m_binder->unbindSurfaceTexture(currentSurface);
372     glPopMatrix();
373     glErrorCode = glGetError();
374     if ( GL_NO_ERROR != glErrorCode )
375     {
376         LOG_ERROR("GLXGraphicsystem", "GL Error occured :" << glErrorCode );
377     }
378     currentSurface->frameCounter++;
379     currentSurface->drawCounter++;
380 }
381
382 void GLXGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
383 {
384     LOG_DEBUG("GLXGraphicsystem","taking screenshot and saving it to:" << fileToSave);
385
386     GLint viewport[4];
387     glGetIntegerv(GL_VIEWPORT,viewport); // x,y,width,height
388
389     int WINDOW_WIDTH= viewport[2];
390     int WINDOW_HEIGHT= viewport[3];
391     LOG_DEBUG("GLXGraphicsystem","Screenshot: " << WINDOW_WIDTH << " * " << WINDOW_HEIGHT);
392     char *buffer = (char *)malloc(WINDOW_WIDTH * WINDOW_HEIGHT * 3 * sizeof(unsigned char));
393     glReadPixels(0,0,WINDOW_WIDTH,WINDOW_HEIGHT,GL_BGR,GL_UNSIGNED_BYTE, buffer);
394
395     writeBitmap(fileToSave,buffer,WINDOW_WIDTH,WINDOW_HEIGHT);
396     free(buffer);
397     LOG_DEBUG("GLXGraphicsystem","done taking screenshot");
398 }
399