summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorAndrew Knight <andrew.knight@digia.com>2014-08-05 23:21:54 +0300
committerAndrew Knight <andrew.knight@digia.com>2014-08-07 08:47:41 +0200
commitc7abf81786f4a0c6940fd606ea32621be7f32a56 (patch)
treecb57fa4da3db0d6f691ad5bd4f310b35b010464f /src/plugins/platforms
parent1a9701fe81c39450822c0d4b51c11444380a2fe4 (diff)
winrt: Refactor backing store
Thanks to new features in ANGLE, the backing store implementation complexity can be greatly reduced. By using ES3 framebuffer blit, no shader code is required, and the shader loading code and blit shader can be removed. Change-Id: Iab3d915e279ad6468a75ef6257794f12acd8cb65 Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/winrt/blit.hlsl14
-rw-r--r--src/plugins/platforms/winrt/qwinrtbackingstore.cpp359
-rw-r--r--src/plugins/platforms/winrt/qwinrtbackingstore.h16
-rw-r--r--src/plugins/platforms/winrt/winrt.pro19
4 files changed, 82 insertions, 326 deletions
diff --git a/src/plugins/platforms/winrt/blit.hlsl b/src/plugins/platforms/winrt/blit.hlsl
deleted file mode 100644
index 170e7f40ca..0000000000
--- a/src/plugins/platforms/winrt/blit.hlsl
+++ /dev/null
@@ -1,14 +0,0 @@
-uniform SamplerState Sampler : register(s0);
-uniform Texture2D Texture : register(t0);
-
-void blitvs(in float4 pos0 : TEXCOORD0, in float2 tex0 : TEXCOORD1,
- out float4 gl_Position : SV_POSITION, out float2 coord : TEXCOORD0)
-{
- coord = tex0;
- gl_Position = pos0 * float4(1.0, -1.0, 1.0, 1.0);
-}
-
-float4 blitps(in float4 gl_Position : SV_POSITION, in float2 coord : TEXCOORD0) : SV_TARGET0
-{
- return Texture.Sample(Sampler, coord);
-}
diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
index b8418eef6a..7475965d11 100644
--- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
+++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
@@ -45,343 +45,136 @@
#include "qwinrtwindow.h"
#include "qwinrteglcontext.h"
#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFramebufferObject>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
-// Generated shader headers
-#include "blitps.h"
-#include "blitvs.h"
-
-namespace { // Utility namespace for writing out an ANGLE-compatible binary blob
-
-// Must match packaged ANGLE
-enum : quint32 {
- AngleMajorVersion = 1,
- AngleMinorVersion = 3
-};
-
-struct ShaderString
-{
- ShaderString(const char *data = 0) : data(data) { }
- const char *data;
-};
-
-// ANGLE stream compatibility - when size_t is 32-bit, QDataStream::writeBytes() also works
-QDataStream &operator<<(QDataStream &stream, const ShaderString &shaderString)
-{
- if (!shaderString.data)
- return stream << size_t(0);
-
- size_t len = strlen(shaderString.data);
- stream << len;
- stream.writeRawData(shaderString.data, int(len));
- return stream;
-}
-
-struct Attribute
-{
- Attribute(GLenum type = 0, const char *name = 0, quint32 index = 0)
- : type(type), name(name), index(index) { }
- GLenum type;
- ShaderString name;
- quint32 index;
-};
-
-struct Sampler
-{
- enum TextureType { Texture2D, TextureCube };
- Sampler(bool active = false, GLint unit = 0, TextureType type = Texture2D)
- : active(active), unit(unit), type(type) { }
- bool active;
- GLint unit;
- TextureType type;
-};
-
-struct Uniform
-{
- Uniform() { }
- Uniform(GLenum type, quint32 precision, const char *name, quint32 arraySize,
- quint32 psRegisterIndex, quint32 vsRegisterIndex, quint32 registerCount)
- : type(type), precision(precision), name(name), arraySize(arraySize)
- , psRegisterIndex(psRegisterIndex), vsRegisterIndex(vsRegisterIndex), registerCount(registerCount) { }
- GLenum type;
- quint32 precision;
- ShaderString name;
- quint32 arraySize;
- quint32 psRegisterIndex;
- quint32 vsRegisterIndex;
- quint32 registerCount;
-};
+QT_BEGIN_NAMESPACE
-struct UniformIndex
+class QWinRTBackingStorePrivate
{
- UniformIndex(const char *name = 0, quint32 element = 0, quint32 index = 0)
- : name(name), element(element), index(index) { }
- ShaderString name;
- quint32 element;
- quint32 index;
+public:
+ bool initialized;
+ QSize size;
+ QScopedPointer<QOpenGLContext> context;
+ QScopedPointer<QOpenGLFramebufferObject> fbo;
+ QWinRTScreen *screen;
+ QImage paintDevice;
};
-static const QByteArray createAngleBinary(
- const QVector<Attribute> &attributes,
- const QVector<Sampler> &textureSamplers,
- const QVector<Sampler> &vertexSamplers,
- const QVector<Uniform> &uniforms,
- const QVector<UniformIndex> &uniformIndex,
- const QByteArray &pixelShader,
- const QByteArray &vertexShader,
- const QByteArray &geometryShader = QByteArray(),
- bool usesPointSize = false)
+QWinRTBackingStore::QWinRTBackingStore(QWindow *window)
+ : QPlatformBackingStore(window), d_ptr(new QWinRTBackingStorePrivate)
{
- QByteArray binary;
-
- QDataStream stream(&binary, QIODevice::WriteOnly);
- stream.setByteOrder(QDataStream::LittleEndian);
-
- stream << quint32(GL_PROGRAM_BINARY_ANGLE)
- << qint32(AngleMajorVersion)
- << qint32(AngleMinorVersion);
-
- // Vertex attributes
- for (int i = 0; i < 16; ++i) {
- if (i < attributes.size())
- stream << quint32(attributes[i].type) << attributes[i].name << attributes[i].index;
- else
- stream << quint32(GL_NONE) << ShaderString() << qint32(-1);
- }
-
- // Texture units
- for (int i = 0; i < 16; ++i) {
- if (i < textureSamplers.size())
- stream << textureSamplers[i].active << textureSamplers[i].unit << qint32(textureSamplers[i].type);
- else
- stream << false << qint32(0) << qint32(Sampler::Texture2D);
- }
-
- // Vertex texture units
- for (int i = 0; i < 16; ++i) {
- if (i < vertexSamplers.size())
- stream << vertexSamplers[i].active << vertexSamplers[i].unit << qint32(vertexSamplers[i].type);
- else
- stream << false << qint32(0) << qint32(Sampler::Texture2D);
- }
-
- stream << vertexSamplers.size()
- << textureSamplers.size()
- << usesPointSize;
-
- stream << size_t(uniforms.size());
- foreach (const Uniform &uniform, uniforms) {
- stream << uniform.type << uniform.precision << uniform.name << uniform.arraySize
- << uniform.psRegisterIndex << uniform.vsRegisterIndex << uniform.registerCount;
- }
-
- stream << size_t(uniformIndex.size());
- foreach (const UniformIndex &index, uniformIndex)
- stream << index.name << index.element << index.index;
-
- stream << quint32(pixelShader.size())
- << quint32(vertexShader.size())
- << quint32(geometryShader.size());
-
- stream.writeRawData(pixelShader.constData(), pixelShader.size());
- stream.writeRawData(vertexShader.constData(), vertexShader.size());
- if (!geometryShader.isEmpty())
- stream.writeRawData(geometryShader.constData(), geometryShader.size());
-
- return binary;
-}
-
-} // namespace
-
-QT_BEGIN_NAMESPACE
+ Q_D(QWinRTBackingStore);
-static const GLfloat normCoords[] = { -1, 1, 1, 1, 1, -1, -1, -1 };
-static const GLfloat quadCoords[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
+ d->initialized = false;
+ d->screen = static_cast<QWinRTScreen*>(window->screen()->handle());
-QWinRTBackingStore::QWinRTBackingStore(QWindow *window)
- : QPlatformBackingStore(window)
- , m_context(new QOpenGLContext)
- , m_shaderProgram(0)
- , m_fbo(0)
- , m_texture(0)
- , m_screen(static_cast<QWinRTScreen*>(window->screen()->handle()))
- , m_initialized(false)
-{
window->setSurfaceType(QSurface::OpenGLSurface); // Required for flipping, but could be done in the swap
}
bool QWinRTBackingStore::initialize()
{
- if (m_initialized)
+ Q_D(QWinRTBackingStore);
+
+ if (d->initialized)
return true;
- m_context->setFormat(window()->requestedFormat());
- m_context->setScreen(window()->screen());
- if (!m_context->create())
+ d->context.reset(new QOpenGLContext);
+ QSurfaceFormat format = window()->requestedFormat();
+ format.setVersion(3, 0); // Required for ES3 framebuffer blit
+ d->context->setFormat(format);
+ d->context->setScreen(window()->screen());
+ if (!d->context->create())
return false;
- if (!m_context->makeCurrent(window()))
+ if (!d->context->makeCurrent(window()))
return false;
- glGenFramebuffers(1, &m_fbo);
- glGenRenderbuffers(1, &m_rbo);
- glGenTextures(1, &m_texture);
- m_shaderProgram = glCreateProgram();
-
-#if 0 // Standard GLES passthrough shader program
- static const char *vertexShaderSource =
- "attribute vec4 pos0;\n"
- "attribute vec2 tex0;\n"
- "varying vec2 coord;\n"
- "void main() {\n"
- " coord = tex0;\n"
- " gl_Position = pos0;\n"
- "}\n";
- static const char *fragmentShaderSource =
- "uniform sampler2D texture;\n"
- "varying highp vec2 coord;\n"
- "void main() {\n"
- " gl_FragColor = texture2D(texture, coord);\n"
- "}\n";
- GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
- glCompileShader(vertexShader);
- GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
- glCompileShader(fragmentShader);
- glAttachShader(m_shaderProgram, vertexShader);
- glAttachShader(m_shaderProgram, fragmentShader);
- glLinkProgram(m_shaderProgram);
-#else // Precompiled passthrough shader
- QVector<Attribute> attributes = QVector<Attribute>() << Attribute(GL_FLOAT_VEC4, "pos0", 0)
- << Attribute(GL_FLOAT_VEC2, "tex0", 1);
- QVector<Sampler> textureSamplers = QVector<Sampler>() << Sampler(true, 0, Sampler::Texture2D);
- QVector<Sampler> vertexSamplers;
- QVector<Uniform> uniforms = QVector<Uniform>() << Uniform(GL_SAMPLER_2D, 0, "texture", 0, 0, -1, 1);
- QVector<UniformIndex> uniformsIndex = QVector<UniformIndex>() << UniformIndex("texture", 0, 0);
- QByteArray pixelShader(reinterpret_cast<const char *>(q_blitps), sizeof(q_blitps));
- QByteArray vertexShader(reinterpret_cast<const char *>(q_blitvs), sizeof(q_blitvs));
- QByteArray binary = createAngleBinary(attributes, textureSamplers, vertexSamplers,
- uniforms, uniformsIndex, pixelShader, vertexShader);
- glProgramBinaryOES(m_shaderProgram, GL_PROGRAM_BINARY_ANGLE, binary.constData(), binary.size());
-#endif
- m_context->doneCurrent();
- m_initialized = true;
+ d->context->doneCurrent();
+ d->initialized = true;
return true;
}
QWinRTBackingStore::~QWinRTBackingStore()
{
- if (!m_initialized)
- return;
- glDeleteBuffers(1, &m_fbo);
- glDeleteRenderbuffers(1, &m_rbo);
- glDeleteTextures(1, &m_texture);
- glDeleteProgram(m_shaderProgram);
}
QPaintDevice *QWinRTBackingStore::paintDevice()
{
- return &m_paintDevice;
+ Q_D(QWinRTBackingStore);
+ return &d->paintDevice;
}
void QWinRTBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
+ Q_D(QWinRTBackingStore);
Q_UNUSED(offset)
- if (m_size.isEmpty())
+
+ if (d->size.isEmpty())
return;
- m_context->makeCurrent(window);
-
- // Blitting the entire image width trades zero image copy/relayout for a larger texture upload.
- // Since we're blitting the whole width anyway, the boundingRect() is used in the assumption that
- // we don't repeat upload. This is of course dependent on the distance between update regions.
- // Ideally, we would use the GL_EXT_unpack_subimage extension, which should be possible to implement
- // since D3D11_MAPPED_SUBRESOURCE supports RowPitch (see below).
- // Note that single-line blits in a loop are *very* slow, so reducing calls to glTexSubImage2D
- // is probably a good idea anyway.
- glBindTexture(GL_TEXTURE_2D, m_texture);
- QRect bounds = region.boundingRect();
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), m_size.width(), bounds.height(),
- GL_BGRA_EXT, GL_UNSIGNED_BYTE, m_paintDevice.constScanLine(bounds.y()));
- // TODO: Implement GL_EXT_unpack_subimage in ANGLE for more minimal uploads
- //glPixelStorei(GL_UNPACK_ROW_LENGTH, image->bytesPerLine());
- //glTexSubImage2D(GL_TEXTURE_2D, 0, bounds.x(), bounds.y(), bounds.width(), bounds.height(),
- // GL_BGRA_EXT, GL_UNSIGNED_BYTE, image->scanLine(bounds.y()) + bounds.x() * 4);
-
- // Bind render buffer
- glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
-
- // Bind position
- glUseProgram(m_shaderProgram);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, normCoords);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, quadCoords);
-
- // Render
- const QSize blitSize = m_size * window->devicePixelRatio();
- glViewport(0, 0, blitSize.width(), blitSize.height());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- // Unbind
- glDisableVertexAttribArray(0);
- glDisableVertexAttribArray(1);
- glUseProgram(0);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glBindTexture(GL_TEXTURE_2D, 0);
+ const bool ok = d->context->makeCurrent(window);
+ if (!ok)
+ qWarning("unable to flush");
- // fast blit - TODO: perform the blit inside swap buffers instead
- glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_fbo);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0);
- glBlitFramebufferANGLE(0, 0, blitSize.width(), blitSize.height(), // TODO: blit only the changed rectangle
- 0, 0, blitSize.width(), blitSize.height(),
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ const QRect bounds = region.boundingRect();
+ glBindTexture(GL_TEXTURE_2D, d->fbo->texture());
+ // TODO: when ANGLE GLES3 support is finished, use the glPixelStorei functions to minimize upload
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), d->size.width(), bounds.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE, d->paintDevice.constScanLine(bounds.y()));
+ glBindTexture(GL_TEXTURE_2D, 0);
- m_context->swapBuffers(window);
- m_context->doneCurrent();
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, d->fbo->handle());
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ const int y1 = bounds.height() + bounds.y();
+ const int y2 = d->size.height() - y1;
+ const int x1 = bounds.x();
+ const int x2 = x1 + bounds.width();
+ glBlitFramebuffer(x1, y2, x2, y1,
+ x1, y1, x2, y2,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ d->context->swapBuffers(window);
+ d->context->doneCurrent();
}
void QWinRTBackingStore::resize(const QSize &size, const QRegion &staticContents)
{
+ Q_D(QWinRTBackingStore);
Q_UNUSED(staticContents)
+
if (!initialize())
return;
- if (m_size == size)
+ if (d->size == size)
return;
- m_size = size;
- if (m_size.isEmpty())
+ d->size = size;
+ if (d->size.isEmpty())
return;
- m_paintDevice = QImage(m_size, QImage::Format_ARGB32_Premultiplied);
-
- m_context->makeCurrent(window());
- // Input texture
- glBindTexture(GL_TEXTURE_2D, m_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, m_size.width(), m_size.height(),
- 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glBindTexture(GL_TEXTURE_2D, 0);
- // Render buffer
- glBindRenderbuffer(GL_RENDERBUFFER, m_rbo);
- const QSize blitSize = m_size * window()->devicePixelRatio();
- glRenderbufferStorage(GL_RENDERBUFFER, GL_BGRA8_EXT, blitSize.width(), blitSize.height());
- glBindRenderbuffer(GL_RENDERBUFFER, 0);
- m_context->doneCurrent();
+ d->paintDevice = QImage(d->size, QImage::Format_RGBA8888_Premultiplied);
+
+ const bool ok = d->context->makeCurrent(window());
+ if (!ok)
+ qWarning("unable to resize");
+
+ d->fbo.reset(new QOpenGLFramebufferObject(d->size));
+
+ d->context->doneCurrent();
+}
+
+QImage QWinRTBackingStore::toImage() const
+{
+ Q_D(const QWinRTBackingStore);
+ return d->paintDevice;
}
void QWinRTBackingStore::beginPaint(const QRegion &region)
{
- Q_UNUSED(region)
- resize(window()->size(), QRegion());
+ resize(window()->size(), region);
}
void QWinRTBackingStore::endPaint()
diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.h b/src/plugins/platforms/winrt/qwinrtbackingstore.h
index f00fa85a26..40728559f7 100644
--- a/src/plugins/platforms/winrt/qwinrtbackingstore.h
+++ b/src/plugins/platforms/winrt/qwinrtbackingstore.h
@@ -48,8 +48,8 @@
QT_BEGIN_NAMESPACE
class QWinRTScreen;
-class QOpenGLContext;
+class QWinRTBackingStorePrivate;
class QWinRTBackingStore : public QPlatformBackingStore
{
public:
@@ -60,19 +60,13 @@ public:
void endPaint();
void flush(QWindow *window, const QRegion &region, const QPoint &offset);
void resize(const QSize &size, const QRegion &staticContents);
- QImage toImage() const Q_DECL_OVERRIDE { return m_paintDevice; }
+ QImage toImage() const Q_DECL_OVERRIDE;
private:
bool initialize();
- bool m_initialized;
- QSize m_size;
- QScopedPointer<QOpenGLContext> m_context;
- quint32 m_shaderProgram;
- quint32 m_fbo;
- quint32 m_rbo;
- quint32 m_texture;
- QWinRTScreen *m_screen;
- QImage m_paintDevice;
+
+ QScopedPointer<QWinRTBackingStorePrivate> d_ptr;
+ Q_DECLARE_PRIVATE(QWinRTBackingStore)
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 427920a670..214ac0e154 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -56,26 +56,9 @@ HEADERS = \
qwinrttheme.h \
qwinrtwindow.h
-
-BLIT_INPUT = $$PWD/blit.hlsl
-fxc_blitps.commands = fxc.exe /nologo /T ps_4_0_level_9_1 /E blitps /Vn q_blitps /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
-fxc_blitps.output = $$OUT_PWD/blitps.h
-fxc_blitps.input = BLIT_INPUT
-fxc_blitps.dependency_type = TYPE_C
-fxc_blitps.variable_out = HEADERS
-fxc_blitps.CONFIG += target_predeps
-fxc_blitvs.commands = fxc.exe /nologo /T vs_4_0_level_9_1 /E blitvs /Vn q_blitvs /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
-fxc_blitvs.output = $$OUT_PWD/blitvs.h
-fxc_blitvs.input = BLIT_INPUT
-fxc_blitvs.dependency_type = TYPE_C
-fxc_blitvs.variable_out = HEADERS
-fxc_blitvs.CONFIG += target_predeps
-QMAKE_EXTRA_COMPILERS += fxc_blitps fxc_blitvs
-
winphone:equals(WINSDK_VER, 8.0): {
SOURCES -= qwinrtplatformmessagedialoghelper.cpp
HEADERS -= qwinrtplatformmessagedialoghelper.h
}
-OTHER_FILES += winrt.json \
- blit.hlsl
+OTHER_FILES += winrt.json