diff --git a/lib/kwinglutils.cpp b/lib/kwinglutils.cpp index 47846ab430..0a5d5f9c75 100644 --- a/lib/kwinglutils.cpp +++ b/lib/kwinglutils.cpp @@ -438,7 +438,25 @@ bool GLTexture::load( const QPixmap& pixmap, GLenum target ) { if( pixmap.isNull()) return false; +#ifdef KWIN_HAVE_OPENGLES + if( isNull() ) + glGenTextures( 1, &mTexture ); + mTarget = target; + bind(); + const EGLint attribs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE + }; + EGLDisplay dpy = eglGetCurrentDisplay(); + EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer)pixmap.handle(), attribs); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); + eglDestroyImageKHR(dpy, image); + unbind(); + return true; +#else return load( pixmap.toImage(), target ); +#endif } bool GLTexture::load( const QString& fileName ) @@ -1020,6 +1038,7 @@ float GLShader::textureWidth() void GLShader::bindAttributeLocation(int index, const char* name) { glBindAttribLocation(mProgram, index, name); + // TODO: relink the shader } /*** GLRenderTarget ***/ @@ -1247,26 +1266,32 @@ void GLVertexBufferPrivate::corePainting( const QRegion& region, GLenum primitiv glEnableVertexAttribArray( 0 ); glEnableVertexAttribArray( 1 ); + // TODO: have this information available somewhere useable + GLint currentProgram; + glGetIntegerv( GL_CURRENT_PROGRAM, ¤tProgram ); + GLint vertexAttrib = glGetAttribLocation( currentProgram, "vertex" ); + GLint texAttrib = glGetAttribLocation( currentProgram, "texCoord" ); glBindBuffer( GL_ARRAY_BUFFER, buffers[ 0 ] ); - glVertexAttribPointer( 0, dimension, GL_FLOAT, GL_FALSE, 0, 0 ); + glVertexAttribPointer( vertexAttrib, dimension, GL_FLOAT, GL_FALSE, 0, 0 ); glBindBuffer( GL_ARRAY_BUFFER, buffers[ 1 ] ); - glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, 0 ); + glVertexAttribPointer( texAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0 ); + // TODO: reenable paint clipper // Clip using scissoring - PaintClipper pc( region ); + /*PaintClipper pc( region ); for( PaintClipper::Iterator iterator; !iterator.isDone(); iterator.next()) - { + {*/ glDrawArrays( primitiveMode, 0, numberVertices ); - } + //} glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDisableVertexAttribArray( 1 ); - glDisableVertexAttribArray( 2 ); + glDisableVertexAttribArray( 0 ); } //********************************* diff --git a/scene-fragment.glsl b/scene-fragment.glsl index 8569df76d2..7d9724100d 100644 --- a/scene-fragment.glsl +++ b/scene-fragment.glsl @@ -1,3 +1,6 @@ +#ifdef GL_ES +precision highp float; +#endif uniform sampler2D sample; uniform float textureWidth; uniform float textureHeight; @@ -6,9 +9,9 @@ uniform float brightness; uniform float saturation; uniform int debug; -varying in vec2 varyingTexCoords; +varying vec2 varyingTexCoords; -varying out vec4 color; +//varying vec4 color; // Converts pixel coordinates to texture coordinates vec2 pix2tex( vec2 pix ) @@ -25,9 +28,9 @@ void main() { } tex.rgb = tex.rgb * opacity * brightness; tex.a = tex.a * opacity; - if (debug != 0) { + /*if (debug != 0) { tex.g += 0.5; - } + }*/ - color = tex; + gl_FragColor = tex; } diff --git a/scene-vertex.glsl b/scene-vertex.glsl index e61f24ecfa..cd259449f3 100644 --- a/scene-vertex.glsl +++ b/scene-vertex.glsl @@ -1,17 +1,20 @@ +#ifdef GL_ES +precision highp float; +#endif // size of the complete display in pixels, x==width, y==height uniform vec2 displaySize; // geometry of the window/texture to be rendered: x, y, width, height in display geometry uniform vec4 geometry; // passed in vertex - only x and y are used -in vec4 vertex; +attribute vec4 vertex; // passed in texCoords - to be forwarded -in vec2 texCoord; +attribute vec2 texCoord; // texCoords passed to fragment shader -varying out vec2 varyingTexCoords; +varying vec2 varyingTexCoords; void main() { varyingTexCoords = texCoord; - gl_Position.xy = 2*vec2(geometry.x + vertex.x, displaySize.y - vertex.y - geometry.y)/displaySize - vertex.ww; + gl_Position.xy = 2.0*vec2(geometry.x + vertex.x, displaySize.y - vertex.y - geometry.y)/displaySize - vertex.ww; } diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 4d3be6f1ef..1453a39f0a 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -368,12 +368,14 @@ SceneOpenGL::Window::~Window() // Bind the window pixmap to an OpenGL texture. bool SceneOpenGL::Window::bindTexture() { +#ifndef KWIN_HAVE_OPENGLES if( texture.texture() != None && toplevel->damage().isEmpty()) { // texture doesn't need updating, just bind it glBindTexture( texture.target(), texture.texture()); return true; } +#endif // Get the pixmap with the window contents Pixmap pix = toplevel->windowPixmap(); if( pix == None ) @@ -1113,7 +1115,6 @@ void SceneOpenGL::EffectFrame::render( QRegion region, double opacity, double fr { shader = static_cast(scene)->m_sceneShader; sceneShader = true; - kDebug(1212) << "using scene shader"; } if( shader ) { @@ -1274,7 +1275,6 @@ void SceneOpenGL::EffectFrame::render( QRegion region, double opacity, double fr } #endif m_unstyledTexture->unbind(); - checkGLError("unstyled texture"); } else if( m_effectFrame->style() == EffectFrameStyled ) { diff --git a/scene_opengl_egl.cpp b/scene_opengl_egl.cpp index 52b2c8de45..18c83ff543 100644 --- a/scene_opengl_egl.cpp +++ b/scene_opengl_egl.cpp @@ -19,6 +19,13 @@ along with this program. If not, see . *********************************************************************/ // This file is included in scene_opengl.cpp +//#include "scene_opengl.h" +#include + +EGLDisplay dpy; +EGLConfig config; +EGLSurface surface; +EGLContext ctx; SceneOpenGL::SceneOpenGL( Workspace* ws ) : Scene( ws ) @@ -26,8 +33,10 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) , selfCheckDone( true ) , m_sceneShader( NULL ) { - // TODO: EGL + if( !initRenderingContext() ) + return; + initGL(); debug = qstrcmp( qgetenv( "KWIN_GL_DEBUG" ), "1" ) == 0; m_sceneShader = new GLShader( ":/resources/scene-vertex.glsl", ":/resources/scene-fragment.glsl" ); @@ -37,8 +46,6 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) m_sceneShader->setUniform( "sample", 0 ); m_sceneShader->setUniform( "displaySize", QVector2D(displayWidth(), displayHeight())); m_sceneShader->setUniform( "debug", debug ? 1 : 0 ); - m_sceneShader->bindAttributeLocation( 0, "vertex" ); - m_sceneShader->bindAttributeLocation( 1, "texCoord" ); m_sceneShader->unbind(); kDebug(1212) << "Scene Shader is valid"; } @@ -62,6 +69,12 @@ SceneOpenGL::~SceneOpenGL() { foreach( Window* w, windows ) delete w; + // do cleanup after initBuffer() + eglMakeCurrent( dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); + eglDestroyContext( dpy, ctx ); + eglDestroySurface( dpy, surface ); + eglTerminate( dpy ); + eglReleaseThread(); delete m_sceneShader; SceneOpenGL::EffectFrame::cleanup(); checkGLError( "Cleanup" ); @@ -74,7 +87,39 @@ bool SceneOpenGL::initTfp() bool SceneOpenGL::initRenderingContext() { - return false; + dpy = eglGetDisplay( display() ); + if( dpy == EGL_NO_DISPLAY ) + return false; + EGLint major, minor; + if( eglInitialize( dpy, &major, &minor ) == EGL_FALSE ) + return false; + eglBindAPI( EGL_OPENGL_ES_API ); + initBufferConfigs(); + if( !wspace->createOverlay() ) + { + kError( 1212 ) << "Could not get overlay window"; + return false; + } + surface = eglCreateWindowSurface( dpy, config, wspace->overlayWindow(), 0 ); + + const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + ctx = eglCreateContext( dpy, config, EGL_NO_CONTEXT, context_attribs ); + if( ctx == EGL_NO_CONTEXT ) + return false; + if( eglMakeCurrent( dpy, surface, surface, ctx ) == EGL_FALSE ) + return false; + kDebug( 1212 ) << "EGL version: " << major << "." << minor; + EGLint error = eglGetError(); + if( error != EGL_SUCCESS ) + { + kWarning( 1212 ) << "Error occurred while creating context " << error; + return false; + } + return true; } bool SceneOpenGL::initBuffer() @@ -84,7 +129,35 @@ bool SceneOpenGL::initBuffer() bool SceneOpenGL::initBufferConfigs() { - return false; + const EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + EGL_ALPHA_SIZE, 0, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE, + }; + + EGLint count; + EGLConfig configs[1024]; + eglChooseConfig(dpy, config_attribs, configs, 1024, &count); + + EGLint visualId = XVisualIDFromVisual((Visual*)QX11Info::appVisual()); + + config = configs[0]; + for (int i = 0; i < count; i++) + { + EGLint val; + eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &val); + if (visualId == val) + { + config = configs[i]; + break; + } + } + return true; } bool SceneOpenGL::initDrawableConfigs() @@ -112,8 +185,12 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) assert( windows.contains( c )); stacking_order.append( windows[ c ] ); } + grabXServer(); int mask = 0; paintScreen( &mask, &damage ); // call generic implementation + ungrabXServer(); // ungrab before flushBuffer(), it may wait for vsync + if( wspace->overlayWindow()) // show the window only after the first pass, since + wspace->showOverlay(); // that pass may take long lastRenderTime = t.elapsed(); flushBuffer( mask, damage ); // do cleanup @@ -128,7 +205,19 @@ void SceneOpenGL::waitSync() void SceneOpenGL::flushBuffer( int mask, QRegion damage ) { - // TODO: implement me + glFlush(); + if( mask & PAINT_SCREEN_REGION ) + { + // TODO: implement me properly + eglSwapBuffers( dpy, surface ); + } + else + { + eglSwapBuffers( dpy, surface ); + } + eglWaitGL(); + // TODO: remove for wayland + XFlush( display()); } void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data ) @@ -140,6 +229,8 @@ void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data ) void SceneOpenGL::paintBackground( QRegion region ) { // TODO: implement me + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); } //**************************************** @@ -149,10 +240,12 @@ void SceneOpenGL::paintBackground( QRegion region ) void SceneOpenGL::Texture::init() { damaged = true; + findTarget(); } void SceneOpenGL::Texture::release() { + mTexture = None; } void SceneOpenGL::Texture::findTarget() @@ -163,8 +256,26 @@ void SceneOpenGL::Texture::findTarget() bool SceneOpenGL::Texture::load( const Pixmap& pix, const QSize& size, int depth, QRegion region ) { - // TODO: implement proper - return GLTexture::load(QPixmap::fromX11Pixmap(pix)); + if( mTexture == None ) + { + createTexture(); + bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + const EGLint attribs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE + }; + EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer)pix, attribs); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); + eglDestroyImageKHR( dpy, image ); + unbind(); + checkGLError("load texture"); + } + return true; } void SceneOpenGL::Texture::bind()