Back to index

unity  6.0.0
ScreenEffectFramebufferObject.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /* Compiz unity plugin
00003  * unity.h
00004  *
00005  * Copyright (c) 2010-11 Canonical Ltd.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 3
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * Authored By: Sam Spilsbury <sam.spilsbury@canonical.com>
00018  */
00019 
00020 #ifndef USE_MODERN_COMPIZ_GL
00021 #include "ScreenEffectFramebufferObject.h"
00022 #include "BackgroundEffectHelper.h"
00023 #include <NuxCore/Logger.h>
00024 #include <dlfcn.h>
00025 
00026 namespace
00027 {
00028   nux::logging::Logger logger ("unity.screeneffectframebufferobject");
00029 }
00030 
00031 void unity::ScreenEffectFramebufferObject::paint (const nux::Geometry &output)
00032 {
00033   /* Draw the bit of the relevant framebuffer for each output */
00034 
00035   glPushAttrib (GL_VIEWPORT_BIT);
00036   glViewport (0, 0, mScreenSize.width, mScreenSize.height);
00037 
00038   if (mFBTexture)
00039   {
00040     glEnable (GL_TEXTURE_2D);
00041     activeTexture (GL_TEXTURE0_ARB);
00042     glBindTexture (GL_TEXTURE_2D, mFBTexture);
00043     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00044     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00045 
00046     glPushAttrib (GL_SCISSOR_BIT);
00047     glEnable (GL_SCISSOR_TEST);
00048 
00049     glScissor (output.x, mScreenSize.height - (output.y + output.height),
00050               output.width, output.height);
00051 
00052     /* FIXME: This needs to be GL_TRIANGLE_STRIP */
00053     glBegin (GL_QUADS);
00054     glTexCoord2f (0, 1);
00055     glVertex2i   (mGeometry.x, mGeometry.y);
00056     glTexCoord2f (0, 0);
00057     glVertex2i   (mGeometry.x, mGeometry.y + mGeometry.height);
00058     glTexCoord2f (1, 0);
00059     glVertex2i   (mGeometry.x + mGeometry.width, mGeometry.y + mGeometry.height);
00060     glTexCoord2f (1, 1);
00061     glVertex2i   (mGeometry.x + mGeometry.width, mGeometry.y);
00062     glEnd ();
00063 
00064     activeTexture (GL_TEXTURE0_ARB);
00065     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00066     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00067     glBindTexture (GL_TEXTURE_2D, 0);
00068     glDisable (GL_TEXTURE_2D);
00069     glPopAttrib ();
00070   }
00071   glPopAttrib ();
00072 }
00073 
00074 void unity::ScreenEffectFramebufferObject::onScreenSizeChanged(const nux::Geometry& screenSize)
00075 {
00076   mScreenSize = screenSize;
00077 }
00078 
00079 
00080 void unity::ScreenEffectFramebufferObject::unbind ()
00081 {
00082   if (!mBoundCnt)
00083     return;
00084 
00085   mBoundCnt--;
00086 
00087   (*bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
00088 
00089   glDrawBuffer (GL_BACK);
00090   glReadBuffer (GL_BACK);
00091 
00092   /* Matches the viewport set we did in ::bind () */
00093   glPopAttrib ();
00094 
00095 }
00096 
00097 bool unity::ScreenEffectFramebufferObject::status ()
00098 {
00099   return mFboStatus;
00100 }
00101 
00102 void unity::ScreenEffectFramebufferObject::bind (const nux::Geometry &output)
00103 {
00104   /* Very important!
00105    * Don't bind unless BackgroundEffectHelper says it's necessary.
00106    * Because binding has a severe impact on graphics performance and we
00107    * can't afford to do it every frame. (LP: #861061) (LP: #987304)
00108    */
00109   if (!BackgroundEffectHelper::HasDirtyHelpers())
00110     return;
00111 
00112   /* Clear the error bit */
00113   glGetError ();
00114 
00115   if (!mFBTexture)
00116   {
00117     glGenTextures (1, &mFBTexture);
00118 
00119     glBindTexture (GL_TEXTURE_2D, mFBTexture);
00120     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00121     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00122     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00123     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00124     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, mGeometry.width, mGeometry.height, 0, GL_BGRA,
00125 #if IMAGE_BYTE_ORDER == MSBFirst
00126                  GL_UNSIGNED_INT_8_8_8_8_REV,
00127 #else
00128                  GL_UNSIGNED_BYTE,
00129 #endif
00130                  NULL);
00131 
00132     glBindTexture (GL_TEXTURE_2D, 0);
00133 
00134     if (glGetError () != GL_NO_ERROR)
00135     {
00136       mFboHandle = 0;
00137       mFboStatus = false;
00138       return;
00139     }
00140   }
00141 
00142   (*bindFramebuffer) (GL_FRAMEBUFFER_EXT, mFboHandle);
00143 
00144   (*framebufferTexture2D) (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
00145                                GL_TEXTURE_2D, mFBTexture, 0);
00146 
00147   (*framebufferTexture2D) (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
00148                                GL_TEXTURE_2D, 0, 0);
00149 
00150   /* Ensure that a framebuffer is actually available */
00151   if (!mFboStatus)
00152   {
00153     GLint status = (*checkFramebufferStatus) (GL_DRAW_FRAMEBUFFER);
00154 
00155     if (status != GL_FRAMEBUFFER_COMPLETE)
00156     {
00157       switch (status)
00158       {
00159         case GL_FRAMEBUFFER_UNDEFINED:
00160           LOG_WARN (logger) <<  "no window";
00161           break;
00162         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
00163           LOG_WARN (logger) <<  "attachment incomplete";
00164           break;
00165         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
00166           LOG_WARN (logger) <<  "no buffers attached to fbo";
00167           break;
00168         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
00169           LOG_WARN (logger) <<  "some attachment in glDrawBuffers doesn't exist in FBO";
00170           break;
00171         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
00172           LOG_WARN (logger) <<  "some attachment in glReadBuffers doesn't exist in FBO";
00173           break;
00174         case GL_FRAMEBUFFER_UNSUPPORTED:
00175           LOG_WARN (logger) <<  "unsupported internal format";
00176           break;
00177         case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
00178           LOG_WARN (logger) <<  "different levels of sampling for each attachment";
00179           break;
00180         case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
00181           LOG_WARN (logger) <<  "number of layers is different";
00182           break;
00183         default:
00184           LOG_WARN (logger) <<  "unable to bind the framebuffer for an unknown reason";
00185           break;
00186       }
00187 
00188       bindFramebuffer (GL_FRAMEBUFFER_EXT, 0);
00189       deleteFramebuffers (1, &mFboHandle);
00190 
00191       glDrawBuffer (GL_BACK);
00192       glReadBuffer (GL_BACK);
00193 
00194       mFboHandle = 0;
00195 
00196       mFboStatus = false;
00197     }
00198     else
00199       mFboStatus = true;
00200   }
00201 
00202   if (mFboStatus)
00203   {
00204     glPushAttrib (GL_VIEWPORT_BIT);
00205 
00206     glViewport (output.x,
00207               mScreenSize.height - (output.y + output.height),
00208               output.width,
00209               output.height);
00210   }
00211 
00212   mBoundCnt++;
00213 }
00214 
00215 
00216 unity::ScreenEffectFramebufferObject::ScreenEffectFramebufferObject (GLXGetProcAddressProc p, const nux::Geometry &geom)
00217  : getProcAddressGLX (p)
00218  , mFboStatus (false)
00219  , mFBTexture (0)
00220  , mGeometry (geom)
00221  , mBoundCnt (0)
00222  , mScreenSize (geom)
00223 {
00224   activeTexture = (GLActiveTextureProc) (*getProcAddressGLX) ((GLubyte *) "glActiveTexture");
00225   genFramebuffers = (GLGenFramebuffersProc) (*getProcAddressGLX) ((GLubyte *)"glGenFramebuffersEXT");
00226   deleteFramebuffers = (GLDeleteFramebuffersProc) (*getProcAddressGLX) ((GLubyte *)"glDeleteFramebuffersEXT");
00227   bindFramebuffer = (GLBindFramebufferProc) (*getProcAddressGLX) ((GLubyte *)"glBindFramebufferEXT");
00228   checkFramebufferStatus = (GLCheckFramebufferStatusProc) (*getProcAddressGLX) ((GLubyte *) "glCheckFramebufferStatusEXT");
00229   framebufferTexture2D = (GLFramebufferTexture2DProc) (*getProcAddressGLX) ((GLubyte *) "glFramebufferTexture2DEXT");
00230   
00231   (*genFramebuffers) (1, &mFboHandle);
00232 }
00233 
00234 unity::ScreenEffectFramebufferObject::~ScreenEffectFramebufferObject ()
00235 {
00236   (*deleteFramebuffers) (1, &mFboHandle);
00237 
00238   if (mFBTexture)
00239     glDeleteTextures (1, &mFBTexture);
00240 }
00241 
00242 #endif // USE_MODERN_COMPIZ_GL
00243