Support translucent windows on eglfs

Task-number: QTBUG-39834
Change-Id: I3f6b041c992365d611aa97a41bc37e80b764b78a
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
Laszlo Agocs 2014-06-24 15:05:49 +02:00
parent 33e9aeca7f
commit 7fa584254c
8 changed files with 91 additions and 11 deletions

View File

@ -67,8 +67,10 @@ static const char fragment_shader150[] =
"out vec4 fragcolor;"
"uniform sampler2D textureSampler;"
"uniform bool swizzle;"
"uniform float opacity;"
"void main() {"
" vec4 tmpFragColor = texture(textureSampler, uv);"
" tmpFragColor.a *= opacity;"
" fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
"}";
@ -87,8 +89,10 @@ static const char fragment_shader[] =
"varying highp vec2 uv;"
"uniform sampler2D textureSampler;"
"uniform bool swizzle;"
"uniform highp float opacity;"
"void main() {"
" highp vec4 tmpFragColor = texture2D(textureSampler,uv);"
" tmpFragColor.a *= opacity;"
" gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
"}";
@ -140,6 +144,8 @@ public:
, textureTransformUniformPos(0)
, swizzle(false)
, swizzleOld(false)
, opacity(1.0f)
, opacityOld(0.0f)
, textureMatrixUniformState(User)
, vao(new QOpenGLVertexArrayObject())
{ }
@ -165,6 +171,11 @@ public:
program->setUniformValue(swizzleUniformPos, swizzle);
swizzleOld = swizzle;
}
if (opacity != opacityOld) {
program->setUniformValue(opacityUniformPos, opacity);
opacityOld = opacity;
}
}
QOpenGLBuffer vertexBuffer;
@ -175,8 +186,11 @@ public:
GLuint textureCoordAttribPos;
GLuint textureTransformUniformPos;
GLuint swizzleUniformPos;
GLuint opacityUniformPos;
bool swizzle;
bool swizzleOld;
float opacity;
float opacityOld;
TextureMatrixUniform textureMatrixUniformState;
QScopedPointer<QOpenGLVertexArrayObject> vao;
};
@ -274,6 +288,7 @@ bool QOpenGLTextureBlitter::create()
d->textureCoordAttribPos = d->program->attributeLocation("textureCoord");
d->textureTransformUniformPos = d->program->uniformLocation("textureTransform");
d->swizzleUniformPos = d->program->uniformLocation("swizzle");
d->opacityUniformPos = d->program->uniformLocation("opacity");
d->program->setUniformValue(d->swizzleUniformPos,false);
@ -329,6 +344,12 @@ void QOpenGLTextureBlitter::setSwizzleRB(bool swizzle)
d->swizzle = swizzle;
}
void QOpenGLTextureBlitter::setOpacity(float opacity)
{
Q_D(QOpenGLTextureBlitter);
d->opacity = opacity;
}
void QOpenGLTextureBlitter::blit(GLuint texture,
const QMatrix4x4 &targetTransform,
Origin sourceOrigin)

View File

@ -69,6 +69,7 @@ public:
void release();
void setSwizzleRB(bool swizzle);
void setOpacity(float opacity);
void blit(GLuint texture, const QMatrix4x4 &targetTransform, Origin sourceOrigin);
void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform);

View File

