Improved and made public the QOpenGLPaintDevice API.
The new API is more flexible, allowing the use of QOpenGLPaintDevice with any QOpenGLContext, and putting more responsibility on the user for ensuring the correct FBO is current (the user knows best anyhow). Task-number: QTBUG-21263 Change-Id: I50b954125f552baef52fbb3fe2ed907a11ad519c Reviewed-on: http://codereview.qt-project.org/4325 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Paul Olav Tvete <paul.tvete@nokia.com>bb10
parent
68974d8e64
commit
1b18315001
|
|
@ -12,10 +12,6 @@ int main(int argc, char **argv)
|
|||
|
||||
QRect screenGeometry = screen->availableGeometry();
|
||||
|
||||
QSurfaceFormat format;
|
||||
format.setDepthBufferSize(16);
|
||||
format.setSamples(4);
|
||||
|
||||
QPoint center = screenGeometry.center();
|
||||
QRect windowRect(0, 0, 640, 480);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#include "paintedwindow.h"
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLPaintDevice>
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
#include <qmath.h>
|
||||
|
||||
PaintedWindow::PaintedWindow()
|
||||
: m_fbo(0)
|
||||
{
|
||||
QSurfaceFormat format;
|
||||
format.setStencilBufferSize(8);
|
||||
format.setSamples(4);
|
||||
|
||||
setSurfaceType(QWindow::OpenGLSurface);
|
||||
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
|
||||
|
|
@ -22,103 +22,32 @@ PaintedWindow::PaintedWindow()
|
|||
m_context = new QOpenGLContext(this);
|
||||
m_context->setFormat(format);
|
||||
m_context->create();
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
timer->setInterval(16);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(paint()));
|
||||
timer->start();
|
||||
|
||||
m_context->makeCurrent(this);
|
||||
|
||||
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
|
||||
const char *vsrc =
|
||||
"attribute highp vec2 vertexCoordsInput;\n"
|
||||
"attribute mediump vec2 texCoordsInput;\n"
|
||||
"varying mediump vec2 texCoords;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" texCoords = texCoordsInput;\n"
|
||||
" gl_Position = vec4(vertexCoordsInput, 0, 1);\n"
|
||||
"}\n";
|
||||
vshader->compileSourceCode(vsrc);
|
||||
|
||||
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
|
||||
const char *fsrc =
|
||||
"uniform sampler2D tex;\n"
|
||||
"varying mediump vec2 texCoords;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" gl_FragColor = texture2D(tex, texCoords);\n"
|
||||
"}\n";
|
||||
fshader->compileSourceCode(fsrc);
|
||||
|
||||
m_program = new QOpenGLShaderProgram;
|
||||
m_program->addShader(vshader);
|
||||
m_program->addShader(fshader);
|
||||
m_program->link();
|
||||
|
||||
m_vertexAttribute = m_program->attributeLocation("vertexCoordsInput");
|
||||
m_texCoordsAttribute = m_program->attributeLocation("texCoordsInput");
|
||||
}
|
||||
|
||||
void PaintedWindow::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
m_context->makeCurrent(this);
|
||||
paint();
|
||||
}
|
||||
|
||||
delete m_fbo;
|
||||
m_fbo = new QOpenGLFramebufferObject(size());
|
||||
void PaintedWindow::exposeEvent(QExposeEvent *)
|
||||
{
|
||||
paint();
|
||||
}
|
||||
|
||||
void PaintedWindow::paint()
|
||||
{
|
||||
if (!m_fbo)
|
||||
return;
|
||||
|
||||
m_context->makeCurrent(this);
|
||||
|
||||
QPainterPath path;
|
||||
path.addEllipse(0, 0, m_fbo->width(), m_fbo->height());
|
||||
path.addEllipse(0, 0, width(), height());
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(m_fbo);
|
||||
painter.fillRect(0, 0, m_fbo->width(), m_fbo->height(), Qt::white);
|
||||
QOpenGLPaintDevice device(size());
|
||||
|
||||
QPainter painter(&device);
|
||||
painter.fillRect(0, 0, width(), height(), Qt::white);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.fillPath(path, Qt::blue);
|
||||
painter.end();
|
||||
|
||||
glViewport(0, 0, width(), height());
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
GLfloat texCoords[] = { 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 1, 1, 0, 1 };
|
||||
|
||||
GLfloat vertexCoords[] = { -1, -1, 1, -1, -1, 1,
|
||||
1, -1, 1, 1, -1, 1 };
|
||||
|
||||
m_program->bind();
|
||||
|
||||
m_context->functions()->glEnableVertexAttribArray(m_vertexAttribute);
|
||||
m_context->functions()->glEnableVertexAttribArray(m_texCoordsAttribute);
|
||||
|
||||
m_context->functions()->glVertexAttribPointer(m_vertexAttribute, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
|
||||
m_context->functions()->glVertexAttribPointer(m_texCoordsAttribute, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
m_context->functions()->glDisableVertexAttribArray(m_vertexAttribute);
|
||||
m_context->functions()->glDisableVertexAttribArray(m_texCoordsAttribute);
|
||||
|
||||
m_program->release();
|
||||
|
||||
m_context->swapBuffers(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,7 @@ private slots:
|
|||
|
||||
private:
|
||||
void resizeEvent(QResizeEvent *);
|
||||
void exposeEvent(QExposeEvent *);
|
||||
|
||||
QOpenGLContext *m_context;
|
||||
QOpenGLFramebufferObject *m_fbo;
|
||||
QOpenGLShaderProgram *m_program;
|
||||
|
||||
GLuint m_vertexAttribute;
|
||||
GLuint m_texCoordsAttribute;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ HEADERS += opengl/qopengl.h \
|
|||
opengl/qopenglfunctions.h \
|
||||
opengl/qopenglframebufferobject.h \
|
||||
opengl/qopenglframebufferobject_p.h \
|
||||
opengl/qopenglpaintdevice_p.h \
|
||||
opengl/qopenglpaintdevice.h \
|
||||
opengl/qopenglbuffer.h \
|
||||
opengl/qopenglshaderprogram.h \
|
||||
opengl/qopenglextensions_p.h \
|
||||
|
|
|
|||
|
|
@ -80,26 +80,6 @@ private:
|
|||
QVector<int> m_offsets;
|
||||
};
|
||||
|
||||
// this is a class that wraps a QThreadStorage object for storing
|
||||
// thread local instances of the GL 1 and GL 2 paint engines
|
||||
|
||||
class QPaintEngine;
|
||||
|
||||
template <class T>
|
||||
class QOpenGLEngineThreadStorage
|
||||
{
|
||||
public:
|
||||
QPaintEngine *engine() {
|
||||
QPaintEngine *&localEngine = storage.localData();
|
||||
if (!localEngine)
|
||||
localEngine = new T;
|
||||
return localEngine;
|
||||
}
|
||||
|
||||
private:
|
||||
QThreadStorage<QPaintEngine *> storage;
|
||||
};
|
||||
|
||||
class QOpenGLTexture : public QOpenGLSharedResource {
|
||||
public:
|
||||
QOpenGLTexture(QOpenGLContext *ctx, GLuint id, bool inverted)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include <private/qopenglcontext_p.h>
|
||||
#include <private/qopenglextensions_p.h>
|
||||
#include <private/qfont_p.h>
|
||||
#include <private/qopenglpaintengine_p.h>
|
||||
|
||||
#include <qwindow.h>
|
||||
#include <qlibrary.h>
|
||||
|
|
@ -314,41 +313,6 @@ bool QOpenGLFramebufferObjectFormat::operator!=(const QOpenGLFramebufferObjectFo
|
|||
return !(*this == other);
|
||||
}
|
||||
|
||||
void QOpenGLFBOGLPaintDevice::setFBO(QOpenGLFramebufferObject* f,
|
||||
QOpenGLFramebufferObject::Attachment attachment)
|
||||
{
|
||||
fbo = f;
|
||||
m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed
|
||||
|
||||
// The context that the fbo was created in may not have depth
|
||||
// and stencil buffers, but the fbo itself might.
|
||||
fboFormat = QOpenGLContext::currentContext()->format();
|
||||
if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil) {
|
||||
fboFormat.setDepthBufferSize(24);
|
||||
fboFormat.setStencilBufferSize(8);
|
||||
} else if (attachment == QOpenGLFramebufferObject::Depth) {
|
||||
fboFormat.setDepthBufferSize(24);
|
||||
fboFormat.setStencilBufferSize(0);
|
||||
} else {
|
||||
fboFormat.setDepthBufferSize(0);
|
||||
fboFormat.setStencilBufferSize(0);
|
||||
}
|
||||
|
||||
GLenum format = f->format().internalTextureFormat();
|
||||
reqAlpha = (format != GL_RGB
|
||||
#ifndef QT_OPENGL_ES
|
||||
&& format != GL_RGB5 && format != GL_RGB8
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
QOpenGLContextGroup *QOpenGLFBOGLPaintDevice::group() const
|
||||
{
|
||||
QOpenGLSharedResourceGuard *fbo_guard =
|
||||
fbo->d_func()->fbo_guard;
|
||||
return fbo_guard ? fbo_guard->group() : 0;
|
||||
}
|
||||
|
||||
bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus() const
|
||||
{
|
||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
|
|
@ -414,7 +378,7 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *q, const QSize &sz,
|
||||
void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSize &sz,
|
||||
QOpenGLFramebufferObject::Attachment attachment,
|
||||
GLenum texture_target, GLenum internal_format,
|
||||
GLint samples, bool mipmap)
|
||||
|
|
@ -646,8 +610,6 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *q, const QS
|
|||
format.setAttachment(fbo_attachment);
|
||||
format.setInternalTextureFormat(internal_format);
|
||||
format.setMipmap(mipmap);
|
||||
|
||||
glDevice.setFBO(q, attachment);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -704,12 +666,6 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *q, const QS
|
|||
the constructors that take a QOpenGLFramebufferObject parameter, and set the
|
||||
QOpenGLFramebufferObject::samples() property to a non-zero value.
|
||||
|
||||
When painting to a QOpenGLFramebufferObject using QPainter, the state of
|
||||
the current GL context will be altered by the paint engine to reflect
|
||||
its needs. Applications should not rely upon the GL state being reset
|
||||
to its original conditions, particularly the current shader program,
|
||||
GL viewport, texture units, and drawing modes.
|
||||
|
||||
For multisample framebuffer objects a color render buffer is created,
|
||||
otherwise a texture with the specified texture target is created.
|
||||
The color render buffer or texture will have the specified internal
|
||||
|
|
@ -875,8 +831,6 @@ QOpenGLFramebufferObject::~QOpenGLFramebufferObject()
|
|||
{
|
||||
Q_D(QOpenGLFramebufferObject);
|
||||
|
||||
delete d->engine;
|
||||
|
||||
if (d->texture_guard)
|
||||
d->texture_guard->free();
|
||||
if (d->color_buffer_guard)
|
||||
|
|
@ -1103,23 +1057,6 @@ QImage QOpenGLFramebufferObject::toImage() const
|
|||
return image;
|
||||
}
|
||||
|
||||
Q_GLOBAL_STATIC(QOpenGLEngineThreadStorage<QOpenGL2PaintEngineEx>, qt_buffer_2_engine)
|
||||
|
||||
/*! \reimp */
|
||||
QPaintEngine *QOpenGLFramebufferObject::paintEngine() const
|
||||
{
|
||||
Q_D(const QOpenGLFramebufferObject);
|
||||
if (d->engine)
|
||||
return d->engine;
|
||||
|
||||
QPaintEngine *engine = qt_buffer_2_engine()->engine();
|
||||
if (engine->isActive() && engine->paintDevice() != this) {
|
||||
d->engine = new QOpenGL2PaintEngineEx;
|
||||
return d->engine;
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QOpenGLFramebufferObject::bindDefault()
|
||||
\internal
|
||||
|
|
@ -1158,53 +1095,6 @@ bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()
|
|||
return QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::Framebuffers);
|
||||
}
|
||||
|
||||
/*! \reimp */
|
||||
int QOpenGLFramebufferObject::metric(PaintDeviceMetric metric) const
|
||||
{
|
||||
Q_D(const QOpenGLFramebufferObject);
|
||||
|
||||
float dpmx = qt_defaultDpiX()*100./2.54;
|
||||
float dpmy = qt_defaultDpiY()*100./2.54;
|
||||
int w = d->size.width();
|
||||
int h = d->size.height();
|
||||
switch (metric) {
|
||||
case PdmWidth:
|
||||
return w;
|
||||
|
||||
case PdmHeight:
|
||||
return h;
|
||||
|
||||
case PdmWidthMM:
|
||||
return qRound(w * 1000 / dpmx);
|
||||
|
||||
case PdmHeightMM:
|
||||
return qRound(h * 1000 / dpmy);
|
||||
|
||||
case PdmNumColors:
|
||||
return 0;
|
||||
|
||||
case PdmDepth:
|
||||
return 32;//d->depth;
|
||||
|
||||
case PdmDpiX:
|
||||
return qRound(dpmx * 0.0254);
|
||||
|
||||
case PdmDpiY:
|
||||
return qRound(dpmy * 0.0254);
|
||||
|
||||
case PdmPhysicalDpiX:
|
||||
return qRound(dpmx * 0.0254);
|
||||
|
||||
case PdmPhysicalDpiY:
|
||||
return qRound(dpmy * 0.0254);
|
||||
|
||||
default:
|
||||
qWarning("QOpenGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn GLuint QOpenGLFramebufferObject::handle() const
|
||||
|
||||
|
|
@ -1220,11 +1110,6 @@ GLuint QOpenGLFramebufferObject::handle() const
|
|||
return d->fbo();
|
||||
}
|
||||
|
||||
/*! \fn int QOpenGLFramebufferObject::devType() const
|
||||
\internal
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
Returns the status of the depth and stencil buffers attached to
|
||||
this framebuffer object.
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ QT_MODULE(Gui)
|
|||
class QOpenGLFramebufferObjectPrivate;
|
||||
class QOpenGLFramebufferObjectFormat;
|
||||
|
||||
class Q_GUI_EXPORT QOpenGLFramebufferObject : public QPaintDevice
|
||||
class Q_GUI_EXPORT QOpenGLFramebufferObject
|
||||
{
|
||||
Q_DECLARE_PRIVATE(QOpenGLFramebufferObject)
|
||||
public:
|
||||
|
|
@ -92,6 +92,9 @@ public:
|
|||
bool bind();
|
||||
bool release();
|
||||
|
||||
int width() const { return size().width(); }
|
||||
int height() const { return size().width(); }
|
||||
|
||||
GLuint texture() const;
|
||||
QSize size() const;
|
||||
QImage toImage() const;
|
||||
|
|
@ -110,10 +113,6 @@ public:
|
|||
GLbitfield buffers = GL_COLOR_BUFFER_BIT,
|
||||
GLenum filter = GL_NEAREST);
|
||||
|
||||
protected:
|
||||
int metric(PaintDeviceMetric metric) const;
|
||||
int devType() const { return QInternal::FramebufferObject; }
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QOpenGLFramebufferObject)
|
||||
QScopedPointer<QOpenGLFramebufferObjectPrivate> d_ptr;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE
|
|||
QT_BEGIN_INCLUDE_NAMESPACE
|
||||
|
||||
#include <qopenglframebufferobject.h>
|
||||
#include <private/qopenglpaintdevice_p.h>
|
||||
#include <private/qopenglcontext_p.h>
|
||||
#include <private/qopenglextensions_p.h>
|
||||
|
||||
|
|
@ -109,31 +108,12 @@ public:
|
|||
uint mipmap : 1;
|
||||
};
|
||||
|
||||
class QOpenGLFBOGLPaintDevice : public QOpenGLPaintDevice
|
||||
{
|
||||
public:
|
||||
virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();}
|
||||
virtual QSize size() const {return fbo->size();}
|
||||
virtual QSurfaceFormat format() const {return fboFormat;}
|
||||
virtual QOpenGLContextGroup *group() const;
|
||||
virtual bool alphaRequested() const { return reqAlpha; }
|
||||
|
||||
void setFBO(QOpenGLFramebufferObject* f,
|
||||
QOpenGLFramebufferObject::Attachment attachment);
|
||||
|
||||
private:
|
||||
QOpenGLFramebufferObject* fbo;
|
||||
QSurfaceFormat fboFormat;
|
||||
bool wasBound;
|
||||
bool reqAlpha;
|
||||
};
|
||||
|
||||
class QOpenGLFramebufferObjectPrivate
|
||||
{
|
||||
public:
|
||||
QOpenGLFramebufferObjectPrivate() : fbo_guard(0), texture_guard(0), depth_buffer_guard(0)
|
||||
, stencil_buffer_guard(0), color_buffer_guard(0)
|
||||
, valid(false), engine(0) {}
|
||||
, valid(false) {}
|
||||
~QOpenGLFramebufferObjectPrivate() {}
|
||||
|
||||
void init(QOpenGLFramebufferObject *q, const QSize& sz,
|
||||
|
|
@ -151,8 +131,6 @@ public:
|
|||
QOpenGLFramebufferObjectFormat format;
|
||||
uint valid : 1;
|
||||
QOpenGLFramebufferObject::Attachment fbo_attachment;
|
||||
mutable QPaintEngine *engine;
|
||||
QOpenGLFBOGLPaintDevice glDevice;
|
||||
QOpenGLExtensions funcs;
|
||||
|
||||
inline GLuint fbo() const { return fbo_guard ? fbo_guard->id() : 0; }
|
||||
|
|
|
|||
|
|
@ -39,115 +39,193 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <private/qopenglpaintdevice_p.h>
|
||||
#include <qopenglpaintdevice.h>
|
||||
#include <qpaintengine.h>
|
||||
#include <qthreadstorage.h>
|
||||
|
||||
#include <private/qobject_p.h>
|
||||
#include <private/qopenglcontext_p.h>
|
||||
#include <private/qopenglframebufferobject_p.h>
|
||||
#include <private/qopenglpaintengine_p.h>
|
||||
|
||||
// for qt_defaultDpiX/Y
|
||||
#include <private/qfont_p.h>
|
||||
|
||||
#include <qopenglfunctions.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QOpenGLPaintDevice::QOpenGLPaintDevice()
|
||||
: m_thisFBO(0)
|
||||
/*!
|
||||
\class QOpenGLPaintDevice
|
||||
\brief The QOpenGLPaintDevice class enables painting to an OpenGL context using QPainter.
|
||||
\since 5.0
|
||||
|
||||
\ingroup painting-3D
|
||||
|
||||
When painting to a QOpenGLPaintDevice using QPainter, the state of
|
||||
the current GL context will be altered by the paint engine to reflect
|
||||
its needs. Applications should not rely upon the GL state being reset
|
||||
to its original conditions, particularly the current shader program,
|
||||
GL viewport, texture units, and drawing modes.
|
||||
*/
|
||||
|
||||
class QOpenGLPaintDevicePrivate
|
||||
{
|
||||
public:
|
||||
QOpenGLPaintDevicePrivate(const QSize &size);
|
||||
|
||||
QSize size;
|
||||
QOpenGLContext *ctx;
|
||||
|
||||
qreal dpmx;
|
||||
qreal dpmy;
|
||||
|
||||
bool flipped;
|
||||
|
||||
QPaintEngine *engine;
|
||||
|
||||
void init(const QSize &size, QOpenGLContext *ctx);
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructs a QOpenGLPaintDevice with the given \a size.
|
||||
|
||||
The QOpenGLPaintDevice is only valid for the current context.
|
||||
|
||||
\sa QOpenGLContext::currentContext()
|
||||
*/
|
||||
QOpenGLPaintDevice::QOpenGLPaintDevice(const QSize &size)
|
||||
: d_ptr(new QOpenGLPaintDevicePrivate(size))
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QOpenGLPaintDevice with the given \a size and \a ctx.
|
||||
|
||||
The QOpenGLPaintDevice is only valid for the current context.
|
||||
|
||||
\sa QOpenGLContext::currentContext()
|
||||
*/
|
||||
QOpenGLPaintDevice::QOpenGLPaintDevice(int width, int height)
|
||||
: d_ptr(new QOpenGLPaintDevicePrivate(QSize(width, height)))
|
||||
{
|
||||
}
|
||||
|
||||
QOpenGLPaintDevice::~QOpenGLPaintDevice()
|
||||
{
|
||||
delete d_ptr->engine;
|
||||
}
|
||||
|
||||
QOpenGLPaintDevicePrivate::QOpenGLPaintDevicePrivate(const QSize &sz)
|
||||
: size(sz)
|
||||
, ctx(QOpenGLContext::currentContext())
|
||||
, dpmx(qt_defaultDpiX() * 100. / 2.54)
|
||||
, dpmy(qt_defaultDpiY() * 100. / 2.54)
|
||||
, flipped(false)
|
||||
, engine(0)
|
||||
{
|
||||
}
|
||||
|
||||
class QOpenGLEngineThreadStorage
|
||||
{
|
||||
public:
|
||||
QPaintEngine *engine() {
|
||||
QPaintEngine *&localEngine = storage.localData();
|
||||
if (!localEngine)
|
||||
localEngine = new QOpenGL2PaintEngineEx;
|
||||
return localEngine;
|
||||
}
|
||||
|
||||
private:
|
||||
QThreadStorage<QPaintEngine *> storage;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(QOpenGLEngineThreadStorage, qt_opengl_engine)
|
||||
|
||||
QPaintEngine *QOpenGLPaintDevice::paintEngine() const
|
||||
{
|
||||
if (d_ptr->engine)
|
||||
return d_ptr->engine;
|
||||
|
||||
QPaintEngine *engine = qt_opengl_engine()->engine();
|
||||
if (engine->isActive() && engine->paintDevice() != this) {
|
||||
d_ptr->engine = new QOpenGL2PaintEngineEx;
|
||||
return d_ptr->engine;
|
||||
}
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
QOpenGLContext *QOpenGLPaintDevice::context() const
|
||||
{
|
||||
return d_ptr->ctx;
|
||||
}
|
||||
|
||||
QSize QOpenGLPaintDevice::size() const
|
||||
{
|
||||
return d_ptr->size;
|
||||
}
|
||||
|
||||
int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
|
||||
{
|
||||
switch(metric) {
|
||||
switch (metric) {
|
||||
case PdmWidth:
|
||||
return size().width();
|
||||
return d_ptr->size.width();
|
||||
case PdmHeight:
|
||||
return size().height();
|
||||
case PdmDepth: {
|
||||
const QSurfaceFormat f = format();
|
||||
return f.redBufferSize() + f.greenBufferSize() + f.blueBufferSize() + f.alphaBufferSize();
|
||||
}
|
||||
return d_ptr->size.height();
|
||||
case PdmDepth:
|
||||
return 32;
|
||||
case PdmWidthMM:
|
||||
return qRound(d_ptr->size.width() * 1000 / d_ptr->dpmx);
|
||||
case PdmHeightMM:
|
||||
return qRound(d_ptr->size.height() * 1000 / d_ptr->dpmy);
|
||||
case PdmNumColors:
|
||||
return 0;
|
||||
case PdmDpiX:
|
||||
return qRound(d_ptr->dpmx * 0.0254);
|
||||
case PdmDpiY:
|
||||
return qRound(d_ptr->dpmy * 0.0254);
|
||||
case PdmPhysicalDpiX:
|
||||
return qRound(d_ptr->dpmx * 0.0254);
|
||||
case PdmPhysicalDpiY:
|
||||
return qRound(d_ptr->dpmy * 0.0254);
|
||||
default:
|
||||
qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void QOpenGLPaintDevice::beginPaint()
|
||||
qreal QOpenGLPaintDevice::dotsPerMeterX() const
|
||||
{
|
||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
|
||||
// Record the currently bound FBO so we can restore it again
|
||||
// in endPaint() and bind this device's FBO
|
||||
//
|
||||
// Note: m_thisFBO could be zero if the paint device is not
|
||||
// backed by an FBO (e.g. window back buffer). But there could
|
||||
// be a previous FBO bound to the context which we need to
|
||||
// explicitly unbind. Otherwise the painting will go into
|
||||
// the previous FBO instead of to the window.
|
||||
m_previousFBO = ctx->d_func()->current_fbo;
|
||||
|
||||
if (m_previousFBO != m_thisFBO) {
|
||||
ctx->d_func()->current_fbo = m_thisFBO;
|
||||
QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
|
||||
}
|
||||
|
||||
// Set the default fbo for the context to m_thisFBO so that
|
||||
// if some raw GL code between beginNativePainting() and
|
||||
// endNativePainting() calls QOpenGLFramebufferObject::release(),
|
||||
// painting will revert to the window surface's fbo.
|
||||
ctx->d_func()->default_fbo = m_thisFBO;
|
||||
return d_ptr->dpmx;
|
||||
}
|
||||
|
||||
void QOpenGLPaintDevice::ensureActiveTarget()
|
||||
qreal QOpenGLPaintDevice::dotsPerMeterY() const
|
||||
{
|
||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
|
||||
if (ctx->d_func()->current_fbo != m_thisFBO) {
|
||||
ctx->d_func()->current_fbo = m_thisFBO;
|
||||
QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
|
||||
}
|
||||
|
||||
ctx->d_func()->default_fbo = m_thisFBO;
|
||||
return d_ptr->dpmy;
|
||||
}
|
||||
|
||||
void QOpenGLPaintDevice::endPaint()
|
||||
void QOpenGLPaintDevice::setDotsPerMeterX(qreal dpmx)
|
||||
{
|
||||
// Make sure the FBO bound at beginPaint is re-bound again here:
|
||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
|
||||
if (m_previousFBO != ctx->d_func()->current_fbo) {
|
||||
ctx->d_func()->current_fbo = m_previousFBO;
|
||||
QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO);
|
||||
}
|
||||
|
||||
ctx->d_func()->default_fbo = 0;
|
||||
d_ptr->dpmx = dpmx;
|
||||
}
|
||||
|
||||
bool QOpenGLPaintDevice::isFlipped() const
|
||||
void QOpenGLPaintDevice::setDotsPerMeterY(qreal dpmy)
|
||||
{
|
||||
return false;
|
||||
d_ptr->dpmx = dpmy;
|
||||
}
|
||||
|
||||
// returns the QOpenGLPaintDevice for the given QPaintDevice
|
||||
QOpenGLPaintDevice* QOpenGLPaintDevice::getDevice(QPaintDevice* pd)
|
||||
/*!
|
||||
Specifies whether painting should be flipped around the Y-axis or not.
|
||||
*/
|
||||
void QOpenGLPaintDevice::setPaintFlipped(bool flipped)
|
||||
{
|
||||
QOpenGLPaintDevice* glpd = 0;
|
||||
d_ptr->flipped = flipped;
|
||||
}
|
||||
|
||||
switch(pd->devType()) {
|
||||
case QInternal::FramebufferObject:
|
||||
glpd = &(static_cast<QOpenGLFramebufferObject*>(pd)->d_func()->glDevice);
|
||||
break;
|
||||
case QInternal::Pixmap: {
|
||||
qWarning("Pixmap type not supported for GL rendering");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qWarning("QOpenGLPaintDevice::getDevice() - Unknown device type %d", pd->devType());
|
||||
break;
|
||||
}
|
||||
|
||||
return glpd;
|
||||
bool QOpenGLPaintDevice::paintFlipped() const
|
||||
{
|
||||
return d_ptr->flipped;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QOPENGLPAINTDEVICE_P_H
|
||||
#define QOPENGLPAINTDEVICE_P_H
|
||||
#ifndef QOPENGLPAINTDEVICE_H
|
||||
#define QOPENGLPAINTDEVICE_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
|
|
@ -58,62 +58,46 @@
|
|||
#include <QtGui/qopengl.h>
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QT_MODULE(Gui)
|
||||
|
||||
class QOpenGLPaintDevicePrivate;
|
||||
|
||||
class Q_GUI_EXPORT QOpenGLPaintDevice : public QPaintDevice
|
||||
{
|
||||
Q_DECLARE_PRIVATE(QOpenGLPaintDevice)
|
||||
public:
|
||||
QOpenGLPaintDevice();
|
||||
QOpenGLPaintDevice(const QSize &size);
|
||||
QOpenGLPaintDevice(int width, int height);
|
||||
virtual ~QOpenGLPaintDevice();
|
||||
|
||||
int devType() const {return QInternal::OpenGL;}
|
||||
int devType() const { return QInternal::OpenGL; }
|
||||
QPaintEngine *paintEngine() const;
|
||||
|
||||
virtual void beginPaint();
|
||||
virtual void ensureActiveTarget();
|
||||
virtual void endPaint();
|
||||
QOpenGLContext *context() const;
|
||||
QSize size() const;
|
||||
|
||||
virtual QOpenGLContextGroup *group() const = 0;
|
||||
qreal dotsPerMeterX() const;
|
||||
qreal dotsPerMeterY() const;
|
||||
|
||||
virtual QSurfaceFormat format() const = 0;
|
||||
virtual QSize size() const = 0;
|
||||
void setDotsPerMeterX(qreal);
|
||||
void setDotsPerMeterY(qreal);
|
||||
|
||||
virtual bool alphaRequested() const = 0;
|
||||
virtual bool isFlipped() const;
|
||||
|
||||
// returns the QOpenGLPaintDevice for the given QPaintDevice
|
||||
static QOpenGLPaintDevice* getDevice(QPaintDevice*);
|
||||
void setPaintFlipped(bool flipped);
|
||||
bool paintFlipped() const;
|
||||
|
||||
protected:
|
||||
int metric(QPaintDevice::PaintDeviceMetric metric) const;
|
||||
GLuint m_previousFBO;
|
||||
GLuint m_thisFBO;
|
||||
|
||||
Q_DISABLE_COPY(QOpenGLPaintDevice)
|
||||
QScopedPointer<QOpenGLPaintDevicePrivate> d_ptr;
|
||||
};
|
||||
|
||||
|
||||
#if 0
|
||||
// Wraps a QOpenGLWidget
|
||||
class QOpenGLWidget;
|
||||
class Q_GUI_EXPORT QOpenGLWidgetGLPaintDevice : public QOpenGLPaintDevice
|
||||
{
|
||||
public:
|
||||
QOpenGLWidgetGLPaintDevice();
|
||||
|
||||
virtual QPaintEngine* paintEngine() const;
|
||||
|
||||
// QOpenGLWidgets need to do swapBufers in endPaint:
|
||||
virtual void beginPaint();
|
||||
virtual void endPaint();
|
||||
virtual QSize size() const;
|
||||
virtual QOpenGLContext* context() const;
|
||||
|
||||
void setWidget(QOpenGLWidget*);
|
||||
|
||||
private:
|
||||
friend class QOpenGLWidget;
|
||||
QOpenGLWidget *glWidget;
|
||||
};
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QOPENGLPAINTDEVICE_P_H
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QOPENGLPAINTDEVICE_H
|
||||
|
|
@ -342,7 +342,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushUniforms()
|
|||
QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
|
||||
qreal m22 = -1;
|
||||
qreal dy = height;
|
||||
if (device->isFlipped()) {
|
||||
if (device->paintFlipped()) {
|
||||
m22 = 1;
|
||||
dy = 0;
|
||||
}
|
||||
|
|
@ -390,7 +390,7 @@ void QOpenGL2PaintEngineExPrivate::updateMatrix()
|
|||
GLfloat dx = transform.dx();
|
||||
GLfloat dy = transform.dy();
|
||||
|
||||
if (device->isFlipped()) {
|
||||
if (device->paintFlipped()) {
|
||||
hfactor *= -1;
|
||||
dy -= height;
|
||||
}
|
||||
|
|
@ -542,7 +542,8 @@ void QOpenGL2PaintEngineEx::beginNativePainting()
|
|||
d->funcs.glDisableVertexAttribArray(i);
|
||||
|
||||
#ifndef QT_OPENGL_ES_2
|
||||
const QSurfaceFormat &fmt = d->device->format();
|
||||
Q_ASSERT(QOpenGLContext::currentContext());
|
||||
const QSurfaceFormat &fmt = d->device->context()->format();
|
||||
if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1)
|
||||
|| fmt.profile() == QSurfaceFormat::CompatibilityProfile)
|
||||
{
|
||||
|
|
@ -878,7 +879,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
|
|||
// Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
|
||||
path.makeCacheable();
|
||||
|
||||
if (!device->format().stencilBufferSize()) {
|
||||
if (device->context()->format().stencilBufferSize() == 0) {
|
||||
// If there is no stencil buffer, triangulate the path instead.
|
||||
|
||||
QRectF bbox = path.controlPointRect();
|
||||
|
|
@ -1421,7 +1422,7 @@ void QOpenGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem)
|
|||
? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat)
|
||||
: d->glyphCacheType;
|
||||
if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
|
||||
if (d->device->alphaRequested() || s->matrix.type() > QTransform::TxTranslate
|
||||
if (d->device->context()->format().alphaBufferSize() > 0 || s->matrix.type() > QTransform::TxTranslate
|
||||
|| (s->composition_mode != QPainter::CompositionMode_Source
|
||||
&& s->composition_mode != QPainter::CompositionMode_SourceOver))
|
||||
{
|
||||
|
|
@ -1480,7 +1481,7 @@ void QOpenGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &text
|
|||
|
||||
|
||||
if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
|
||||
if (d->device->alphaRequested() || txtype > QTransform::TxTranslate
|
||||
if (d->device->context()->format().alphaBufferSize() > 0 || txtype > QTransform::TxTranslate
|
||||
|| (state()->composition_mode != QPainter::CompositionMode_Source
|
||||
&& state()->composition_mode != QPainter::CompositionMode_SourceOver))
|
||||
{
|
||||
|
|
@ -1944,17 +1945,14 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
|
|||
{
|
||||
Q_D(QOpenGL2PaintEngineEx);
|
||||
|
||||
// qDebug("QOpenGL2PaintEngineEx::begin()");
|
||||
if (pdev->devType() == QInternal::OpenGL)
|
||||
d->device = static_cast<QOpenGLPaintDevice*>(pdev);
|
||||
else
|
||||
d->device = QOpenGLPaintDevice::getDevice(pdev);
|
||||
Q_ASSERT(pdev->devType() == QInternal::OpenGL);
|
||||
d->device = static_cast<QOpenGLPaintDevice*>(pdev);
|
||||
|
||||
if (!d->device)
|
||||
return false;
|
||||
|
||||
if (d->device->group() != QOpenGLContextGroup::currentContextGroup()) {
|
||||
qWarning("QPainter::begin(): OpenGL resource not valid in current context");
|
||||
if (d->device->context() != QOpenGLContext::currentContext()) {
|
||||
qWarning("QPainter::begin(): QOpenGLPaintDevice's context needs to be current");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1983,10 +1981,6 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
|
|||
d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
|
||||
d->stencilClean = true;
|
||||
|
||||
// Calling begin paint should make the correct context current. So, any
|
||||
// code which calls into GL or otherwise needs a current context *must*
|
||||
// go after beginPaint:
|
||||
d->device->beginPaint();
|
||||
d->shaderManager = new QOpenGLEngineShaderManager(d->ctx);
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
|
@ -2013,7 +2007,7 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
|
|||
#if defined(QT_OPENGL_ES_2)
|
||||
// OpenGL ES can't switch MSAA off, so if the gl paint device is
|
||||
// multisampled, it's always multisampled.
|
||||
d->multisamplingAlwaysEnabled = d->device->format().samples() > 1;
|
||||
d->multisamplingAlwaysEnabled = d->device->context()->format().samples() > 1;
|
||||
#else
|
||||
d->multisamplingAlwaysEnabled = false;
|
||||
#endif
|
||||
|
|
@ -2028,7 +2022,6 @@ bool QOpenGL2PaintEngineEx::end()
|
|||
QOpenGLContext *ctx = d->ctx;
|
||||
d->funcs.glUseProgram(0);
|
||||
d->transferMode(BrushDrawingMode);
|
||||
d->device->endPaint();
|
||||
|
||||
ctx->d_func()->active_engine = 0;
|
||||
|
||||
|
|
@ -2062,8 +2055,6 @@ void QOpenGL2PaintEngineEx::ensureActive()
|
|||
d->needsSync = true;
|
||||
}
|
||||
|
||||
d->device->ensureActiveTarget();
|
||||
|
||||
if (d->needsSync) {
|
||||
d->transferMode(BrushDrawingMode);
|
||||
glViewport(0, 0, d->width, d->height);
|
||||
|
|
@ -2120,7 +2111,7 @@ void QOpenGL2PaintEngineExPrivate::setScissor(const QRect &rect)
|
|||
const int left = rect.left();
|
||||
const int width = rect.width();
|
||||
int bottom = height - (rect.top() + rect.height());
|
||||
if (device->isFlipped()) {
|
||||
if (device->paintFlipped()) {
|
||||
bottom = rect.top();
|
||||
}
|
||||
const int height = rect.height();
|
||||
|
|
|
|||
|
|
@ -55,10 +55,11 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
#include <qopenglpaintdevice.h>
|
||||
|
||||
#include <private/qpaintengineex_p.h>
|
||||
#include <private/qopenglengineshadermanager_p.h>
|
||||
#include <private/qopengl2pexvertexarray_p.h>
|
||||
#include <private/qopenglpaintdevice_p.h>
|
||||
#include <private/qfontengine_p.h>
|
||||
#include <private/qdatabuffer_p.h>
|
||||
#include <private/qopengltriangulatingstroker_p.h>
|
||||
|
|
|
|||
|
|
@ -79,15 +79,6 @@ public:
|
|||
bool paintingActive() const;
|
||||
virtual QPaintEngine *paintEngine() const = 0;
|
||||
|
||||
#if defined(Q_WS_QWS)
|
||||
static QWSDisplay *qwsDisplay();
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
virtual HDC getDC() const;
|
||||
virtual void releaseDC(HDC hdc) const;
|
||||
#endif
|
||||
|
||||
int width() const { return metric(PdmWidth); }
|
||||
int height() const { return metric(PdmHeight); }
|
||||
int widthMM() const { return metric(PdmWidthMM); }
|
||||
|
|
@ -96,9 +87,6 @@ public:
|
|||
int logicalDpiY() const { return metric(PdmDpiY); }
|
||||
int physicalDpiX() const { return metric(PdmPhysicalDpiX); }
|
||||
int physicalDpiY() const { return metric(PdmPhysicalDpiY); }
|
||||
#ifdef QT_DEPRECATED
|
||||
QT_DEPRECATED int numColors() const { return metric(PdmNumColors); }
|
||||
#endif
|
||||
int colorCount() const { return metric(PdmNumColors); }
|
||||
int depth() const { return metric(PdmDepth); }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue