Skip to content

Commit

Permalink
MER: eglfs: Allow scaling down the window surface
Browse files Browse the repository at this point in the history
This patch introduces the QT_QPA_EGLFS_SCALE environment variable.
When set to an integer number > 1 it will scale the draws window
content down by that scale factor.

This is only needed for the Sailfish SDK emulator, for now and i'm
not sure this belongs upstream.

(cherry picked from commit 0061edc)
  • Loading branch information
giucam authored and denexter committed Jun 5, 2018
1 parent 92becaf commit d6b2103
Show file tree
Hide file tree
Showing 2 changed files with 253 additions and 1 deletion.
240 changes: 239 additions & 1 deletion src/plugins/platforms/eglfs/api/qeglfscontext.cpp
Expand Up @@ -46,15 +46,226 @@
#include "qeglfswindow_p.h"
#include "qeglfshooks_p.h"
#include "qeglfscursor_p.h"
#include "qeglfsintegration_p.h"

#include <QtGui/QSurface>
#include <QtDebug>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>

QT_BEGIN_NAMESPACE

class Blitter : public QOpenGLFunctions
{
public:
Blitter(QEglFSContext *context)
: m_context(context)
{
initializeOpenGLFunctions();
m_blitProgram = new QOpenGLShaderProgram();
m_blitProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, "attribute vec4 position;\n\
attribute vec2 texCoords;\n\
varying vec2 outTexCoords;\n\
void main()\n\
{\n\
gl_Position = position;\n\
outTexCoords = texCoords;\n\
}");
m_blitProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, "varying highp vec2 outTexCoords;\n\
uniform sampler2D texture;\n\
void main()\n\
{\n\
gl_FragColor = texture2D(texture, outTexCoords);\n\
}");

m_blitProgram->bindAttributeLocation("position", 0);
m_blitProgram->bindAttributeLocation("texCoords", 1);

if (!m_blitProgram->link()) {
qDebug() << "Shader Program link failed.";
qDebug() << m_blitProgram->log();
}
}
~Blitter()
{
delete m_blitProgram;
}
void blit(QOpenGLFramebufferObject *fbo, const QSize &size)
{
glViewport(0, 0, size.width(), size.height());

glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

m_context->m_useNativeDefaultFbo = true;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
m_context->m_useNativeDefaultFbo = false;

static const GLfloat squareVertices[] = {
-1.f, -1.f,
1.0f, -1.f,
-1.f, 1.0f,
1.0f, 1.0f
};

static const GLfloat textureVertices[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};

glBindBuffer(GL_ARRAY_BUFFER, 0);
m_blitProgram->bind();

m_blitProgram->enableAttributeArray(0);
m_blitProgram->enableAttributeArray(1);
m_blitProgram->setAttributeArray(1, textureVertices, 2);

glActiveTexture(GL_TEXTURE0);

//Draw Content
m_blitProgram->setAttributeArray(0, squareVertices, 2);
glBindTexture(GL_TEXTURE_2D, fbo->texture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

//Cleanup
m_blitProgram->disableAttributeArray(0);
m_blitProgram->disableAttributeArray(1);
}

QOpenGLShaderProgram *m_blitProgram;
QEglFSContext *m_context;
};

#define STATE_GUARD_VERTEX_ATTRIB_COUNT 2

class StateGuard
{
public:
StateGuard() {
QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());

glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *) &m_program);
glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &m_activeTextureUnit);
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &m_texture);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &m_fbo);
glGetIntegerv(GL_VIEWPORT, m_viewport);
glGetIntegerv(GL_DEPTH_WRITEMASK, &m_depthWriteMask);
glGetIntegerv(GL_COLOR_WRITEMASK, m_colorWriteMask);
m_blend = glIsEnabled(GL_BLEND);
m_depth = glIsEnabled(GL_DEPTH_TEST);
m_cull = glIsEnabled(GL_CULL_FACE);
m_scissor = glIsEnabled(GL_SCISSOR_TEST);
for (int i = 0; i < STATE_GUARD_VERTEX_ATTRIB_COUNT; ++i) {
glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *) &m_vertexAttribs[i].enabled);
glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *) &m_vertexAttribs[i].arrayBuffer);
glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &m_vertexAttribs[i].size);
glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &m_vertexAttribs[i].stride);
glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *) &m_vertexAttribs[i].type);
glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *) &m_vertexAttribs[i].normalized);
glFuncs.glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &m_vertexAttribs[i].pointer);
}
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint *) &m_minFilter);
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint *) &m_magFilter);
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (GLint *) &m_wrapS);
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (GLint *) &m_wrapT);
}

~StateGuard() {
QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());

