kwin/libkwineffects/kwinglutils.h

652 lines
21 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_GLUTILS_H
#define KWIN_GLUTILS_H
#include <kwinconfig.h> // KWIN_HAVE_OPENGL
#ifdef KWIN_HAVE_OPENGL
#include <kwinglutils_funcs.h>
#include <QtGui/QPixmap>
#include <QtGui/QImage>
#include <QtCore/QSize>
#include <QtCore/QSharedData>
#include <QtCore/QStack>
/** @addtogroup kwineffects */
/** @{ */
class QVector2D;
class QVector3D;
class QVector4D;
class QMatrix4x4;
template< class K, class V > class QHash;
namespace KWin
{
class GLTexture;
class GLVertexBuffer;
class GLVertexBufferPrivate;
// Initializes GLX function pointers
void KWIN_EXPORT initGLX();
// Initializes OpenGL stuff. This includes resolving function pointers as
// well as checking for GL version and extensions
// Note that GL context has to be created by the time this function is called
void KWIN_EXPORT initGL();
// Initializes EGL function pointers
void KWIN_EXPORT initEGL();
// Number of supported texture units
extern KWIN_EXPORT int glTextureUnitsCount;
bool KWIN_EXPORT hasGLVersion(int major, int minor, int release = 0);
bool KWIN_EXPORT hasGLXVersion(int major, int minor, int release = 0);
bool KWIN_EXPORT hasEGLVersion(int major, int minor, int release = 0);
// use for both OpenGL and GLX extensions
bool KWIN_EXPORT hasGLExtension(const QString& extension);
// detect OpenGL error (add to various places in code to pinpoint the place)
bool KWIN_EXPORT checkGLError(const char* txt);
inline bool KWIN_EXPORT isPowerOfTwo(int x)
{
return ((x & (x - 1)) == 0);
}
/**
* @return power of two integer _greater or equal to_ x.
* E.g. nearestPowerOfTwo(513) = nearestPowerOfTwo(800) = 1024
**/
int KWIN_EXPORT nearestPowerOfTwo(int x);
/**
* Push a new matrix on the GL matrix stack.
* In GLES this method is a noop. This method should be preferred over glPushMatrix
* as it also handles GLES.
* @since 4.7
**/
KWIN_EXPORT void pushMatrix();
/**
* Multiplies current matrix on GL stack with @p matrix and pushes the result on the matrix stack.
* This method is the same as pushMatrix followed by multiplyMatrix.
* In GLES this method is a noop. This method should be preferred over glPushMatrix
* as it also handles GLES.
* @param matrix The matrix the current matrix on the stack should be multiplied with.
* @see pushMatrix
* @see multiplyMatrix
* @since 4.7
**/
KWIN_EXPORT void pushMatrix(const QMatrix4x4 &matrix);
/**
* Multiplies the current matrix on GL stack with @p matrix.
* In GLES this method is a noop. This method should be preferred over glMultMatrix
* as it also handles GLES.
* @param matrix The matrix the current matrix on the stack should be multiplied with.
* @since 4.7
**/
KWIN_EXPORT void multiplyMatrix(const QMatrix4x4 &matrix);
/**
* Replaces the current matrix on GL stack with @p matrix.
* In GLES this method is a no-op. This method should be preferred over glLoadMatrix
* as it also handles GLES.
* @param matrix The new matrix to replace the existing one on the GL stack.
* @since 4.7
**/
KWIN_EXPORT void loadMatrix(const QMatrix4x4 &matrix);
/**
* Pops the current matrix from the GL matrix stack.
* In GLES this method is a noop. This method should be preferred over glPopMatrix
* as it also handles GLES.
* @since 4.7
**/
KWIN_EXPORT void popMatrix();
class KWIN_EXPORT GLTexture
: public QSharedData
{
public:
GLTexture();
explicit GLTexture(const QImage& image, GLenum target = GL_TEXTURE_2D);
explicit GLTexture(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
GLTexture(const QString& fileName);
GLTexture(int width, int height);
virtual ~GLTexture();
bool isNull() const;
QSize size() const;
int width() const {
return mSize.width(); /// @since 4.5
}
int height() const {
return mSize.height(); /// @since 4.5
}
virtual bool load(const QImage& image, GLenum target = GL_TEXTURE_2D);
virtual bool load(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
virtual bool load(const QString& fileName);
virtual void discard();
virtual void bind();
virtual void unbind();
void render(QRegion region, const QRect& rect);
/**
* Set up texture transformation matrix to automatically map unnormalized
* texture coordinates (i.e. 0 to width, 0 to height, (0,0) is top-left)
* to OpenGL coordinates. Automatically adjusts for different texture
* types. This can be done only for one texture at a time, repeated
* calls for the same texture are allowed though, requiring the same
* amount of calls to disableUnnormalizedTexCoords().
*
* In OpenGL ES this method is a no-op. In core profile a shader should be used
* @deprecated
*/
void enableUnnormalizedTexCoords();
/**
* Disables transformation set up using enableUnnormalizedTexCoords().
*
* In OpenGL ES this method is a no-op. In core profile a shader should be used
* @deprecated
*/
void disableUnnormalizedTexCoords();
/**
* Set up texture transformation matrix to automatically map normalized
* texture coordinates (i.e. 0 to 1, 0 to 1, (0,0) is bottom-left)
* to OpenGL coordinates. Automatically adjusts for different texture
* types. This can be done only for one texture at a time, repeated
* calls for the same texture are allowed though, requiring the same
* amount of calls to disableNormalizedTexCoords().
*
* In OpenGL ES this method is a no-op. In core profile a shader should be used
* @deprecated
*/
void enableNormalizedTexCoords();
/**
* Disables transformation set up using enableNormalizedTexCoords().
*
* In OpenGL ES this method is a no-op. In core profile a shader should be used
* @deprecated
*/
void disableNormalizedTexCoords();
GLuint texture() const;
GLenum target() const;
GLenum filter() const;
virtual bool isDirty() const;
void setTexture(GLuint texture);
void setTarget(GLenum target);
void setFilter(GLenum filter);
void setWrapMode(GLenum mode);
virtual void setDirty();
static void initStatic();
static bool NPOTTextureSupported() {
return sNPOTTextureSupported;
}
static bool framebufferObjectSupported() {
return sFramebufferObjectSupported;
}
static bool saturationSupported() {
return sSaturationSupported;
}
protected:
void enableFilter();
QImage convertToGLFormat(const QImage& img) const;
GLuint mTexture;
GLenum mTarget;
GLenum mFilter;
QSize mSize;
QSizeF mScale; // to un-normalize GL_TEXTURE_2D
bool y_inverted; // texture has y inverted
bool can_use_mipmaps;
bool has_valid_mipmaps;
private:
void init();
int mUnnormalizeActive; // 0 - no, otherwise refcount
int mNormalizeActive; // 0 - no, otherwise refcount
GLVertexBuffer* m_vbo;
QSize m_cachedSize;
static bool sNPOTTextureSupported;
static bool sFramebufferObjectSupported;
static bool sSaturationSupported;
Q_DISABLE_COPY(GLTexture)
};
class KWIN_EXPORT GLShader
{
public:
GLShader(const QString& vertexfile, const QString& fragmentfile);
~GLShader();
bool isValid() const {
return mValid;
}
int uniformLocation(const char* name);
bool setUniform(const char* name, float value);
bool setUniform(const char* name, int value);
bool setUniform(const char* name, const QVector2D& value);
bool setUniform(const char* name, const QVector3D& value);
bool setUniform(const char* name, const QVector4D& value);
bool setUniform(const char* name, const QMatrix4x4& value);
bool setUniform(const char* name, const QColor& color);
bool setUniform(int location, float value);
bool setUniform(int location, int value);
bool setUniform(int location, const QVector2D &value);
bool setUniform(int location, const QVector3D &value);
bool setUniform(int location, const QVector4D &value);
bool setUniform(int location, const QMatrix4x4 &value);
bool setUniform(int location, const QColor &value);
int attributeLocation(const char* name);
bool setAttribute(const char* name, float value);
/**
* @return The value of the uniform as a matrix
* @since 4.7
**/
QMatrix4x4 getUniformMatrix4x4(const char* name);
void setTextureWidth(float width);
void setTextureHeight(float height);
float textureWidth();
float textureHeight();
enum MatrixUniform {
TextureMatrix = 0,
ProjectionMatrix,
ModelViewMatrix,
WindowTransformation,
ScreenTransformation,
MatrixCount
};
enum Vec2Uniform {
Offset,
Vec2UniformCount
};
enum Vec4Uniform {
ModulationConstant,
Vec4UniformCount
};
enum FloatUniform {
Saturation,
TextureWidth,
TextureHeight,
FloatUniformCount
};
enum IntUniform {
AlphaToOne,
IntUniformCount
};
bool setUniform(MatrixUniform uniform, const QMatrix4x4 &matrix);
bool setUniform(Vec2Uniform uniform, const QVector2D &value);
bool setUniform(Vec4Uniform uniform, const QVector4D &value);
bool setUniform(FloatUniform uniform, float value);
bool setUniform(IntUniform uniform, int value);
protected:
GLShader();
bool loadFromFiles(const QString& vertexfile, const QString& fragmentfile);
bool load(const QByteArray &vertexSource, const QByteArray &fragmentSource);
bool compile(GLuint program, GLenum shaderType, const QByteArray &sourceCode) const;
void bind();
void unbind();
void resolveLocations();
private:
unsigned int mProgram;
bool mValid:1;
bool mLocationsResolved:1;
int mMatrixLocation[MatrixCount];
int mVec2Location[Vec2UniformCount];
int mVec4Location[Vec4UniformCount];
int mFloatLocation[FloatUniformCount];
int mIntLocation[IntUniformCount];
float mTextureWidth;
float mTextureHeight;
friend class ShaderManager;
};
/**
* @short Manager for Shaders.
*
* This class provides some built-in shaders to be used by both compositing scene and effects.
* The ShaderManager provides methods to bind a built-in or a custom shader and keeps track of
* the shaders which have been bound. When a shader is unbound the previously bound shader
* will be rebound.
*
* @author Martin Gräßlin <kde@martin-graesslin.com>
* @since 4.7
**/
class KWIN_EXPORT ShaderManager
{
public:
/**
* Identifiers for built-in shaders available for effects and scene
**/
enum ShaderType {
/**
* An orthographic projection shader able to render textured geometries.
* Expects a @c vec2 uniform @c offset describing the offset from top-left corner
* and defaults to @c (0/0). Expects a @c vec2 uniform @c textureSize to calculate
* normalized texture coordinates. Defaults to @c (1.0/1.0). And expects a @c vec3
* uniform @c colorManiuplation, with @c x being opacity, @c y being brightness and
* @c z being saturation. All three values default to @c 1.0.
* The fragment shader takes a uniform @c u_forceAlpha to force the alpha component
* to @c 1.0 if it is set to a value not @c 0. This uniform is useful when rendering
* a RGB-only window and the alpha channel is required in a later step.
* The sampler uniform is @c sample and defaults to @c 0.
* The shader uses two vertex attributes @c vertex and @c texCoord.
**/
SimpleShader,
/**
* A generic shader able to render transformed, textured geometries.
* This shader is mostly needed by the scene and not of much interest for effects.
* Effects can influence this shader through @link ScreenPaintData and @link WindowPaintData.
* The shader expects four @c mat4 uniforms @c projection, @c modelview,
* @c screenTransformation and @c windowTransformation. The fragment shader expect the
* same uniforms as the SimpleShader and the same vertex attributes are used.
**/
GenericShader,
/**
* An orthographic shader to render simple colored geometries without texturing.
* Expects a @c vec2 uniform @c offset describing the offset from top-left corner
* and defaults to @c (0/0). The fragment shader expects a single @c vec4 uniform
* @c geometryColor, which defaults to fully opaque black.
* The Shader uses one vertex attribute @c vertex.
**/
ColorShader
};
/**
* @return The currently bound shader or @c null if no shader is bound.
**/
GLShader *getBoundShader() const;
/**
* @return @c true if a shader is bound, @c false otherwise
**/
bool isShaderBound() const;
/**
* @return @c true if the built-in shaders are valid, @c false otherwise
**/
bool isValid() const;
/**
* Binds the shader of specified @p type.
* To unbind the shader use @link popShader. A previous bound shader will be rebound.
* @param type The built-in shader to bind
* @param reset Whether all uniforms should be reset to their default values
* @return The bound shader or @c NULL if shaders are not valid
* @see popShader
**/
GLShader *pushShader(ShaderType type, bool reset = false);
/**
* Binds the @p shader.
* To unbind the shader use @link popShader. A previous bound shader will be rebound.
* To bind a built-in shader use the more specific method.
* @param shader The shader to be bound
* @see popShader
**/
void pushShader(GLShader *shader);
/**
* Unbinds the currently bound shader and rebinds a previous stored shader.
* If there is no previous shader, no shader will be rebound.
* It is not safe to call this method if there is no bound shader.
* @see pushShader
* @see getBoundShader
**/
void popShader();
/**
* Creates a GLShader with a built-in vertex shader and a custom fragment shader.
* @param vertex The generic vertex shader
* @param fragmentFile The path to the source code of the fragment shader
* @return The created shader
**/
GLShader *loadFragmentShader(ShaderType vertex, const QString &fragmentFile);
/**
* Creates a GLShader with a built-in fragment shader and a custom vertex shader.
* @param fragment The generic fragment shader
* @param vertexFile The path to the source code of the vertex shader
* @return The created shader
**/
GLShader *loadVertexShader(ShaderType fragment, const QString &vertexFile);
/**
* Creates a GLShader with the specified sources.
* The difference to GLShader is that it does not need to be loaded from files.
* @param vertexSource The source code of the vertex shader
* @param fragmentSource The source code of the fragment shader.
* @return The created shader
**/
GLShader *loadShaderFromCode(const QByteArray &vertexSource, const QByteArray &fragmentSource);
/**
* @return a pointer to the ShaderManager instance
**/
static ShaderManager *instance();
/**
* @internal
**/
static void cleanup();
private:
ShaderManager();
~ShaderManager();
void initShaders();
void resetShader(ShaderType type);
QStack<GLShader*> m_boundShaders;
GLShader *m_orthoShader;
GLShader *m_genericShader;
GLShader *m_colorShader;
bool m_inited;
bool m_valid;
static ShaderManager *s_shaderManager;
};
/**
* @short Render target object
*
* Render target object enables you to render onto a texture. This texture can
* later be used to e.g. do post-processing of the scene.
*
* @author Rivo Laks <rivolaks@hot.ee>
**/
class KWIN_EXPORT GLRenderTarget
{
public:
/**
* Constructs a GLRenderTarget
* @param color texture where the scene will be rendered onto
**/
GLRenderTarget(GLTexture* color);
~GLRenderTarget();
/**
* Enables this render target.
* All OpenGL commands from now on affect this render target until the
* @ref disable method is called
**/
bool enable();
/**
* Disables this render target, activating whichever target was active
* when @ref enable was called.
**/
bool disable();
bool valid() const {
return mValid;
}
static void initStatic();
static bool supported() {
return sSupported;
}
protected:
void initFBO();
private:
static bool sSupported;
GLTexture* mTexture;
bool mValid;
GLuint mFramebuffer;
};
/**
* @short Vertex Buffer Object
*
* This is a short helper class to use vertex buffer objects (VBO). A VBO can be used to buffer
* vertex data and to store them on graphics memory. It is the only allowed way to pass vertex
* data to the GPU in OpenGL ES 2 and OpenGL 3 with forward compatible mode.
*
* If VBOs are not supported on the used OpenGL profile this class falls back to legacy
* rendering using client arrays. Therefore this class should always be used for rendering geometries.
*
* @author Martin Gräßlin <kde@martin-graesslin.com>
* @since 4.6
*/
class KWIN_EXPORT GLVertexBuffer
{
public:
/**
* Enum to define how often the vertex data in the buffer object changes.
*/
enum UsageHint {
Dynamic, ///< frequent changes, but used several times for rendering
Static, ///< No changes to data
Stream ///< Data only used once for rendering, updated very frequently
};
GLVertexBuffer(UsageHint hint);
~GLVertexBuffer();
/**
* Sets the vertex data.
* @param numberVertices The number of vertices in the arrays
* @param dim The dimension of the vertices: 2 for x/y, 3 for x/y/z
* @param vertices The vertices, size must equal @a numberVertices * @a dim
* @param texcoords The texture coordinates for each vertex.
* Size must equal 2 * @a numberVertices.
*/
void setData(int numberVertices, int dim, const float* vertices, const float* texcoords);
/**
* Renders the vertex data in given @a primitiveMode.
* Please refer to OpenGL documentation of glDrawArrays or glDrawElements for allowed
* values for @a primitiveMode. Best is to use GL_TRIANGLES or similar to be future
* compatible.
*/
void render(GLenum primitiveMode);
/**
* Same as above restricting painting to @a region.
*/
void render(const QRegion& region, GLenum primitiveMode);
/**
* Sets the color the geometry will be rendered with.
* For legacy rendering glColor is used before rendering the geometry.
* For core shader a uniform "geometryColor" is expected and is set.
* @param color The color to render the geometry
* @param enableColor Whether the geometry should be rendered with a color or not
* @see setUseColor
* @see isUseColor
* @since 4.7
**/
void setColor(const QColor& color, bool enableColor = true);
/**
* @return @c true if geometry will be painted with a color, @c false otherwise
* @see setUseColor
* @see setColor
* @since 4.7
**/
bool isUseColor() const;
/**
* Enables/Disables rendering the geometry with a color.
* If no color is set an opaque, black color is used.
* @param enable Enable/Disable rendering with color
* @see isUseColor
* @see setColor
* @since 4.7
**/
void setUseColor(bool enable);
/**
* Resets the instance to default values.
* Useful for shared buffers.
* @since 4.7
**/
void reset();
/**
* @internal
*/
static void initStatic();
/**
* Returns true if VBOs are supported, it is save to use this class even if VBOs are not
* supported.
* @returns true if vertex buffer objects are supported
*/
static bool isSupported();
/**
* @return A shared VBO for streaming data
* @since 4.7
**/
static GLVertexBuffer *streamingBuffer();
private:
GLVertexBufferPrivate* const d;
};
} // namespace
#endif
/** @} */
#endif