void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion,
const QPoint &offset,
QPlatformTextureList *textures, QOpenGLContext *context,
bool translucentBackground)
{
if (!qt_window_private(window)->receivedExpose)
return;
if (!context->makeCurrent(window)) {
qWarning("composeAndFlush: makeCurrent() failed");
return;
}
QWindowPrivate::get(window)->lastComposeTime.start();
QOpenGLFunctions *funcs = context->functions();
funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio());
funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
funcs->glClear(GL_COLOR_BUFFER_BIT);
if (!d_ptr->blitter) {
d_ptr->blitter = new QOpenGLTextureBlitter;
d_ptr->blitter->create();
}
d_ptr->blitter->bind();
const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window);
// Textures for renderToTexture widgets.
for (int i = 0; i < textures->count(); ++i) {
if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
/*1*/ blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset);
}
// Backingstore texture with the normal widgets.
GLuint textureId = 0;
QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft;
if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) {
if (graphicsBuffer->size() != d_ptr->textureSize) {
if (d_ptr->textureId)
funcs->glDeleteTextures(1, &d_ptr->textureId);
funcs->glGenTextures(1, &d_ptr->textureId);
funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
}
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle, &d_ptr->premultiplied)) {
d_ptr->textureSize = graphicsBuffer->size();
} else {
d_ptr->textureSize = QSize(0,0);
}
graphicsBuffer->unlock();
} else if (!region.isEmpty()){
funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
/*2*/ QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle,
&d_ptr->premultiplied); }
if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
origin = QOpenGLTextureBlitter::OriginBottomLeft;
textureId = d_ptr->textureId;
} else {
TextureFlags flags = 0;
textureId = toTexture(deviceRegion(region, window, offset), &d_ptr->textureSize, &flags);
d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0;
d_ptr->premultiplied = (flags & TexturePremultiplied) != 0;
if (flags & TextureFlip)
origin = QOpenGLTextureBlitter::OriginBottomLeft;
}
funcs->glEnable(GL_BLEND);
if (d_ptr->premultiplied)
funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
else
funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
if (textureId) {
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(true);
// The backingstore is for the entire tlw.
// In case of native children offset tells the position relative to the tlw.
const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(offset), d_ptr->textureSize.height());
const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect,
d_ptr->textureSize,
origin);
d_ptr->blitter->blit(textureId, QMatrix4x4(), source);
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(false);
}
// Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
for (int i = 0; i < textures->count(); ++i) {
if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset);
}
funcs->glDisable(GL_BLEND);
d_ptr->blitter->release();
context->swapBuffers(window);
}
bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer,
bool *swizzleRandB, bool *premultipliedB,
const QRect &subRect)
{
#ifndef QT_NO_OPENGL
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!ctx)
return false;
if (!(graphicsBuffer->isLocked() & QPlatformGraphicsBuffer::SWReadAccess))
return false;
QSize size = graphicsBuffer->size();
Q_ASSERT(subRect.isEmpty() || QRect(QPoint(0,0), size).contains(subRect));
GLenum internalFormat = GL_RGBA;
GLuint pixelType = GL_UNSIGNED_BYTE;
bool needsConversion = false;
bool swizzle = false;
bool premultiplied = false;
QImage::Format imageformat = QImage::toImageFormat(graphicsBuffer->format());
QImage image(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), imageformat);
if (graphicsBuffer->bytesPerLine() != (size.width() * 4)) {
needsConversion = true;
} else {
switch (imageformat) {
case QImage::Format_ARGB32_Premultiplied:
premultiplied = true;
// no break
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
swizzle = true;
break;
case QImage::Format_RGBA8888_Premultiplied:
premultiplied = true;
// no break
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
break;
case QImage::Format_BGR30:
case QImage::Format_A2BGR30_Premultiplied:
if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
internalFormat = GL_RGB10_A2;
premultiplied = true;
} else {
needsConversion = true;
}
break;
case QImage::Format_RGB30:
case QImage::Format_A2RGB30_Premultiplied:
if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
internalFormat = GL_RGB10_A2;
premultiplied = true;
swiz5zle = true;
} else {
needsConversion = true;
}
break;
default:
needsConversion = true;
break;
}
}
if (needsConversion)
image = image.convertToFormat(QImage::Format_RGBA8888);
QOpenGLFunctions *funcs = ctx->functions();
QRect rect = subRect;
if (rect.isNull() || rect == QRect(QPoint(0,0),size)) {
funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.width(), size.height(), 0, GL_RGBA, pixelType, image.constBits());
} else {
#ifndef QT_OPENGL_ES_2
if (!ctx->isOpenGLES()) {
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width());
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
image.constScanLine(rect.y()) + rect.x() * 4);
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} else
#endif
{
// if the rect is wide enough it's cheaper to just
// extend it instead of doing an image copy
if (rect.width() >= size.width() / 2) {
rect.setX(0);
rect.setWidth(size.width());
}
// if the sub-rect is full-width we can pass the image data directly to
// OpenGL instead of copying, since there's no gap between scanlines
if (rect.width() == size.width()) {
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
image.constScanLine(rect.y()));
} else {
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
image.copy(rect).constBits());
}
}
}
if (swizzleRandB)
*swizzleRandB = swizzle;
if (premultipliedB)
*premultipliedB = premultiplied;
return true;
#else
Q_UNUSED(graphicsBuffer)
Q_UNUSED(swizzleRandB)
Q_UNUSED(premultipliedB)
Q_UNUSED(subRect)
return false;
#endif // QT_NO_OPENGL
}
July 2009 August 2009 September 2009 October 2009 November 2009 December 2009 January 2010 September 2010 December 2010 January 2011 February 2011 April 2011 June 2011 August 2011 February 2012 June 2012 July 2012 August 2012 October 2012 November 2012 January 2014 April 2014 June 2014 August 2014 September 2014 October 2014 January 2015 March 2015 April 2015 June 2015 November 2015 December 2015 January 2016 June 2016 August 2016 January 2017 March 2017 April 2018 April 2019 June 2019 January 2020
Subscribe to Posts [Atom]