@ -105,6 +105,29 @@ void QEGLCompositor::renderAll()
windows.at(i)->composited();
}
struct BlendStateBinder
{
BlendStateBinder() : m_blend(false) {
glDisable(GL_BLEND);
}
void set(bool blend) {
if (blend != m_blend) {
if (blend) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
}
m_blend = blend;
}
}
~BlendStateBinder() {
if (m_blend)
glDisable(GL_BLEND);
}
bool m_blend;
};
void QEGLCompositor::render(QEGLPlatformWindow *window)
{
const QPlatformTextureList *textures = window->textures();
@ -114,29 +137,37 @@ void QEGLCompositor::render(QEGLPlatformWindow *window)
const QRect targetWindowRect(QPoint(0, 0), window->screen()->geometry().size());
glViewport(0, 0, targetWindowRect.width(), targetWindowRect.height());
float currentOpacity = 1.0f;
BlendStateBinder blend;
for (int i = 0; i < textures->count(); ++i) {
uint textureId = textures->textureId(i);
glBindTexture(GL_TEXTURE_2D, textureId);
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i),
targetWindowRect);
const float opacity = window->window()->opacity();
if (opacity != currentOpacity) {
currentOpacity = opacity;
m_blitter->setOpacity(currentOpacity);
}
if (textures->count() > 1 && i == textures->count() - 1) {
// Backingstore for a widget with QOpenGLWidget subwidgets
m_blitter->setSwizzleRB(true);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
blend.set(true);
m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
glDisable(GL_BLEND);
} else if (textures->count() == 1) {
// A regular QWidget window
m_blitter->setSwizzleRB(true);
const bool translucent = window->window()->requestedFormat().alphaBufferSize() > 0;
blend.set(translucent);
m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
} else {
// Texture from an FBO belonging to a QOpenGLWidget
m_blitter->setSwizzleRB(false);
blend.set(false);
m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft);
}
}
m_blitter->setOpacity(1.0f);
}
QEGLCompositor *QEGLCompositor::instance()

View File

@ -41,6 +41,7 @@
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <QtGui/QPainter>
#include "qeglplatformbackingstore_p.h"
#include "qeglcompositor_p.h"
@ -209,9 +210,16 @@ void QEGLPlatformBackingStore::composited()
}
}
void QEGLPlatformBackingStore::beginPaint(const QRegion &rgn)
void QEGLPlatformBackingStore::beginPaint(const QRegion &region)
{
m_dirty |= rgn;
m_dirty |= region;
if (m_image.hasAlphaChannel()) {
QPainter p(&m_image);
p.setCompositionMode(QPainter::CompositionMode_Source);
foreach (const QRect &r, region.rects())
p.fillRect(r, Qt::transparent);
}
}
void QEGLPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents)
@ -223,7 +231,15 @@ void QEGLPlatformBackingStore::resize(const QSize &size, const QRegion &staticCo
if (!dstWin || (!dstWin->isRaster() && dstWin->window()->surfaceType() != QSurface::RasterGLSurface))
return;
m_image = QImage(size, QImage::Format_RGB32);
// Child windows do not get real native surfaces and so share the same
// format as the parent, regardless of what has been requested. The
// exception is WA_TranslucentBackground that sets alphaBufferSize in the
// requested format, this has to be taken into account when compositing.
const bool translucent = m_window->window()->requestedFormat().alphaBufferSize() > 0;
const QImage::Format format = translucent ? QImage::Format_RGBA8888 : QImage::Format_RGBX8888;
m_image = QImage(size, format);
m_window->create();
screen->compositingContext()->makeCurrent(dstWin->window());

View File

@ -61,7 +61,7 @@ public:
QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
void beginPaint(const QRegion &) Q_DECL_OVERRIDE;
void beginPaint(const QRegion &region) Q_DECL_OVERRIDE;
void flush(QWindow *window, const QRegion &region, const QPoint &offset) Q_DECL_OVERRIDE;
void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE;

View File

@ -127,4 +127,12 @@ WId QEGLPlatformWindow::winId() const
return m_winId;
}
void QEGLPlatformWindow::setOpacity(qreal)
{
if (!isRaster())
qWarning("eglfs: Cannot set opacity for non-raster windows");
// Nothing to do here. The opacity is stored in the QWindow.
}
QT_END_NAMESPACE

View File

@ -64,6 +64,7 @@ public:
bool isRaster() const;
WId winId() const Q_DECL_OVERRIDE;
void setOpacity(qreal opacity) Q_DECL_OVERRIDE;
virtual EGLNativeWindowType eglWindow() const = 0;

View File

@ -82,8 +82,10 @@ void QEglFSWindow::create()
// they will be composited onto the root window's surface.
QEglFSScreen *screen = this->screen();
if (screen->primarySurface() != EGL_NO_SURFACE) {
if (isRaster() && screen->compositingWindow())
if (isRaster() && screen->compositingWindow()) {
m_format = screen->compositingWindow()->format();
return;
}
#if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)
// We can have either a single OpenGL window or multiple raster windows.