glFuncs.glUseProgram(m_program);
glActiveTexture(m_activeTextureUnit);
glBindTexture(GL_TEXTURE_2D, m_texture);
glFuncs.glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glViewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
glDepthMask(m_depthWriteMask);
glColorMask(m_colorWriteMask[0], m_colorWriteMask[1], m_colorWriteMask[2], m_colorWriteMask[3]);
if (m_blend)
glEnable(GL_BLEND);
if (m_depth)
glEnable(GL_DEPTH_TEST);
if (m_cull)
glEnable(GL_CULL_FACE);
if (m_scissor)
glEnable(GL_SCISSOR_TEST);
for (int i = 0; i < STATE_GUARD_VERTEX_ATTRIB_COUNT; ++i) {
if (m_vertexAttribs[i].enabled)
glFuncs.glEnableVertexAttribArray(i);
GLuint prevBuf;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint *) &prevBuf);
glFuncs.glBindBuffer(GL_ARRAY_BUFFER, m_vertexAttribs[i].arrayBuffer);
glFuncs.glVertexAttribPointer(i, m_vertexAttribs[i].size, m_vertexAttribs[i].type,
m_vertexAttribs[i].normalized, m_vertexAttribs[i].stride,
m_vertexAttribs[i].pointer);
glFuncs.glBindBuffer(GL_ARRAY_BUFFER, prevBuf);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
}

private:
GLuint m_program;
GLenum m_activeTextureUnit;
GLuint m_texture;
GLuint m_fbo;
GLint m_depthWriteMask;
GLint m_colorWriteMask[4];
GLboolean m_blend;
GLboolean m_depth;
GLboolean m_cull;
GLboolean m_scissor;
GLint m_viewport[4];
struct VertexAttrib {
bool enabled;
GLuint arrayBuffer;
GLint size;
GLint stride;
GLenum type;
bool normalized;
void *pointer;
} m_vertexAttribs[STATE_GUARD_VERTEX_ATTRIB_COUNT];
GLenum m_minFilter;
GLenum m_magFilter;
GLenum m_wrapS;
GLenum m_wrapT;
};

QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
EGLConfig *config, const QVariant &nativeHandle)
: QEGLPlatformContext(format, share, display, config, nativeHandle,
qt_egl_device_integration()->supportsSurfacelessContexts() ? Flags(0) : QEGLPlatformContext::NoSurfaceless),
m_tempWindow(0)
m_tempWindow(0),
m_useNativeDefaultFbo(false),
m_fbo(0),
m_blitter(0)
{
m_scale = qgetenv("QT_QPA_EGLFS_SCALE").toInt();
}

QEglFSContext::~QEglFSContext()
{
delete m_blitter;
delete m_fbo;
}

bool QEglFSContext::makeCurrent(QPlatformSurface *surface)
{
bool success = QEGLPlatformContext::makeCurrent(surface);

if (m_scale > 1)
fbo(surface)->bind();

return success;
}

EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
Expand Down Expand Up @@ -104,6 +315,16 @@ void QEglFSContext::runGLChecks()

void QEglFSContext::swapBuffers(QPlatformSurface *surface)
{
if (m_scale > 1) {
// Must save & restore all state. Applications are usually not prepared
// for random context state changes in a swapBuffers() call.
StateGuard stateGuard;

if (!m_blitter)
m_blitter = new Blitter(this);
m_blitter->blit(m_fbo, surface->surface()->size() / m_scale);
}

// draw the cursor
if (surface->surface()->surfaceClass() == QSurface::Window) {
QPlatformWindow *window = static_cast<QPlatformWindow *>(surface);
Expand All @@ -116,4 +337,21 @@ void QEglFSContext::swapBuffers(QPlatformSurface *surface)
qt_egl_device_integration()->presentBuffer(surface);
}

QOpenGLFramebufferObject *QEglFSContext::fbo(QPlatformSurface *surface) const
{
QSize size = surface->surface()->size();
if (!m_fbo || m_fbo->size() != size) {
delete m_fbo;
m_fbo = new QOpenGLFramebufferObject(size);
}
return m_fbo;
}

GLuint QEglFSContext::defaultFramebufferObject(QPlatformSurface *surface) const
{
if (m_useNativeDefaultFbo || m_scale <= 1)
return 0;
return fbo(surface)->handle();
}

QT_END_NAMESPACE
14 changes: 14 additions & 0 deletions src/plugins/platforms/eglfs/api/qeglfscontext_p.h
Expand Up @@ -58,21 +58,35 @@

QT_BEGIN_NAMESPACE

class QOpenGLFramebufferObject;
class Blitter;

class Q_EGLFS_EXPORT QEglFSContext : public QEGLPlatformContext
{
public:
QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
EGLConfig *config, const QVariant &nativeHandle);
~QEglFSContext();
bool makeCurrent(QPlatformSurface *surface) override;
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override;
EGLSurface createTemporaryOffscreenSurface() override;
void destroyTemporaryOffscreenSurface(EGLSurface surface) override;
void runGLChecks() override;
void swapBuffers(QPlatformSurface *surface) override;
GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;

QEglFSCursorData cursorData;

private:
QOpenGLFramebufferObject *fbo(QPlatformSurface *surface) const;

EGLNativeWindowType m_tempWindow;
bool m_useNativeDefaultFbo;
mutable QOpenGLFramebufferObject *m_fbo;
Blitter *m_blitter;
int m_scale;

friend class Blitter;
};

QT_END_NAMESPACE
Expand Down

0 comments on commit d6b2103

Please sign in to comment.