Merge remote-tracking branch 'origin/5.15' into dev

Change-Id: Ideaa64d583746f1ce8265997131fb1ce3a9acbcf
This commit is contained in:
Qt Forward Merge Bot 2019-10-02 01:01:20 +02:00 committed by Simon Hausmann
commit 4c8814a341
141 changed files with 6922 additions and 5002 deletions

View File

@ -484,6 +484,17 @@
]
}
},
"signaling_nan": {
"label": "Signaling NaN for doubles",
"type": "compile",
"test": {
"head": [ "#include <limits>" ],
"main": [
"using B = std::numeric_limits<double>;",
"static_assert(B::has_signaling_NaN, \"System lacks signaling NaN\");"
]
}
},
"sse2": {
"label": "SSE2 instructions",
"type": "x86Simd"
@ -1005,6 +1016,11 @@
{ "type": "define", "name": "QT_REDUCE_RELOCATIONS" }
]
},
"signaling_nan": {
"label": "Signaling NaN",
"condition": "tests.signaling_nan",
"output": [ "publicFeature" ]
},
"sse2": {
"label": "SSE2",
"condition": "(arch.i386 || arch.x86_64) && tests.sse2",

View File

@ -98,7 +98,7 @@ public:
QPoint delta;
QPoint speed;
FlickableTicker *ticker;
QTime timeStamp;
QElapsedTimer timeStamp;
QWidget *target;
QList<QEvent*> ignoreList;
};
@ -109,7 +109,7 @@ Flickable::Flickable()
d->state = FlickablePrivate::Steady;
d->threshold = 10;
d->ticker = new FlickableTicker(this);
d->timeStamp = QTime::currentTime();
d->timeStamp.start();
d->target = 0;
}
@ -208,7 +208,7 @@ void Flickable::handleMouseRelease(QMouseEvent *event)
event->accept();
delta = event->pos() - d->pressPos;
if (d->timeStamp.elapsed() > 100) {
d->timeStamp = QTime::currentTime();
d->timeStamp.start();
d->speed = delta - d->delta;
d->delta = delta;
}
@ -253,7 +253,7 @@ void Flickable::handleMouseMove(QMouseEvent *event)
delta = event->pos() - d->pressPos;
if (delta.x() > d->threshold || delta.x() < -d->threshold ||
delta.y() > d->threshold || delta.y() < -d->threshold) {
d->timeStamp = QTime::currentTime();
d->timeStamp.start();
d->state = FlickablePrivate::ManualScroll;
d->delta = QPoint(0, 0);
d->pressPos = event->pos();
@ -266,7 +266,7 @@ void Flickable::handleMouseMove(QMouseEvent *event)
delta = event->pos() - d->pressPos;
setScrollOffset(d->offset - delta);
if (d->timeStamp.elapsed() > 100) {
d->timeStamp = QTime::currentTime();
d->timeStamp.start();
d->speed = delta - d->delta;
d->delta = delta;
}

View File

@ -92,7 +92,7 @@ public:
}
void updatePlayer() {
int interval = qBound(20, watch.elapsed(), 250);
int interval = qBound(20ll, watch.elapsed(), 250ll);
watch.start();
angle += angleDelta * interval / 1000;
qreal step = moveDelta * interval / 1000;
@ -106,10 +106,10 @@ public:
}
void showFps() {
static QTime frameTick;
static QElapsedTimer frameTick;
static int totalFrame = 0;
if (!(totalFrame & 31)) {
int elapsed = frameTick.elapsed();
const qint64 elapsed = frameTick.elapsed();
frameTick.start();
int fps = 32 * 1000 / (1 + elapsed);
setWindowTitle(QString("Raycasting (%1 FPS)").arg(fps));
@ -355,7 +355,7 @@ protected:
}
private:
QTime watch;
QElapsedTimer watch;
QBasicTimer ticker;
QImage buffer;
qreal angle;

View File

@ -50,36 +50,30 @@
#include "openglwindow.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QMatrix4x4>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QScreen>
#include <QGuiApplication>
#include <QMatrix4x4>
#include <QOpenGLShaderProgram>
#include <QScreen>
#include <QtMath>
#include <QtCore/qmath.h>
//! [1]
class TriangleWindow : public OpenGLWindow
{
public:
TriangleWindow();
using OpenGLWindow::OpenGLWindow;
void initialize() override;
void render() override;
private:
GLuint m_posAttr;
GLuint m_colAttr;
GLuint m_matrixUniform;
GLuint m_posAttr = 0;
GLuint m_colAttr = 0;
GLuint m_matrixUniform = 0;
QOpenGLShaderProgram *m_program;
int m_frame;
QOpenGLShaderProgram *m_program = nullptr;
int m_frame = 0;
};
TriangleWindow::TriangleWindow()
: m_program(0)
, m_frame(0)
{
}
//! [1]
//! [2]

View File

@ -50,18 +50,13 @@
#include "openglwindow.h"
#include <QtCore/QCoreApplication>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLPaintDevice>
#include <QtGui/QPainter>
#include <QOpenGLContext>
#include <QOpenGLPaintDevice>
#include <QPainter>
//! [1]
OpenGLWindow::OpenGLWindow(QWindow *parent)
: QWindow(parent)
, m_animating(false)
, m_context(0)
, m_device(0)
{
setSurfaceType(QWindow::OpenGLSurface);
}

View File

@ -48,8 +48,8 @@
**
****************************************************************************/
#include <QtGui/QWindow>
#include <QtGui/QOpenGLFunctions>
#include <QWindow>
#include <QOpenGLFunctions>
QT_BEGIN_NAMESPACE
class QPainter;
@ -62,7 +62,7 @@ class OpenGLWindow : public QWindow, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit OpenGLWindow(QWindow *parent = 0);
explicit OpenGLWindow(QWindow *parent = nullptr);
~OpenGLWindow();
virtual void render(QPainter *painter);
@ -82,10 +82,10 @@ protected:
void exposeEvent(QExposeEvent *event) override;
private:
bool m_animating;
bool m_animating = false;
QOpenGLContext *m_context;
QOpenGLPaintDevice *m_device;
QOpenGLContext *m_context = nullptr;
QOpenGLPaintDevice *m_device = nullptr;
};
//! [1]

View File

@ -73,15 +73,6 @@
#endif
GLWindow::GLWindow()
: m_texImageInput(0),
m_texImageTmp(0),
m_texImageProcessed(0),
m_shaderDisplay(0),
m_shaderComputeV(0),
m_shaderComputeH(0),
m_blurRadius(0.0f),
m_animate(true),
m_vao(0)
{
const float animationStart = 0.0;
const float animationEnd = 10.0;
@ -324,27 +315,18 @@ void GLWindow::initializeGL()
<< ((ctx->format().renderableType() == QSurfaceFormat::OpenGLES) ? (" GLES") : (" GL"))
<< " context";
if (m_texImageInput) {
delete m_texImageInput;
m_texImageInput = 0;
}
QImage img(":/Qt-logo-medium.png");
Q_ASSERT(!img.isNull());
delete m_texImageInput;
m_texImageInput = new QOpenGLTexture(img.convertToFormat(QImage::Format_RGBA8888).mirrored());
if (m_texImageTmp) {
delete m_texImageTmp;
m_texImageTmp = 0;
}
m_texImageTmp = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texImageTmp->setFormat(m_texImageInput->format());
m_texImageTmp->setSize(m_texImageInput->width(),m_texImageInput->height());
m_texImageTmp->allocateStorage(QOpenGLTexture::RGBA,QOpenGLTexture::UInt8); // WTF?
if (m_texImageProcessed) {
delete m_texImageProcessed;
m_texImageProcessed = 0;
}
m_texImageProcessed = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texImageProcessed->setFormat(m_texImageInput->format());
m_texImageProcessed->setSize(m_texImageInput->width(),m_texImageInput->height());
@ -354,10 +336,7 @@ void GLWindow::initializeGL()
m_texImageProcessed->setMinificationFilter(QOpenGLTexture::Linear);
m_texImageProcessed->setWrapMode(QOpenGLTexture::ClampToEdge);
if (m_shaderDisplay) {
delete m_shaderDisplay;
m_shaderDisplay = 0;
}
m_shaderDisplay = new QOpenGLShaderProgram;
// Prepend the correct version directive to the sources. The rest is the
// same, thanks to the common GLSL syntax.
@ -365,18 +344,12 @@ void GLWindow::initializeGL()
m_shaderDisplay->addShaderFromSourceCode(QOpenGLShader::Fragment, versionedShaderCode(fsDisplaySource));
m_shaderDisplay->link();
if (m_shaderComputeV) {
delete m_shaderComputeV;
m_shaderComputeV = 0;
}
m_shaderComputeV = new QOpenGLShaderProgram;
m_shaderComputeV->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceV));
m_shaderComputeV->link();
if (m_shaderComputeH) {
delete m_shaderComputeH;
m_shaderComputeH = 0;
}
m_shaderComputeH = new QOpenGLShaderProgram;
m_shaderComputeH->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceH));
m_shaderComputeH->link();

View File

@ -90,21 +90,21 @@ protected:
void setAnimating(bool animate);
private:
QPropertyAnimation *m_animationForward;
QPropertyAnimation *m_animationBackward;
QPropertyAnimation *m_animationForward = nullptr;
QPropertyAnimation *m_animationBackward = nullptr;
QSequentialAnimationGroup *m_animationGroup;
QOpenGLTexture *m_texImageInput;
QOpenGLTexture *m_texImageTmp;
QOpenGLTexture *m_texImageProcessed;
QOpenGLShaderProgram *m_shaderDisplay;
QOpenGLShaderProgram *m_shaderComputeV;
QOpenGLShaderProgram *m_shaderComputeH;
QOpenGLTexture *m_texImageInput = nullptr;
QOpenGLTexture *m_texImageTmp = nullptr;
QOpenGLTexture *m_texImageProcessed = nullptr;
QOpenGLShaderProgram *m_shaderDisplay = nullptr;
QOpenGLShaderProgram *m_shaderComputeV = nullptr;
QOpenGLShaderProgram *m_shaderComputeH = nullptr;
QMatrix4x4 m_proj;
QSizeF m_quadSize;
int m_blurRadius;
bool m_animate;
QOpenGLVertexArrayObject *m_vao;
int m_blurRadius = 0;
bool m_animate = true;
QOpenGLVertexArrayObject *m_vao = nullptr;
};
#endif

View File

@ -56,7 +56,7 @@
#include <QOpenGLFunctions>
RenderWindow::RenderWindow(const QSurfaceFormat &format)
: m_context(0),
: m_context(nullptr),
m_initialized(false),
m_forceGLSL110(false),
m_angle(0.0f)
@ -67,7 +67,7 @@ RenderWindow::RenderWindow(const QSurfaceFormat &format)
m_context->setFormat(requestedFormat());
if (!m_context->create()) {
delete m_context;
m_context = 0;
m_context = nullptr;
}
}

View File

@ -64,7 +64,7 @@ class Widget : public QWidget
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
explicit Widget(QWidget *parent = nullptr);
private slots:
void start();

View File

@ -174,6 +174,6 @@ void GeometryEngine::drawCubeGeometry(QOpenGLShaderProgram *program)
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
// Draw cube geometry using indices from VBO 1
glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, 0);
glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, nullptr);
}
//! [2]

View File

@ -52,15 +52,7 @@
#include <QMouseEvent>
#include <math.h>
MainWidget::MainWidget(QWidget *parent) :
QOpenGLWidget(parent),
geometries(0),
texture(0),
angularSpeed(0)
{
}
#include <cmath>
MainWidget::~MainWidget()
{

View File

@ -69,7 +69,7 @@ class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions
Q_OBJECT
public:
explicit MainWidget(QWidget *parent = 0);
using QOpenGLWidget::QOpenGLWidget;
~MainWidget();
protected:
@ -87,15 +87,15 @@ protected:
private:
QBasicTimer timer;
QOpenGLShaderProgram program;
GeometryEngine *geometries;
GeometryEngine *geometries = nullptr;
QOpenGLTexture *texture;
QOpenGLTexture *texture = nullptr;
QMatrix4x4 projection;
QVector2D mousePressPosition;
QVector3D rotationAxis;
qreal angularSpeed;
qreal angularSpeed = 0;
QQuaternion rotation;
};

View File

@ -57,11 +57,7 @@
bool GLWidget::m_transparent = false;
GLWidget::GLWidget(QWidget *parent)
: QOpenGLWidget(parent),
m_xRot(0),
m_yRot(0),
m_zRot(0),
m_program(0)
: QOpenGLWidget(parent)
{
m_core = QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile;
// --transparent causes the clear color to be transparent. Therefore, on systems that
@ -133,7 +129,7 @@ void GLWidget::cleanup()
makeCurrent();
m_logoVbo.destroy();
delete m_program;
m_program = 0;
m_program = nullptr;
doneCurrent();
}
@ -250,8 +246,10 @@ void GLWidget::setupVertexAttribs()
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glEnableVertexAttribArray(0);
f->glEnableVertexAttribArray(1);
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
nullptr);
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
reinterpret_cast<void *>(3 * sizeof(GLfloat)));
m_logoVbo.release();
}

View File

@ -65,7 +65,7 @@ class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
Q_OBJECT
public:
GLWidget(QWidget *parent = 0);
GLWidget(QWidget *parent = nullptr);
~GLWidget();
static bool isTransparent() { return m_transparent; }
@ -96,18 +96,18 @@ private:
void setupVertexAttribs();
bool m_core;
int m_xRot;
int m_yRot;
int m_zRot;
int m_xRot = 0;
int m_yRot = 0;
int m_zRot = 0;
QPoint m_lastPos;
Logo m_logo;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_logoVbo;
QOpenGLShaderProgram *m_program;
int m_projMatrixLoc;
int m_mvMatrixLoc;
int m_normalMatrixLoc;
int m_lightPosLoc;
QOpenGLShaderProgram *m_program = nullptr;
int m_projMatrixLoc = 0;
int m_mvMatrixLoc = 0;
int m_normalMatrixLoc = 0;
int m_lightPosLoc = 0;
QMatrix4x4 m_proj;
QMatrix4x4 m_camera;
QMatrix4x4 m_world;

View File

@ -52,7 +52,6 @@
#include <qmath.h>
Logo::Logo()
: m_count(0)
{
m_data.resize(2500 * 6);

View File

@ -69,7 +69,7 @@ private:
void add(const QVector3D &v, const QVector3D &n);
QVector<GLfloat> m_data;
int m_count;
int m_count = 0;
};
#endif // LOGO_H

View File

@ -72,5 +72,6 @@ void MainWindow::onAddNew()
if (!centralWidget())
setCentralWidget(new Window(this));
else
QMessageBox::information(0, tr("Cannot add new window"), tr("Already occupied. Undock first."));
QMessageBox::information(nullptr, tr("Cannot add new window"),
tr("Already occupied. Undock first."));
}

View File

@ -121,7 +121,7 @@ void Window::keyPressEvent(QKeyEvent *e)
void Window::dockUndock()
{
if (parent()) {
setParent(0);
setParent(nullptr);
setAttribute(Qt::WA_DeleteOnClose);
move(QApplication::desktop()->width() / 2 - width() / 2,
QApplication::desktop()->height() / 2 - height() / 2);
@ -134,10 +134,12 @@ void Window::dockUndock()
dockBtn->setText(tr("Undock"));
mainWindow->setCentralWidget(this);
} else {
QMessageBox::information(0, tr("Cannot dock"), tr("Main window already closed"));
QMessageBox::information(nullptr, tr("Cannot dock"),
tr("Main window already closed"));
}
} else {
QMessageBox::information(0, tr("Cannot dock"), tr("Main window already occupied"));
QMessageBox::information(nullptr, tr("Cannot dock"),
tr("Main window already occupied"));
}
}
}

View File

@ -57,19 +57,10 @@
#include <QOpenGLVertexArrayObject>
#include <QOpenGLExtraFunctions>
#include <QPropertyAnimation>
#include <QPauseAnimation>
#include <QSequentialAnimationGroup>
#include <QTimer>
GLWindow::GLWindow()
: m_texture(0),
m_program(0),
m_vbo(0),
m_vao(0),
m_target(0, 0, -1),
m_uniformsDirty(true),
m_r(0),
m_r2(0)
{
m_world.setToIdentity();
m_world.translate(0, 0, -1);
@ -197,18 +188,12 @@ void GLWindow::initializeGL()
{
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
if (m_texture) {
delete m_texture;
m_texture = 0;
}
QImage img(":/qtlogo.png");
Q_ASSERT(!img.isNull());
delete m_texture;
m_texture = new QOpenGLTexture(img.scaled(32, 36).mirrored());
if (m_program) {
delete m_program;
m_program = 0;
}
m_program = new QOpenGLShaderProgram;
// Prepend the correct version directive to the sources. The rest is the
// same, thanks to the common GLSL syntax.
@ -223,26 +208,21 @@ void GLWindow::initializeGL()
m_lightPosLoc = m_program->uniformLocation("lightPos");
// Create a VAO. Not strictly required for ES 3, but it is for plain OpenGL.
if (m_vao) {
delete m_vao;
m_vao = 0;
}
m_vao = new QOpenGLVertexArrayObject;
if (m_vao->create())
m_vao->bind();
if (m_vbo) {
delete m_vbo;
m_vbo = 0;
}
m_program->bind();
delete m_vbo;
m_vbo = new QOpenGLBuffer;
m_vbo->create();
m_vbo->bind();
m_vbo->allocate(m_logo.constData(), m_logo.count() * sizeof(GLfloat));
f->glEnableVertexAttribArray(0);
f->glEnableVertexAttribArray(1);
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
nullptr);
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
reinterpret_cast<void *>(3 * sizeof(GLfloat)));
m_vbo->release();

View File

@ -90,23 +90,23 @@ public:
private slots:
void startSecondStage();
private:
QOpenGLTexture *m_texture;
QOpenGLShaderProgram *m_program;
QOpenGLBuffer *m_vbo;
QOpenGLVertexArrayObject *m_vao;
QOpenGLTexture *m_texture = nullptr;
QOpenGLShaderProgram *m_program = nullptr;
QOpenGLBuffer *m_vbo = nullptr;
QOpenGLVertexArrayObject *m_vao = nullptr;
Logo m_logo;
int m_projMatrixLoc;
int m_camMatrixLoc;
int m_worldMatrixLoc;
int m_myMatrixLoc;
int m_lightPosLoc;
int m_projMatrixLoc = 0;
int m_camMatrixLoc = 0;
int m_worldMatrixLoc = 0;
int m_myMatrixLoc = 0;
int m_lightPosLoc = 0;
QMatrix4x4 m_proj;
QMatrix4x4 m_world;
QVector3D m_eye;
QVector3D m_target;
bool m_uniformsDirty;
float m_r;
float m_r2;
QVector3D m_target = {0, 0, -1};
bool m_uniformsDirty = true;
float m_r = 0;
float m_r2 = 0;
};
#endif

View File

@ -57,14 +57,12 @@ Bubble::Bubble(const QPointF &position, qreal radius, const QPointF &velocity)
{
innerColor = randomColor();
outerColor = randomColor();
cache = 0;
updateBrush();
}
//! [0]
void Bubble::updateCache()
{
if (cache)
delete cache;
cache = new QImage(qRound(radius * 2 + 2), qRound(radius * 2 + 2), QImage::Format_ARGB32_Premultiplied);
cache->fill(0x00000000);
@ -80,7 +78,6 @@ void Bubble::updateCache()
Bubble::~Bubble()
{
if (cache)
delete cache;
}

View File

@ -80,7 +80,7 @@ private:
qreal radius;
QColor innerColor;
QColor outerColor;
QImage *cache;
QImage *cache = nullptr;
};
#endif

View File

@ -68,14 +68,6 @@ const int bubbleNum = 8;
GLWidget::GLWidget(MainWindow *mw, bool button, const QColor &background)
: m_mainWindow(mw),
m_showBubbles(true),
m_qtLogo(true),
m_frames(0),
m_program1(0),
m_program2(0),
m_texture(0),
m_transparent(false),
m_btn(0),
m_hasButton(button),
m_background(background)
{

View File

@ -98,34 +98,34 @@ private:
void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
MainWindow *m_mainWindow;
qreal m_fAngle;
qreal m_fScale;
bool m_showBubbles;
qreal m_fAngle = 0;
qreal m_fScale = 1;
bool m_showBubbles = true;
QVector<QVector3D> m_vertices;
QVector<QVector3D> m_normals;
bool m_qtLogo;
QList<Bubble *> m_bubbles;
int m_frames;
bool m_qtLogo = true;
QVector<Bubble *> m_bubbles;
int m_frames = 0;
QElapsedTimer m_time;
QOpenGLShader *m_vshader1;
QOpenGLShader *m_fshader1;
QOpenGLShader *m_vshader2;
QOpenGLShader *m_fshader2;
QOpenGLShaderProgram *m_program1;
QOpenGLShaderProgram *m_program2;
QOpenGLTexture *m_texture;
QOpenGLShader *m_vshader1 = nullptr;
QOpenGLShader *m_fshader1 = nullptr;
QOpenGLShader *m_vshader2 = nullptr;
QOpenGLShader *m_fshader2 = nullptr;
QOpenGLShaderProgram *m_program1 = nullptr;
QOpenGLShaderProgram *m_program2 = nullptr;
QOpenGLTexture *m_texture = nullptr;
QOpenGLBuffer m_vbo1;
QOpenGLBuffer m_vbo2;
int m_vertexAttr1;
int m_normalAttr1;
int m_matrixUniform1;
int m_vertexAttr2;
int m_normalAttr2;
int m_texCoordAttr2;
int m_matrixUniform2;
int m_textureUniform2;
bool m_transparent;
QPushButton *m_btn;
int m_vertexAttr1 = 0;
int m_normalAttr1 = 0;
int m_matrixUniform1 = 0;
int m_vertexAttr2 = 0;
int m_normalAttr2 = 0;
int m_texCoordAttr2 = 0;
int m_matrixUniform2 = 0;
int m_textureUniform2 = 0;
bool m_transparent = false;
QPushButton *m_btn = nullptr;
bool m_hasButton;
QColor m_background;
};

View File

@ -53,17 +53,6 @@
#include <QOpenGLTexture>
#include <QMouseEvent>
GLWidget::GLWidget(QWidget *parent)
: QOpenGLWidget(parent),
clearColor(Qt::black),
xRot(0),
yRot(0),
zRot(0),
program(0)
{
memset(textures, 0, sizeof(textures));
}
GLWidget::~GLWidget()
{
makeCurrent();

View File

@ -63,7 +63,7 @@ class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);
using QOpenGLWidget::QOpenGLWidget;
~GLWidget();
QSize minimumSizeHint() const override;
@ -85,13 +85,13 @@ protected:
private:
void makeObject();
QColor clearColor;
QColor clearColor = Qt::black;
QPoint lastPos;
int xRot;
int yRot;
int zRot;
QOpenGLTexture *textures[6];
QOpenGLShaderProgram *program;
int xRot = 0;
int yRot = 0;
int zRot = 0;
QOpenGLTexture *textures[6] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
QOpenGLShaderProgram *program = nullptr;
QOpenGLBuffer vbo;
};

View File

@ -115,12 +115,7 @@ void GLWidget::grabContext()
m_renderer->unlockRenderer();
}
Renderer::Renderer(GLWidget *w)
: m_inited(false),
m_glwidget(w),
m_exiting(false)
{
}
Renderer::Renderer(GLWidget *w) : m_glwidget(w) {}
void Renderer::paintQtLogo()
{

View File

@ -88,29 +88,29 @@ private:
void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4);
void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
bool m_inited;
qreal m_fAngle;
qreal m_fScale;
bool m_inited = false;
qreal m_fAngle = 0;
qreal m_fScale = 1;
QVector<QVector3D> vertices;
QVector<QVector3D> normals;
QOpenGLShaderProgram program;
QOpenGLBuffer vbo;
int vertexAttr;
int normalAttr;
int matrixUniform;
GLWidget *m_glwidget;
int vertexAttr = 0;
int normalAttr = 0;
int matrixUniform = 0;
GLWidget *m_glwidget = nullptr;
QMutex m_renderMutex;
QElapsedTimer m_elapsed;
QMutex m_grabMutex;
QWaitCondition m_grabCond;
bool m_exiting;
bool m_exiting = false;
};
class GLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);
explicit GLWidget(QWidget *parent = nullptr);
~GLWidget();
protected:

View File

@ -64,7 +64,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -64,7 +64,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -64,7 +64,7 @@ int main(int argc, char *argv[])
QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs"));
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -128,7 +128,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -0,0 +1,41 @@
#
# qmake configuration for the NXP i.MX8 based boards (64-bit)
#
# The configuration below is set up for running with the fbdev-style
# Vivante graphics stack. (so eglfs with the eglfs_viv backend, no
# direct drm use via eglfs_kms)
# Wayland should also be functional. However, when writing Wayland
# *compositors* with Qt, the eglfs backend will have to be switched to
# eglfs_viv_wl by setting the QT_QPA_EGLFS_INTEGRATION environment
# variable.
#
# Below is an example configure line that assumes there is an AArch64
# toolchain and sysroot available in $HOME/imx8. On device Qt is
# expected to be placed under /usr/local/qt514 whereas on the host
# 'make install' will copy the host tools and the target libraries to
# $HOME/imx8/qt5.
#
# ./configure -release -opengl es2 -device linux-imx8-g++ \
# -device-option CROSS_COMPILE=~/imx8/toolchain/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux- \
# -sysroot ~/imx8/sysroot \
# -opensource -confirm-license -make libs -prefix /usr/local/qt514 -extprefix ~/imx8/qt5 -v
include(../common/linux_device_pre.conf)
QMAKE_LIBS_EGL += -lEGL
QMAKE_LIBS_OPENGL_ES2 += -lGLESv2 -lEGL -lGAL
QMAKE_LIBS_OPENVG += -lOpenVG -lEGL -lGAL
IMX8_CFLAGS = -march=armv8-a -mtune=cortex-a72.cortex-a53 -DLINUX=1 -DEGL_API_FB=1
QMAKE_CFLAGS += $$IMX8_CFLAGS
QMAKE_CXXFLAGS += $$IMX8_CFLAGS
DISTRO_OPTS += aarch64
# Preferred eglfs backend
EGLFS_DEVICE_INTEGRATION = eglfs_viv
include(../common/linux_arm_device_post.conf)
load(qt_config)

View File

@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the qmake spec of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "../../linux-g++/qplatformdefs.h"

View File

@ -71,7 +71,8 @@ qt {
# Add the same default rpaths as Xcode does for new projects.
# This is especially important for iOS/tvOS/watchOS where no other option is possible.
!no_default_rpath {
QMAKE_RPATHDIR += @executable_path/../Frameworks
uikit: QMAKE_RPATHDIR += @executable_path/Frameworks
else: QMAKE_RPATHDIR += @executable_path/../Frameworks
equals(TEMPLATE, lib):!plugin:lib_bundle: QMAKE_RPATHDIR += @loader_path/Frameworks
}

View File

@ -0,0 +1,7 @@
# Prevent warnings about object files without any symbols. This is a common
# thing in Qt as we tend to build files unconditionally, and then use ifdefs
# to compile out parts that are not relevant.
QMAKE_RANLIB += -no_warning_for_no_symbols
# We have to tell 'ar' to not run ranlib by itself
QMAKE_AR += -S

View File

@ -88,6 +88,9 @@ cross_compile: \
android|uikit|winrt: \
CONFIG += builtin_testdata
# Prevent warnings about object files without any symbols
macos: CONFIG += no_warn_empty_obj_files
CONFIG += \
utf8_source \
create_prl link_prl \

View File

@ -992,6 +992,22 @@
\row \li embed_translations \li Embed the generated translations from
\c lrelease in the executable, under \l{QM_FILES_RESOURCE_PREFIX}.
Requires \c lrelease to be set, too. Not set by default.
\row \li create_libtool \li Create a libtool .la file for the currently
built library.
\row \li create_pc \li Create a pkg-config .pc file for the currently built
library.
\row \li no_batch \li NMake only: Turn off generation of NMake batch rules
or inference rules.
\row \li skip_target_version_ext \li Suppress the automatic version number
appended to the DLL file name on Windows.
\row \li suppress_vcproj_warnings \li Suppress warnings of the VS project
generator.
\row \li windeployqt \li Automatically invoke windeployqt after linking,
and add the output as deployment items.
\row \li dont_recurse \li Suppress qmake recursion for the current
subproject.
\row \li no_include_pwd \li Do not add the current directory to
INCLUDEPATHS.
\endtable
When you use the \c debug_and_release option (which is the default under
@ -1039,6 +1055,8 @@
qmake will process all libraries linked to
by the application and find their meta-information (see
\l{LibDepend}{Library Dependencies} for more info).
\row \li no_install_prl \li This option disables the generation of
installation rules for generated .prl files.
\endtable
\note The \c create_prl option is required when \e {building} a

View File

@ -0,0 +1,42 @@
From 3442a3ce9c2bd366eb0bd1c18d37a6ce732a888d Mon Sep 17 00:00:00 2001
From: Andy Shaw <andy.shaw@qt.io>
Date: Wed, 25 Sep 2019 09:17:01 +0200
Subject: [PATCH] Fix CVE-2019-16168 in SQLite
v3.29.0 is the latest and there is no indication as to when the next
release is so we will apply this separately for now and it can be
reverted once it is in a release that we ship with.
This patch is taken from https://www.sqlite.org/src/info/98357d8c1263920b
Change-Id: I82d398b093b67842a4369e3220c01e7eea30763a
---
src/3rdparty/sqlite/sqlite3.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c
index 61bfdeb766..b3e6ae27b6 100644
--- a/src/3rdparty/sqlite/sqlite3.c
+++ b/src/3rdparty/sqlite/sqlite3.c
@@ -105933,7 +105933,9 @@ static void decodeIntArray(
if( sqlite3_strglob("unordered*", z)==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
+ int sz = sqlite3Atoi(z+3);
+ if( sz<2 ) sz = 2;
+ pIndex->szIdxRow = sqlite3LogEst(sz);
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
pIndex->noSkipScan = 1;
}
@@ -143260,6 +143262,7 @@ static int whereLoopAddBtreeIndex(
** it to pNew->rRun, which is currently set to the cost of the index
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
+ assert( pSrc->pTab->szTabRow>0 );
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
--
2.20.1 (Apple Git-117)

View File

@ -6,8 +6,8 @@
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
"Homepage": "https://www.sqlite.org/",
"Version": "3.28.0",
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3280000.zip",
"Version": "3.29.0",
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3290000.zip",
"License": "Public Domain",
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
}

File diff suppressed because it is too large Load Diff

View File

@ -123,9 +123,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.28.0"
#define SQLITE_VERSION_NUMBER 3028000
#define SQLITE_SOURCE_ID "2019-04-16 19:49:53 884b4b7e502b4e991677b53971277adfaf0a04a284f8e483e2553d0f83156b50"
#define SQLITE_VERSION "3.29.0"
#define SQLITE_VERSION_NUMBER 3029000
#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -1296,8 +1296,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
** to test whether a file is at least readable. The file can be a
** directory.
** to test whether a file is at least readable. The SQLITE_ACCESS_READ
** flag is never actually used and is not implemented in the built-in
** VFSes of SQLite. The file is named by the second argument and can be a
** directory. The xAccess method returns [SQLITE_OK] on success or some
** non-zero error code if there is an I/O error or if the name of
** the file given in the second argument is illegal. If SQLITE_OK
** is returned, then non-zero or zero is written into *pResOut to indicate
** whether or not the file is accessible.
**
** ^SQLite will always allocate at least mxPathname+1 bytes for the
** output buffer xFullPathname. The exact size of the output buffer
@ -2198,6 +2204,7 @@ struct sqlite3_mem_methods {
** features include but are not limited to the following:
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@ -2213,6 +2220,34 @@ struct sqlite3_mem_methods {
** integer into which is written 0 or 1 to indicate whether the writable_schema
** is enabled or disabled following this call.
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]]
** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates
** the legacy behavior of the [ALTER TABLE RENAME] command such it
** behaves as it did prior to [version 3.24.0] (2018-06-04). See the
** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for
** additional information. This feature can also be turned on and off
** using the [PRAGMA legacy_alter_table] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statement
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@ -2227,7 +2262,10 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */
#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */
#define SQLITE_DBCONFIG_MAX 1011 /* Largest DBCONFIG */
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@ -7319,7 +7357,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_IMPOSTER 25
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking

View File

@ -416,7 +416,7 @@ public:
LoadArchiveMemberHint = 0x04
};
Q_DECLARE_FLAGS(LoadHints, LoadHint)
Q_FLAG(LoadHints)
Q_FLAG(LoadHint)
...
}
//! [39]

View File

@ -109,6 +109,7 @@
# define QT_FEATURE_renameat2 -1
#endif
#define QT_FEATURE_sharedmemory -1
#define QT_FEATURE_signaling_nan -1
#define QT_FEATURE_slog2 -1
#ifdef __GLIBC_PREREQ
# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1)

View File

@ -108,9 +108,50 @@ QT_BEGIN_NAMESPACE
/*!
\internal
Implements qFpClassify() for qfloat16.
\since 5.14
bool qfloat16::isInf() const noexcept
Tests whether this \c qfloat16 value is an infinity.
\sa qIsInf()
*/
/*!
\internal
\since 5.14
bool qfloat16::isNaN() const noexcept
Tests whether this \c qfloat16 value is "not a number".
\sa qIsNaN()
*/
/*!
\since 5.14
bool qfloat16::isNormal() const noexcept
Tests whether this \c qfloat16 value is finite and in normal form.
\sa qFpClassify()
*/
/*!
\internal
\since 5.14
bool qfloat16::isFinite() const noexcept
Tests whether this \c qfloat16 value is finite.
\sa qIsFinite()
*/
/*!
\internal
\since 5.14
Implements qFpClassify() for qfloat16.
\sa qFpClassify()
*/
int qfloat16::fpClassify() const noexcept
{
return isInf() ? FP_INFINITE : isNaN() ? FP_NAN

View File

@ -48,6 +48,10 @@
#include "qoperatingsystemversion_p.h"
#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) || defined(Q_OS_WINRT)
#include "qoperatingsystemversion_win_p.h"
# if QT_CONFIG(settings)
# include "qsettings.h"
# include "qvariant.h"
# endif
#endif
#include <private/qlocale_tools_p.h>
@ -2202,6 +2206,30 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion()
QT_WARNING_POP
#endif
static QString readRegistryString(const QString &key, const QString &subKey)
{
#if QT_CONFIG(settings)
QSettings settings(key, QSettings::NativeFormat);
return settings.value(subKey).toString();
#else
Q_UNUSED(key);
Q_UNUSED(subKey);
return QString();
#endif
}
static inline QString windowsVersionKey() { return QStringLiteral(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion)"); }
static inline QString windows10ReleaseId()
{
return readRegistryString(windowsVersionKey(), QStringLiteral("ReleaseId"));
}
static inline QString windows7Build()
{
return readRegistryString(windowsVersionKey(), QStringLiteral("CurrentBuild"));
}
static QString winSp_helper()
{
const auto osv = qWindowsVersionInfo();
@ -2920,19 +2948,35 @@ QString QSysInfo::prettyProductName()
{
#if (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
const auto version = QOperatingSystemVersion::current();
const char *name = osVer_helper(version);
if (name)
return version.name() + QLatin1Char(' ') + QLatin1String(name)
# if defined(Q_OS_WIN)
+ winSp_helper()
# endif
+ QLatin1String(" (") + QString::number(version.majorVersion())
+ QLatin1Char('.') + QString::number(version.minorVersion())
+ QLatin1Char(')');
else
return version.name() + QLatin1Char(' ')
+ QString::number(version.majorVersion()) + QLatin1Char('.')
const int majorVersion = version.majorVersion();
const QString versionString = QString::number(majorVersion) + QLatin1Char('.')
+ QString::number(version.minorVersion());
QString result = version.name() + QLatin1Char(' ');
const char *name = osVer_helper(version);
if (!name)
return result + versionString;
result += QLatin1String(name);
# if !defined(Q_OS_WIN)
return result + QLatin1String(" (") + versionString + QLatin1Char(')');
# else
// (resembling winver.exe): Windows 10 "Windows 10 Version 1809"
result += QLatin1String(" Version ");
if (majorVersion >= 10) {
const auto releaseId = windows10ReleaseId();
if (!releaseId.isEmpty())
result += QLatin1String(" Version ") + releaseId;
return result;
}
// Windows 7: "Windows 7 Version 6.1 (Build 7601: Service Pack 1)"
result += versionString + QLatin1String(" (");
const auto build = windows7Build();
if (!build.isEmpty())
result += QLatin1String("Build ") + build;
const auto servicePack = winSp_helper();
if (!servicePack.isEmpty())
result += QLatin1String(": ") + servicePack;
return result + QLatin1Char(')');
# endif // Windows
#elif defined(Q_OS_HAIKU)
return QLatin1String("Haiku ") + productVersion();
#elif defined(Q_OS_UNIX)

View File

@ -81,11 +81,13 @@ Q_CORE_EXPORT bool qIsNaN(float f) { return qt_is_nan(f); }
*/
Q_CORE_EXPORT bool qIsFinite(float f) { return qt_is_finite(f); }
#if QT_CONFIG(signaling_nan)
/*!
Returns the bit pattern of a signalling NaN as a double.
\relates <QtGlobal>
*/
Q_CORE_EXPORT double qSNaN() { return qt_snan(); }
#endif
/*!
Returns the bit pattern of a quiet NaN as a double.

View File

@ -44,7 +44,6 @@
QT_BEGIN_NAMESPACE
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
@ -53,7 +52,9 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
#if QT_CONFIG(signaling_nan)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
#endif
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
@ -61,7 +62,9 @@ Q_CORE_EXPORT quint32 qFloatDistance(float a, float b);
Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
#define Q_INFINITY (QT_PREPEND_NAMESPACE(qInf)())
#if QT_CONFIG(signaling_nan)
# define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
#endif
#define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
QT_END_NAMESPACE

View File

@ -133,13 +133,14 @@ Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_inf() noexcept
return std::numeric_limits<double>::infinity();
}
// Signaling NaN
#if QT_CONFIG(signaling_nan)
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_snan() noexcept
{
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_signaling_NaN,
"platform has no definition for signaling NaN for type double");
return std::numeric_limits<double>::signaling_NaN();
}
#endif
// Quiet NaN
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_qnan() noexcept

View File

@ -90,47 +90,6 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
QT_BEGIN_NAMESPACE
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
static qsizetype qt_random_cpu(void *buffer, qsizetype count) noexcept;
# ifdef Q_PROCESSOR_X86_64
# define _rdrandXX_step _rdrand64_step
# else
# define _rdrandXX_step _rdrand32_step
# endif
static QT_FUNCTION_TARGET(RDRND) qsizetype qt_random_cpu(void *buffer, qsizetype count) noexcept
{
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
unsigned *end = ptr + count;
int retries = 10;
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
ptr += sizeof(qregisteruint)/sizeof(*ptr);
else if (--retries == 0)
goto out;
}
while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
bool ok = _rdrand32_step(ptr);
if (!ok && --retries)
continue;
if (ok)
++ptr;
break;
}
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
#else
static qsizetype qt_random_cpu(void *, qsizetype)
{
return 0;
}
#endif
enum {
// may be "overridden" by a member enum
FillBufferNoexcept = true
@ -371,8 +330,8 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin,
}
qsizetype filled = 0;
if (qt_has_hwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
filled += qt_random_cpu(buffer, count);
if (qHasHwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
filled += qRandomCpu(buffer, count);
if (filled != count && (uint(qt_randomdevice_control.loadAcquire()) & SkipSystemRNG) == 0) {
qsizetype bytesFilled =

View File

@ -81,14 +81,6 @@ static const struct {
} qt_randomdevice_control;
#endif
inline bool qt_has_hwrng()
{
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
return qCpuHasFeature(RDRND);
#else
return false;
#endif
}
QT_END_NAMESPACE

View File

@ -249,16 +249,18 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
isSymLink(). The symLinkTarget() function provides the name of the file
the symlink points to.
On Unix (including \macos and iOS), the symlink has the same size() has
the file it points to, because Unix handles symlinks
transparently; similarly, opening a symlink using QFile
effectively opens the link's target. For example:
On Unix (including \macos and iOS), the property getter functions in this
class return the properties such as times and size of the target file, not
the symlink, because Unix handles symlinks transparently. Opening a symlink
using QFile effectively opens the link's target. For example:
\snippet code/src_corelib_io_qfileinfo.cpp 0
On Windows, shortcuts are \c .lnk files. The reported size() is that of
the shortcut (not the link's target), and opening a shortcut using QFile
opens the \c .lnk file. For example:
On Windows, shortcuts (\c .lnk files) are currently treated as symlinks. As
on Unix systems, the property getters return the size of the targeted file,
not the \c .lnk file itself. This behavior is deprecated and will likely be
removed in a future version of Qt, after which \c .lnk files will be treated
as regular files.
\snippet code/src_corelib_io_qfileinfo.cpp 1
@ -903,6 +905,9 @@ QDir QFileInfo::absoluteDir() const
/*!
Returns \c true if the user can read the file; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is
readable (not the symlink).
\note If the \l{NTFS permissions} check has not been enabled, the result
on Windows will merely reflect whether the file exists.
@ -920,6 +925,9 @@ bool QFileInfo::isReadable() const
/*!
Returns \c true if the user can write to the file; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is
writeable (not the symlink).
\note If the \l{NTFS permissions} check has not been enabled, the result on
Windows will merely reflect whether the file is marked as Read Only.
@ -937,6 +945,9 @@ bool QFileInfo::isWritable() const
/*!
Returns \c true if the file is executable; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is
executable (not the symlink).
\sa isReadable(), isWritable(), permission()
*/
bool QFileInfo::isExecutable() const
@ -951,8 +962,13 @@ bool QFileInfo::isExecutable() const
/*!
Returns \c true if this is a `hidden' file; otherwise returns \c false.
\b{Note:} This function returns \c true for the special entries
"." and ".." on Unix, even though QDir::entryList threats them as shown.
\b{Note:} This function returns \c true for the special entries "." and
".." on Unix, even though QDir::entryList threats them as shown. And note
that, since this function inspects the file name, on Unix it will inspect
the name of the symlink, if this file is a symlink, not the target's name.
On Windows, this function returns \c true if the target file is hidden (not
the symlink).
*/
bool QFileInfo::isHidden() const
{
@ -991,6 +1007,9 @@ bool QFileInfo::isNativePath() const
link to a file. Returns \c false if the
object points to something which isn't a file, such as a directory.
If the file is a symlink, this function returns true if the target is a
regular file (not the symlink).
\sa isDir(), isSymLink(), isBundle()
*/
bool QFileInfo::isFile() const
@ -1006,6 +1025,9 @@ bool QFileInfo::isFile() const
Returns \c true if this object points to a directory or to a symbolic
link to a directory; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is a
directory (not the symlink).
\sa isFile(), isSymLink(), isBundle()
*/
bool QFileInfo::isDir() const
@ -1023,6 +1045,9 @@ bool QFileInfo::isDir() const
Returns \c true if this object points to a bundle or to a symbolic
link to a bundle on \macos and iOS; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is a
bundle (not the symlink).
\sa isDir(), isSymLink(), isFile()
*/
bool QFileInfo::isBundle() const
@ -1044,7 +1069,8 @@ bool QFileInfo::isBundle() const
the \l{symLinkTarget()}{link's target}.
In addition, true will be returned for shortcuts (\c *.lnk files) on
Windows. Opening those will open the \c .lnk file itself.
Windows. This behavior is deprecated and will likely change in a future
version of Qt. Opening those will open the \c .lnk file itself.
Example:
@ -1190,6 +1216,9 @@ QString QFileInfo::symLinkTarget() const
milliseconds). On Windows, it will return an empty string unless
the \l{NTFS permissions} check has been enabled.
If the file is a symlink, this function returns the owner of the target
(not the symlink).
\sa ownerId(), group(), groupId()
*/
QString QFileInfo::owner() const
@ -1206,6 +1235,9 @@ QString QFileInfo::owner() const
On Windows and on systems where files do not have owners this
function returns ((uint) -2).
If the file is a symlink, this function returns the id of the owner of the target
(not the symlink).
\sa owner(), group(), groupId()
*/
uint QFileInfo::ownerId() const
@ -1225,6 +1257,9 @@ uint QFileInfo::ownerId() const
This function can be time consuming under Unix (in the order of
milliseconds).
If the file is a symlink, this function returns the owning group of the
target (not the symlink).
\sa groupId(), owner(), ownerId()
*/
QString QFileInfo::group() const
@ -1241,6 +1276,9 @@ QString QFileInfo::group() const
On Windows and on systems where files do not have groups this
function always returns (uint) -2.
If the file is a symlink, this function returns the id of the group owning the
target (not the symlink).
\sa group(), owner(), ownerId()
*/
uint QFileInfo::groupId() const
@ -1266,6 +1304,9 @@ uint QFileInfo::groupId() const
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 10
If the file is a symlink, this function checks the permissions of the
target (not the symlink).
\sa isReadable(), isWritable(), isExecutable()
*/
bool QFileInfo::permission(QFile::Permissions permissions) const
@ -1288,6 +1329,9 @@ bool QFileInfo::permission(QFile::Permissions permissions) const
\note The result might be inaccurate on Windows if the
\l{NTFS permissions} check has not been enabled.
If the file is a symlink, this function returns the permissions of the
target (not the symlink).
*/
QFile::Permissions QFileInfo::permissions() const
{
@ -1305,6 +1349,9 @@ QFile::Permissions QFileInfo::permissions() const
Returns the file size in bytes. If the file does not exist or cannot be
fetched, 0 is returned.
If the file is a symlink, the size of the target file is returned
(not the symlink).
\sa exists()
*/
qint64 QFileInfo::size() const
@ -1334,6 +1381,9 @@ qint64 QFileInfo::size() const
the time the file was created, metadataChangeTime() to get the time its
metadata was last changed, or lastModified() to get the time it was last modified.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa birthTime(), metadataChangeTime(), lastModified(), lastRead()
*/
QDateTime QFileInfo::created() const
@ -1352,6 +1402,9 @@ QDateTime QFileInfo::created() const
If the file birth time is not available, this function returns an invalid
QDateTime.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa lastModified(), lastRead(), metadataChangeTime()
*/
QDateTime QFileInfo::birthTime() const
@ -1366,6 +1419,9 @@ QDateTime QFileInfo::birthTime() const
user writes or sets inode information (for example, changing the file
permissions).
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa lastModified(), lastRead()
*/
QDateTime QFileInfo::metadataChangeTime() const
@ -1376,6 +1432,9 @@ QDateTime QFileInfo::metadataChangeTime() const
/*!
Returns the date and local time when the file was last modified.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa birthTime(), lastRead(), metadataChangeTime(), fileTime()
*/
QDateTime QFileInfo::lastModified() const
@ -1389,6 +1448,9 @@ QDateTime QFileInfo::lastModified() const
On platforms where this information is not available, returns the
same as lastModified().
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa birthTime(), lastModified(), metadataChangeTime(), fileTime()
*/
QDateTime QFileInfo::lastRead() const
@ -1402,6 +1464,9 @@ QDateTime QFileInfo::lastRead() const
Returns the file time specified by \a time. If the time cannot be
determined, an invalid date time is returned.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa QFile::FileTime, QDateTime::isValid()
*/
QDateTime QFileInfo::fileTime(QFile::FileTime time) const

View File

@ -69,7 +69,9 @@ static bool checkNameDecodable(const char *d_name, qsizetype len)
# ifdef QT_LOCALE_IS_UTF8
int mibEnum = 106;
# else
int mibEnum = codec->mibEnum();
int mibEnum = 4; // Latin 1
if (codec)
mibEnum = codec->mibEnum();
# endif
if (Q_LIKELY(mibEnum == 106)) // UTF-8
return QUtf8::isValidUtf8(d_name, len).isValidUtf8;

View File

@ -423,7 +423,7 @@ bool QEventDispatcherCoreFoundation::processPostedEvents()
m_processEvents.processedPostedEvents = true;
qCDebug(lcEventDispatcher) << "Sending posted events for"
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.load());
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
QCoreApplication::sendPostedEvents();
return true;

View File

@ -0,0 +1,153 @@
/****************************************************************************
**
** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QWAITCONDITION_P_H
#define QWAITCONDITION_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of qmutex.cpp, qmutex_unix.cpp, and qmutex_win.cpp. This header
// file may change from version to version without notice, or even be
// removed.
//
// We mean it.
//
#include <QtCore/QWaitCondition>
#include <QtCore/QMutex>
#include <QtCore/QDeadlineTimer>
#include <condition_variable>
#include <mutex>
QT_BEGIN_NAMESPACE
namespace QtPrivate
{
#if defined(Q_OS_INTEGRITY)
class condition_variable;
class mutex : private QMutex
{
friend class QtPrivate::condition_variable;
public:
// all special member functions are ok!
// do not expose the (QMutex::Recursive) ctor
// don't use 'using QMutex::lock;' etc as those have the wrong noexcept
void lock() { return QMutex::lock(); }
void unlock() { return QMutex::unlock(); }
bool try_lock() { return QMutex::tryLock(); }
};
class condition_variable : private QWaitCondition
{
public:
// all special member functions are ok!
void notify_one() { QWaitCondition::wakeOne(); }
void notify_all() { QWaitCondition::wakeAll(); }
void wait(std::unique_lock<QtPrivate::mutex> &lock) { QWaitCondition::wait(lock.mutex()); }
template <class Predicate>
void wait(std::unique_lock<QtPrivate::mutex> &lock, Predicate p)
{
while (!p())
wait(lock);
}
template <typename Rep, typename Period>
std::cv_status wait_for(std::unique_lock<QtPrivate::mutex> &lock,
const std::chrono::duration<Rep, Period> &d)
{
return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{d})
? std::cv_status::no_timeout
: std::cv_status::timeout;
}
template <typename Rep, typename Period, typename Predicate>
bool wait_for(std::unique_lock<QtPrivate::mutex> &lock,
const std::chrono::duration<Rep, Period> &d, Predicate p)
{
const auto timer = QDeadlineTimer{d};
while (!p()) {
if (!QWaitCondition::wait(lock.mutex(), timer))
return p();
}
return true;
}
template <typename Clock, typename Duration>
std::cv_status wait_until(std::unique_lock<QtPrivate::mutex> &lock,
const std::chrono::time_point<Clock, Duration> &t)
{
return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{t})
? std::cv_status::no_timeout
: std::cv_status::timeout;
}
template <typename Clock, typename Duration, typename Predicate>
bool wait_until(std::unique_lock<QtPrivate::mutex> &lock,
const std::chrono::time_point<Clock, Duration> &t, Predicate p)
{
const auto timer = QDeadlineTimer{t};
while (!p()) {
if (!QWaitCondition::wait(lock.mutex(), timer))
return p();
}
return true;
}
};
#else // Integrity
using mutex = std::mutex;
using condition_variable = std::condition_variable;
#endif // Integrity
} // namespace QtPrivate
QT_END_NAMESPACE
#endif /* QWAITCONDITION_P_H */

View File

@ -6,6 +6,7 @@ HEADERS += \
thread/qrunnable.h \
thread/qthread.h \
thread/qthreadstorage.h \
thread/qwaitcondition_p.h \
thread/qwaitcondition.h
SOURCES += \

View File

@ -701,7 +701,7 @@ const QCalendarBackend *QCalendarBackend::fromEnum(QCalendar::System system)
calendar being constructed by other means first. With no argument, the
default constructor returns the Gregorian calendar.
\sa QCalendar, System
\sa QCalendar, System, isValid()
*/
QCalendar::QCalendar()
@ -723,6 +723,15 @@ QCalendar::QCalendar(QLatin1String name)
QCalendar::QCalendar(QStringView name)
: d(QCalendarBackend::fromName(name)) {}
/*
\fn bool QCalendar::isValid() const
Returns true if this is a valid calendar object.
Constructing a calendar with an unrecognised calendar name may result in an
invalid object. Use this method to check after creating a calendar by name.
*/
// Date queries:
/*!

View File

@ -137,7 +137,7 @@ public:
explicit QCalendar(QStringView name);
// QCalendar is a trivially copyable value type.
bool isValid() { return d != nullptr; }
bool isValid() const { return d != nullptr; }
// Date queries:
int daysInMonth(int month, int year = Unspecified) const;

View File

@ -3548,6 +3548,7 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT
*/
/*!
\since 5.14
\enum QDateTime::YearRange
This enumerated type describes the range of years (in the Gregorian

View File

@ -376,6 +376,38 @@ static quint64 detectProcessorFeatures()
features &= ~AllAVX512;
}
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
/**
* Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a
* failing random generation instruction, which always returns
* 0xffffffff, even when generation was "successful".
*
* This code checks if hardware random generator generates four consecutive
* equal numbers. If it does, then we probably have a failing one and
* should disable it completely.
*
* https://bugreports.qt.io/browse/QTBUG-69423
*/
if (features & CpuFeatureRDRND) {
const qsizetype testBufferSize = 4;
unsigned testBuffer[4] = {};
const qsizetype generated = qRandomCpu(testBuffer, testBufferSize);
if (Q_UNLIKELY(generated == testBufferSize &&
testBuffer[0] == testBuffer[1] &&
testBuffer[1] == testBuffer[2] &&
testBuffer[2] == testBuffer[3])) {
fprintf(stderr, "WARNING: CPU random generator seem to be failing, disable hardware random number generation\n");
fprintf(stderr, "WARNING: RDRND generated: 0x%x 0x%x 0x%x 0x%x\n",
testBuffer[0], testBuffer[1], testBuffer[2], testBuffer[3]);
features &= ~CpuFeatureRDRND;
}
}
#endif
return features;
}
@ -590,4 +622,40 @@ void qDumpCPUFeatures()
puts("");
}
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
# ifdef Q_PROCESSOR_X86_64
# define _rdrandXX_step _rdrand64_step
# else
# define _rdrandXX_step _rdrand32_step
# endif
QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
{
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
unsigned *end = ptr + count;
int retries = 10;
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
ptr += sizeof(qregisteruint)/sizeof(*ptr);
else if (--retries == 0)
goto out;
}
while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
bool ok = _rdrand32_step(ptr);
if (!ok && --retries)
continue;
if (ok)
++ptr;
break;
}
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
#endif
QT_END_NAMESPACE

View File

@ -346,6 +346,15 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2];
#endif
Q_CORE_EXPORT quint64 qDetectCpuFeatures();
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
Q_CORE_EXPORT qsizetype qRandomCpu(void *, qsizetype) noexcept;
#else
static inline qsizetype qRandomCpu(void *, qsizetype) noexcept
{
return 0;
}
#endif
static inline quint64 qCpuFeatures()
{
quint64 features = qt_cpu_features[0].loadRelaxed();
@ -362,6 +371,15 @@ static inline quint64 qCpuFeatures()
#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
|| ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
inline bool qHasHwrng()
{
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
return qCpuHasFeature(RDRND);
#else
return false;
#endif
}
#define ALIGNMENT_PROLOGUE_16BYTES(ptr, i, length) \
for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i)

View File

@ -104,7 +104,7 @@ public:
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
{
resize(list.size());
resize(int(list.size())); // ### q6sizetype
std::copy(list.begin(), list.end(),
QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
return *this;

View File

@ -186,7 +186,7 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, MyDictionary &myd
argument.beginMap();
mydict.clear();
while ( !argMap.atEnd() ) {
while ( !argument.atEnd() ) {
int key;
MyValue value;
argument.beginMapEntry();

View File

@ -44,7 +44,9 @@
#include <QStandardPaths>
#include <QDir>
#include <QSaveFile>
#include <QCoreApplication>
#include <QLoggingCategory>
#include <QCryptographicHash>
#ifdef Q_OS_UNIX
#include <sys/mman.h>
@ -53,7 +55,7 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
Q_LOGGING_CATEGORY(lcOpenGLProgramDiskCache, "qt.opengl.diskcache")
#ifndef GL_CONTEXT_LOST
#define GL_CONTEXT_LOST 0x0507
@ -63,6 +65,10 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#endif
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#endif
const quint32 BINSHADER_MAGIC = 0x5174;
const quint32 BINSHADER_VERSION = 0x3;
const quint32 BINSHADER_QTVERSION = QT_VERSION;
@ -94,6 +100,15 @@ GLEnvInfo::GLEnvInfo()
glversion = QByteArray(version);
}
QByteArray QOpenGLProgramBinaryCache::ProgramDesc::cacheKey() const
{
QCryptographicHash keyBuilder(QCryptographicHash::Sha1);
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : shaders)
keyBuilder.addData(shader.source);
return keyBuilder.result().toHex();
}
static inline bool qt_ensureWritableDir(const QString &name)
{
QDir::root().mkpath(name);
@ -113,7 +128,7 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
}
qCDebug(DBG_SHADER_CACHE, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
}
QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
@ -144,24 +159,24 @@ static inline QByteArray readStr(const uchar **p)
bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
{
if (buf.size() < BASE_HEADER_SIZE) {
qCDebug(DBG_SHADER_CACHE, "Cached size too small");
qCDebug(lcOpenGLProgramDiskCache, "Cached size too small");
return false;
}
const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
if (readUInt(&p) != BINSHADER_MAGIC) {
qCDebug(DBG_SHADER_CACHE, "Magic does not match");
qCDebug(lcOpenGLProgramDiskCache, "Magic does not match");
return false;
}
if (readUInt(&p) != BINSHADER_VERSION) {
qCDebug(DBG_SHADER_CACHE, "Version does not match");
qCDebug(lcOpenGLProgramDiskCache, "Version does not match");
return false;
}
if (readUInt(&p) != BINSHADER_QTVERSION) {
qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
qCDebug(lcOpenGLProgramDiskCache, "Qt version does not match");
return false;
}
if (readUInt(&p) != sizeof(quintptr)) {
qCDebug(DBG_SHADER_CACHE, "Architecture does not match");
qCDebug(lcOpenGLProgramDiskCache, "Architecture does not match");
return false;
}
return true;
@ -186,7 +201,7 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLenum err = funcs->glGetError();
if (err != GL_NO_ERROR) {
qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return false;
@ -194,13 +209,13 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLint linkStatus = 0;
funcs->glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, linkStatus = 0x%x, err = 0x%x",
programId, blobSize, blobFormat, linkStatus, err);
return false;
}
qCDebug(DBG_SHADER_CACHE, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
qCDebug(lcOpenGLProgramDiskCache, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return true;
}
@ -308,19 +323,19 @@ bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
if (vendor != info.glvendor) {
// readStr returns non-null terminated strings just pointing to inside
// 'p' so must print these via the stream qCDebug and not constData().
qCDebug(DBG_SHADER_CACHE) << "GL_VENDOR does not match" << vendor << info.glvendor;
qCDebug(lcOpenGLProgramDiskCache) << "GL_VENDOR does not match" << vendor << info.glvendor;
undertaker.setActive();
return false;
}
QByteArray renderer = readStr(&p);
if (renderer != info.glrenderer) {
qCDebug(DBG_SHADER_CACHE) << "GL_RENDERER does not match" << renderer << info.glrenderer;
qCDebug(lcOpenGLProgramDiskCache) << "GL_RENDERER does not match" << renderer << info.glrenderer;
undertaker.setActive();
return false;
}
QByteArray version = readStr(&p);
if (version != info.glversion) {
qCDebug(DBG_SHADER_CACHE) << "GL_VERSION does not match" << version << info.glversion;
qCDebug(lcOpenGLProgramDiskCache) << "GL_VERSION does not match" << version << info.glversion;
undertaker.setActive();
return false;
}
@ -373,7 +388,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
const int totalSize = headerSize + paddingSize + blobSize;
qCDebug(DBG_SHADER_CACHE, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
qCDebug(lcOpenGLProgramDiskCache, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
if (!blobSize)
return;
@ -407,7 +422,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
#endif
funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
if (blobSize != outSize) {
qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
qCDebug(lcOpenGLProgramDiskCache, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
return;
}
@ -423,9 +438,9 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
if (f.write(blob) < blob.length())
#endif
qCDebug(DBG_SHADER_CACHE, "Failed to write %s to shader cache", qPrintable(f.fileName()));
qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(f.fileName()));
} else {
qCDebug(DBG_SHADER_CACHE, "Failed to create %s in shader cache", qPrintable(f.fileName()));
qCDebug(lcOpenGLProgramDiskCache, "Failed to create %s in shader cache", qPrintable(f.fileName()));
}
}
@ -442,4 +457,45 @@ void QOpenGLProgramBinaryCache::initializeProgramBinaryOES(QOpenGLContext *conte
}
#endif
QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
: QOpenGLSharedResource(context->shareGroup()),
m_supported(false)
{
if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via app attribute");
return;
}
if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via env var");
return;
}
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) {
if (ctx->isOpenGLES()) {
qCDebug(lcOpenGLProgramDiskCache, "OpenGL ES v%d context", ctx->format().majorVersion());
if (ctx->format().majorVersion() >= 3) {
m_supported = true;
} else {
const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
qCDebug(lcOpenGLProgramDiskCache, "GL_OES_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
} else {
const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
qCDebug(lcOpenGLProgramDiskCache, "GL_ARB_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
if (m_supported) {
GLint fmtCount = 0;
ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
qCDebug(lcOpenGLProgramDiskCache, "Supported binary format count = %d", fmtCount);
m_supported = fmtCount > 0;
}
}
qCDebug(lcOpenGLProgramDiskCache, "Shader cache supported = %d", m_supported);
}
QT_END_NAMESPACE

View File

@ -52,25 +52,31 @@
//
#include <QtGui/qtguiglobal.h>
#include <QtGui/qopenglshaderprogram.h>
#include <QtCore/qcache.h>
#include <QtCore/qmutex.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/private/qshader_p.h>
QT_BEGIN_NAMESPACE
// These classes are also used by the OpenGL backend of QRhi. They must
// therefore stay independent from QOpenGLShader(Program). Must rely only on
// QOpenGLContext/Functions.
class QOpenGLProgramBinaryCache
{
public:
struct ShaderDesc {
ShaderDesc() { }
ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray())
: type(type), source(source)
ShaderDesc(QShader::Stage stage, const QByteArray &source = QByteArray())
: stage(stage), source(source)
{ }
QOpenGLShader::ShaderType type;
QShader::Stage stage;
QByteArray source;
};
struct ProgramDesc {
QVector<ShaderDesc> shaders;
QByteArray cacheKey() const;
};
QOpenGLProgramBinaryCache();
@ -103,6 +109,36 @@ private:
QMutex m_mutex;
};
// While unlikely, one application can in theory use contexts with different versions
// or profiles. Therefore any version- or extension-specific checks must be done on a
// per-context basis, not just once per process. QOpenGLSharedResource enables this,
// although it's once-per-sharing-context-group, not per-context. Still, this should
// be good enough in practice.
class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
{
public:
QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
void invalidateResource() override { }
void freeResource(QOpenGLContext *) override { }
bool isSupported() const { return m_supported; }
private:
bool m_supported;
};
class QOpenGLProgramBinarySupportCheckWrapper
{
public:
QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
{
return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
}
private:
QOpenGLMultiGroupSharedResource m_resource;
};
QT_END_NAMESPACE
#endif

View File

@ -47,8 +47,6 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/qtransform.h>
#include <QtGui/QColor>
#include <QtGui/QSurfaceFormat>
@ -179,7 +177,7 @@ QT_BEGIN_NAMESPACE
(requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
*/
Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
// For GLES 3.1/3.2
#ifndef GL_GEOMETRY_SHADER
@ -210,10 +208,6 @@ Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
#endif
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#endif
#ifndef QT_OPENGL_ES_2
static inline bool isFormatGLES(const QSurfaceFormat &f)
{
@ -1081,6 +1075,44 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
return addCacheableShaderFromSourceCode(type, QByteArray(source));
}
static inline QShader::Stage qt_shaderTypeToStage(QOpenGLShader::ShaderType type)
{
switch (type) {
case QOpenGLShader::Vertex:
return QShader::VertexStage;
case QOpenGLShader::Fragment:
return QShader::FragmentStage;
case QOpenGLShader::Geometry:
return QShader::GeometryStage;
case QOpenGLShader::TessellationControl:
return QShader::TessellationControlStage;
case QOpenGLShader::TessellationEvaluation:
return QShader::TessellationEvaluationStage;
case QOpenGLShader::Compute:
return QShader::ComputeStage;
}
return QShader::VertexStage;
}
static inline QOpenGLShader::ShaderType qt_shaderStageToType(QShader::Stage stage)
{
switch (stage) {
case QShader::VertexStage:
return QOpenGLShader::Vertex;
case QShader::TessellationControlStage:
return QOpenGLShader::TessellationControl;
case QShader::TessellationEvaluationStage:
return QOpenGLShader::TessellationEvaluation;
case QShader::GeometryStage:
return QOpenGLShader::Geometry;
case QShader::FragmentStage:
return QOpenGLShader::Fragment;
case QShader::ComputeStage:
return QOpenGLShader::Compute;
}
return QOpenGLShader::Vertex;
}
/*!
\overload
@ -1109,7 +1141,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceCode(type, source);
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source));
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source));
return true;
}
@ -1166,7 +1198,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceFile(type, fileName);
QOpenGLProgramBinaryCache::ShaderDesc shader(type);
QOpenGLProgramBinaryCache::ShaderDesc shader(qt_shaderTypeToStage(type));
// NB! It could be tempting to defer reading the file contents and just
// hash the filename as the cache key, perhaps combined with last-modified
// timestamp checks. However, this would raise a number of issues (no
@ -3720,77 +3752,6 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
return true;
}
// While unlikely, one application can in theory use contexts with different versions
// or profiles. Therefore any version- or extension-specific checks must be done on a
// per-context basis, not just once per process. QOpenGLSharedResource enables this,
// although it's once-per-sharing-context-group, not per-context. Still, this should
// be good enough in practice.
class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
{
public:
QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
void invalidateResource() override { }
void freeResource(QOpenGLContext *) override { }
bool isSupported() const { return m_supported; }
private:
bool m_supported;
};
QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
: QOpenGLSharedResource(context->shareGroup()),
m_supported(false)
{
if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute");
return;
}
if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var");
return;
}
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) {
if (ctx->isOpenGLES()) {
qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion());
if (ctx->format().majorVersion() >= 3) {
m_supported = true;
} else {
const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
qCDebug(DBG_SHADER_CACHE, "GL_OES_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
} else {
const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
if (m_supported) {
GLint fmtCount = 0;
ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d", fmtCount);
m_supported = fmtCount > 0;
}
}
qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d", m_supported);
}
class QOpenGLProgramBinarySupportCheckWrapper
{
public:
QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
{
return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
}
private:
QOpenGLMultiGroupSharedResource m_resource;
};
bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
{
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
@ -3801,7 +3762,7 @@ bool QOpenGLShaderProgramPrivate::compileCacheable()
{
Q_Q(QOpenGLShaderProgram);
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q));
QScopedPointer<QOpenGLShader> s(new QOpenGLShader(qt_shaderStageToType(shader.stage), q));
if (!s->compileSourceCode(shader.source)) {
log = s->log();
return false;
@ -3819,24 +3780,20 @@ bool QOpenGLShaderProgramPrivate::linkBinary()
Q_Q(QOpenGLShaderProgram);
QCryptographicHash keyBuilder(QCryptographicHash::Sha1);
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders))
keyBuilder.addData(shader.source);
const QByteArray cacheKey = keyBuilder.result().toHex();
if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg))
qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s",
const QByteArray cacheKey = binaryProgram.cacheKey();
if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg))
qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s",
binaryProgram.shaders.count(), cacheKey.constData());
bool needsCompile = true;
if (binCache.load(cacheKey, q->programId())) {
qCDebug(DBG_SHADER_CACHE, "Program binary received from cache");
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache");
needsCompile = false;
}
bool needsSave = false;
if (needsCompile) {
qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling");
qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling");
if (compileCacheable())
needsSave = true;
else

View File

@ -34,7 +34,21 @@
**
****************************************************************************/
#include <qglobal.h>
#ifndef CS_TDR_P_H
#define CS_TDR_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of other Qt classes. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qglobal.h>
#ifdef Q_OS_WIN
@ -207,3 +221,5 @@ const BYTE g_killDeviceByTimingOut[] =
};
#endif // Q_OS_WIN
#endif // CS_TDR_P_H

View File

@ -707,8 +707,8 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
Used with QRhiCommandBuffer::setViewport().
\note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
bottom-left.
QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
bottom-left. Negative width or height are not allowed.
Typical usage is like the following:
@ -737,7 +737,9 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
Constructs a viewport description with the rectangle specified by \a x, \a
y, \a w, \a h and the depth range \a minDepth and \a maxDepth.
\note x and y are assumed to be the bottom-left position.
\note \a x and \a y are assumed to be the bottom-left position. \a w and \a
h should not be negative, the viewport will be ignored by
QRhiCommandBuffer::setViewport() otherwise.
\sa QRhi::clipSpaceCorrMatrix()
*/
@ -810,8 +812,12 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v)
only possible with a QRhiGraphicsPipeline that has
QRhiGraphicsPipeline::UsesScissor set.
\note QRhi assumes OpenGL-style scissor coordinates, meaning x and y are
bottom-left.
QRhi assumes OpenGL-style scissor coordinates, meaning x and y are
bottom-left. Negative width or height are not allowed. However, apart from
that, the flexible OpenGL semantics apply: negative x and y, partially out
of bounds rectangles, etc. will be handled gracefully, clamping as
appropriate. Therefore, any rendering logic targeting OpenGL can feed
scissor rectangles into QRhiScissor as-is, without any adaptation.
\sa QRhiCommandBuffer::setScissor(), QRhiViewport
*/
@ -826,7 +832,11 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v)
Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and
\a h.
\note x and y are assumed to be the bottom-left position.
\note \a x and \a y are assumed to be the bottom-left position. Negative \a w
or \a h are not allowed, such scissor rectangles will be ignored by
QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply:
negative x and y, partially out of bounds rectangles, etc. will be handled
gracefully, clamping as appropriate.
*/
QRhiScissor::QRhiScissor(int x, int y, int w, int h)
: m_rect { { x, y, w, h } }
@ -1971,6 +1981,14 @@ QRhiResource::Type QRhiBuffer::resourceType() const
How the renderbuffer is implemented by a backend is not exposed to the
applications. In some cases it may be backed by ordinary textures, while in
others there may be a different kind of native resource used.
Renderbuffers that are used as (and are only used as) depth-stencil buffers
in combination with a QRhiSwapChain's color buffers should have the
UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers,
depending on the backend and the underlying APIs, be more efficient, and
QRhi provides automatic sizing behavior to match the color buffers, which
means calling setPixelSize() and build() are not necessary for such
renderbuffers.
*/
/*!
@ -1986,12 +2004,15 @@ QRhiResource::Type QRhiBuffer::resourceType() const
Flag values for flags() and setFlags()
\value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
that the renderbuffer is only used in combination with a QRhiSwapChain and
never in other ways. Relevant with some backends, while others ignore it.
With OpenGL where a separate windowing system interface API is in use (EGL,
GLX, etc.), the flag is important since it avoids creating any actual
resource as there is already a windowing system provided depth/stencil
buffer as requested by QSurfaceFormat.
that the renderbuffer is only used in combination with a QRhiSwapChain, and
never in any other way. This provides automatic sizing and resource
rebuilding, so calling setPixelSize() or build() is not needed whenever
this flag is set. This flag value may also trigger backend-specific
behavior, for example with OpenGL, where a separate windowing system
interface API is in use (EGL, GLX, etc.), the flag is especially important
as it avoids creating any actual renderbuffer resource as there is already
a windowing system provided depth/stencil buffer as requested by
QSurfaceFormat.
*/
/*!
@ -2513,16 +2534,8 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
be used with the same pipeline, assuming the pipeline was built with one of
them in the first place.
Creating and then using a new \c srb2 that is very similar to \c srb with
the exception of referencing another texture could be implemented like the
following:
\badcode
srb2 = rhi->newShaderResourceBindings();
QVector<QRhiShaderResourceBinding> bindings = srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, anotherTexture, sampler);
srb2->setBindings(bindings);
srb2->build();
...
cb->setGraphicsPipeline(ps);
cb->setShaderResources(srb2); // binds srb2
@ -2624,43 +2637,10 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
\internal
*/
QRhiShaderResourceBinding::QRhiShaderResourceBinding()
: d(new QRhiShaderResourceBindingPrivate)
{
}
/*!
\internal
*/
void QRhiShaderResourceBinding::detach()
{
qAtomicDetach(d);
}
/*!
\internal
*/
QRhiShaderResourceBinding::QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other)
: d(other.d)
{
d->ref.ref();
}
/*!
\internal
*/
QRhiShaderResourceBinding &QRhiShaderResourceBinding::operator=(const QRhiShaderResourceBinding &other)
{
qAtomicAssign(d, other.d);
return *this;
}
/*!
Destructor.
*/
QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
{
if (!d->ref.deref())
delete d;
// Zero out everything, including possible padding, because will use
// qHashBits on it.
memset(&d.u, 0, sizeof(d.u));
}
/*!
@ -2677,8 +2657,7 @@ QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
*/
bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
{
return (d == other.d)
|| (d->binding == other.d->binding && d->stage == other.d->stage && d->type == other.d->type);
return d.binding == other.d.binding && d.stage == other.d.stage && d.type == other.d.type;
}
/*!
@ -2691,15 +2670,13 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = UniformBuffer;
d->u.ubuf.buf = buf;
d->u.ubuf.offset = 0;
d->u.ubuf.maybeSize = 0; // entire buffer
d->u.ubuf.hasDynamicOffset = false;
b.d.binding = binding;
b.d.stage = stage;
b.d.type = UniformBuffer;
b.d.u.ubuf.buf = buf;
b.d.u.ubuf.offset = 0;
b.d.u.ubuf.maybeSize = 0; // entire buffer
b.d.u.ubuf.hasDynamicOffset = false;
return b;
}
@ -2720,9 +2697,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.ubuf.offset = offset;
d->u.ubuf.maybeSize = size;
b.d.u.ubuf.offset = offset;
b.d.u.ubuf.maybeSize = size;
return b;
}
@ -2741,8 +2717,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff
int binding, StageFlags stage, QRhiBuffer *buf, int size)
{
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.ubuf.hasDynamicOffset = true;
b.d.u.ubuf.hasDynamicOffset = true;
return b;
}
@ -2755,13 +2730,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = SampledTexture;
d->u.stex.tex = tex;
d->u.stex.sampler = sampler;
b.d.binding = binding;
b.d.stage = stage;
b.d.type = SampledTexture;
b.d.u.stex.tex = tex;
b.d.u.stex.sampler = sampler;
return b;
}
@ -2777,13 +2750,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = ImageLoad;
d->u.simage.tex = tex;
d->u.simage.level = level;
b.d.binding = binding;
b.d.stage = stage;
b.d.type = ImageLoad;
b.d.u.simage.tex = tex;
b.d.u.simage.level = level;
return b;
}
@ -2799,8 +2770,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = ImageStore;
b.d.type = ImageStore;
return b;
}
@ -2816,8 +2786,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = ImageLoadStore;
b.d.type = ImageLoadStore;
return b;
}
@ -2831,14 +2800,12 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = BufferLoad;
d->u.sbuf.buf = buf;
d->u.sbuf.offset = 0;
d->u.sbuf.maybeSize = 0; // entire buffer
b.d.binding = binding;
b.d.stage = stage;
b.d.type = BufferLoad;
b.d.u.sbuf.buf = buf;
b.d.u.sbuf.offset = 0;
b.d.u.sbuf.maybeSize = 0; // entire buffer
return b;
}
@ -2854,9 +2821,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.sbuf.offset = offset;
d->u.sbuf.maybeSize = size;
b.d.u.sbuf.offset = offset;
b.d.u.sbuf.maybeSize = size;
return b;
}
@ -2870,8 +2836,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = BufferStore;
b.d.type = BufferStore;
return b;
}
@ -2887,9 +2852,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferStore(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.sbuf.offset = offset;
d->u.sbuf.maybeSize = size;
b.d.u.sbuf.offset = offset;
b.d.u.sbuf.maybeSize = size;
return b;
}
@ -2903,8 +2867,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = BufferLoadStore;
b.d.type = BufferLoadStore;
return b;
}
@ -2920,9 +2883,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.sbuf.offset = offset;
d->u.sbuf.maybeSize = size;
b.d.u.sbuf.offset = offset;
b.d.u.sbuf.maybeSize = size;
return b;
}
@ -2938,28 +2900,32 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
*/
bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW
{
if (a.d == b.d)
const QRhiShaderResourceBinding::Data *da = a.data();
const QRhiShaderResourceBinding::Data *db = b.data();
if (da == db)
return true;
if (a.d->binding != b.d->binding
|| a.d->stage != b.d->stage
|| a.d->type != b.d->type)
if (da->binding != db->binding
|| da->stage != db->stage
|| da->type != db->type)
{
return false;
}
switch (a.d->type) {
switch (da->type) {
case QRhiShaderResourceBinding::UniformBuffer:
if (a.d->u.ubuf.buf != b.d->u.ubuf.buf
|| a.d->u.ubuf.offset != b.d->u.ubuf.offset
|| a.d->u.ubuf.maybeSize != b.d->u.ubuf.maybeSize)
if (da->u.ubuf.buf != db->u.ubuf.buf
|| da->u.ubuf.offset != db->u.ubuf.offset
|| da->u.ubuf.maybeSize != db->u.ubuf.maybeSize)
{
return false;
}
break;
case QRhiShaderResourceBinding::SampledTexture:
if (a.d->u.stex.tex != b.d->u.stex.tex
|| a.d->u.stex.sampler != b.d->u.stex.sampler)
if (da->u.stex.tex != db->u.stex.tex
|| da->u.stex.sampler != db->u.stex.sampler)
{
return false;
}
@ -2969,8 +2935,8 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
case QRhiShaderResourceBinding::ImageStore:
Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
if (a.d->u.simage.tex != b.d->u.simage.tex
|| a.d->u.simage.level != b.d->u.simage.level)
if (da->u.simage.tex != db->u.simage.tex
|| da->u.simage.level != db->u.simage.level)
{
return false;
}
@ -2980,9 +2946,9 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
case QRhiShaderResourceBinding::BufferStore:
Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
if (a.d->u.sbuf.buf != b.d->u.sbuf.buf
|| a.d->u.sbuf.offset != b.d->u.sbuf.offset
|| a.d->u.sbuf.maybeSize != b.d->u.sbuf.maybeSize)
if (da->u.sbuf.buf != db->u.sbuf.buf
|| da->u.sbuf.offset != db->u.sbuf.offset
|| da->u.sbuf.maybeSize != db->u.sbuf.maybeSize)
{
return false;
}
@ -3013,16 +2979,16 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
*/
uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW
{
const char *u = reinterpret_cast<const char *>(&b.d->u);
return seed + uint(b.d->binding) + 10 * uint(b.d->stage) + 100 * uint(b.d->type)
+ qHash(QByteArray::fromRawData(u, sizeof(b.d->u)), seed);
const QRhiShaderResourceBinding::Data *d = b.data();
return seed + uint(d->binding) + 10 * uint(d->stage) + 100 * uint(d->type)
+ qHashBits(&d->u, sizeof(d->u), seed);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
{
const QRhiShaderResourceBindingPrivate *d = b.d;
QDebugStateSaver saver(dbg);
const QRhiShaderResourceBinding::Data *d = b.data();
dbg.nospace() << "QRhiShaderResourceBinding("
<< "binding=" << d->binding
<< " stage=" << d->stage
@ -3090,6 +3056,11 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QVarLengthArray<QRhiShaderResourceBinding, 8> &bindings)
{
return QtPrivate::printSequentialContainer(dbg, "Bindings", bindings);
}
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
{
QDebugStateSaver saver(dbg);
@ -3341,7 +3312,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
{
sc = rhi->newSwapChain();
ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // no need to set the size yet
QSize(), // no need to set the size here due to UsedWithSwapChainOnly
1,
QRhiRenderBuffer::UsedWithSwapChainOnly);
sc->setWindow(window);
@ -3353,9 +3324,6 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
void resizeSwapChain()
{
const QSize outputSize = sc->surfacePixelSize();
ds->setPixelSize(outputSize);
ds->build();
hasSwapChain = sc->buildOrResize();
}
@ -3549,10 +3517,24 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
\return The size of the window's associated surface or layer. Do not assume
this is the same as QWindow::size() * QWindow::devicePixelRatio().
Can be called before buildOrResize() (but with window() already set), which
allows setting the correct size for the depth-stencil buffer that is then
used together with the swapchain's color buffers. Also used in combination
with currentPixelSize() to detect size changes.
\note Can also be called before buildOrResize(), if at least window() is
already set) This in combination with currentPixelSize() allows to detect
when a swapchain needs to be resized. However, watch out for the fact that
the size of the underlying native object (surface, layer, or similar) is
"live", so whenever this function is called, it returns the latest value
reported by the underlying implementation, without any atomicity guarantee.
Therefore, using this function to determine pixel sizes for graphics
resources that are used in a frame is strongly discouraged. Rely on
currentPixelSize() instead which returns a size that is atomic and will not
change between buildOrResize() invocations.
\note For depth-stencil buffers used in combination with the swapchain's
color buffers, it is strongly recommended to rely on the automatic sizing
and rebuilding behavior provided by the
QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface
size via this function just to get a size that can be passed to
QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of
atomicity as described above.
\sa currentPixelSize()
*/
@ -5531,7 +5513,7 @@ static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResource
void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
const UsageState &state)
{
auto it = std::find_if(m_buffers.begin(), m_buffers.end(), [buf](const Buffer &b) { return b.buf == buf; });
auto it = m_buffers.find(buf);
if (it != m_buffers.end()) {
if (it->access != *access) {
const QByteArray name = buf->name();
@ -5547,12 +5529,11 @@ void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAc
}
Buffer b;
b.buf = buf;
b.slot = slot;
b.access = *access;
b.stage = *stage;
b.stateAtPassBegin = state; // first use -> initial state
m_buffers.append(b);
m_buffers.insert(buf, b);
}
static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a,
@ -5571,7 +5552,7 @@ static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess acces
void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
const UsageState &state)
{
auto it = std::find_if(m_textures.begin(), m_textures.end(), [tex](const Texture &t) { return t.tex == tex; });
auto it = m_textures.find(tex);
if (it != m_textures.end()) {
if (it->access != *access) {
// Different subresources of a texture may be used for both load
@ -5595,11 +5576,10 @@ void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *a
}
Texture t;
t.tex = tex;
t.access = *access;
t.stage = *stage;
t.stateAtPassBegin = state; // first use -> initial state
m_textures.append(t);
m_textures.insert(tex, t);
}
QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)

View File

@ -52,6 +52,7 @@
#include <QSize>
#include <QMatrix4x4>
#include <QVector>
#include <QVarLengthArray>
#include <QThread>
#include <QColor>
#include <QImage>
@ -320,10 +321,6 @@ public:
Q_DECLARE_FLAGS(StageFlags, StageFlag)
QRhiShaderResourceBinding();
QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other);
QRhiShaderResourceBinding &operator=(const QRhiShaderResourceBinding &other);
~QRhiShaderResourceBinding();
void detach();
bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const;
@ -344,19 +341,49 @@ public:
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf);
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
struct Data
{
int binding;
QRhiShaderResourceBinding::StageFlags stage;
QRhiShaderResourceBinding::Type type;
struct UniformBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
bool hasDynamicOffset;
};
struct SampledTextureData {
QRhiTexture *tex;
QRhiSampler *sampler;
};
struct StorageImageData {
QRhiTexture *tex;
int level;
};
struct StorageBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
};
union {
UniformBufferData ubuf;
SampledTextureData stex;
StorageImageData simage;
StorageBufferData sbuf;
} u;
};
Data *data() { return &d; }
const Data *data() const { return &d; }
private:
QRhiShaderResourceBindingPrivate *d;
friend class QRhiShaderResourceBindingPrivate;
friend Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
friend Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
friend Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &, uint) Q_DECL_NOTHROW;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
#endif
Data d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_MOVABLE_TYPE);
Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &b, uint seed = 0) Q_DECL_NOTHROW;
@ -900,8 +927,22 @@ class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource
public:
QRhiResource::Type resourceType() const override;
QVector<QRhiShaderResourceBinding> bindings() const { return m_bindings; }
void setBindings(const QVector<QRhiShaderResourceBinding> &b) { m_bindings = b; }
void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
template<typename InputIterator>
void setBindings(InputIterator first, InputIterator last)
{
m_bindings.clear();
std::copy(first, last, std::back_inserter(m_bindings));
}
void setBindings(const QVector<QRhiShaderResourceBinding> &bindings) // compat., to be removed
{
setBindings(bindings.cbegin(), bindings.cend());
}
const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); }
const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); }
bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
@ -909,7 +950,7 @@ public:
protected:
QRhiShaderResourceBindings(QRhiImplementation *rhi);
QVector<QRhiShaderResourceBinding> m_bindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> m_bindings;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
#endif
@ -1040,8 +1081,15 @@ public:
FrontFace frontFace() const { return m_frontFace; }
void setFrontFace(FrontFace f) { m_frontFace = f; }
QVector<TargetBlend> targetBlends() const { return m_targetBlends; }
void setTargetBlends(const QVector<TargetBlend> &blends) { m_targetBlends = blends; }
void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
template<typename InputIterator>
void setTargetBlends(InputIterator first, InputIterator last)
{
m_targetBlends.clear();
std::copy(first, last, std::back_inserter(m_targetBlends));
}
const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); }
const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); }
bool hasDepthTest() const { return m_depthTest; }
void setDepthTest(bool enable) { m_depthTest = enable; }
@ -1073,8 +1121,19 @@ public:
float lineWidth() const { return m_lineWidth; }
void setLineWidth(float width) { m_lineWidth = width; }
QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
template<typename InputIterator>
void setShaderStages(InputIterator first, InputIterator last)
{
m_shaderStages.clear();
std::copy(first, last, std::back_inserter(m_shaderStages));
}
void setShaderStages(const QVector<QRhiShaderStage> &stages) // compat., to be removed
{
setShaderStages(stages.cbegin(), stages.cend());
}
const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); }
const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); }
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
@ -1093,7 +1152,7 @@ protected:
Topology m_topology = Triangles;
CullMode m_cullMode = None;
FrontFace m_frontFace = CCW;
QVector<TargetBlend> m_targetBlends;
QVarLengthArray<TargetBlend, 8> m_targetBlends;
bool m_depthTest = false;
bool m_depthWrite = false;
CompareOp m_depthOp = Less;
@ -1104,7 +1163,7 @@ protected:
quint32 m_stencilWriteMask = 0xFF;
int m_sampleCount = 1;
float m_lineWidth = 1.0f;
QVector<QRhiShaderStage> m_shaderStages;
QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
QRhiVertexInputLayout m_vertexInputLayout;
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;

View File

@ -233,27 +233,37 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T,
T *x, T *y, T *w, T *h)
{
// x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in
// Vulkan/Metal/D3D. We also need proper clamping since some
// validation/debug layers are allergic to out of bounds scissor or
// viewport rects.
// Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both
// negative x or y, and partly or completely out of bounds rects are
// allowed. The only thing the input here cannot have is a negative width
// or height. We must handle all other input gracefully, clamping to a zero
// width or height rect in the worst case, and ensuring the resulting rect
// is inside the rendertarget's bounds because some APIs' validation/debug
// layers are allergic to out of bounds scissor or viewport rects.
const T outputWidth = outputSize.width();
const T outputHeight = outputSize.height();
const T inputWidth = r[2];
const T inputHeight = r[3];
*x = qMax<T>(0, r[0]);
*y = qMax<T>(0, outputHeight - (r[1] + inputHeight));
*w = inputWidth;
*h = inputHeight;
if (*x >= outputWidth || *y >= outputHeight)
if (inputWidth < 0 || inputHeight < 0)
return false;
*x = r[0];
*y = outputHeight - (r[1] + inputHeight);
const T widthOffset = *x < 0 ? -*x : 0;
const T heightOffset = *y < 0 ? -*y : 0;
*x = qBound<T>(0, *x, outputWidth - 1);
*y = qBound<T>(0, *y, outputHeight - 1);
*w = qMax<T>(0, inputWidth - widthOffset);
*h = qMax<T>(0, inputHeight - heightOffset);
if (*x + *w > outputWidth)
*w = outputWidth - *x;
*w = qMax<T>(0, outputWidth - *x - 1);
if (*y + *h > outputHeight)
*h = outputHeight - *y;
*h = qMax<T>(0, outputHeight - *y - 1);
return true;
}
@ -371,57 +381,6 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABL
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE);
class Q_GUI_EXPORT QRhiShaderResourceBindingPrivate
{
public:
QRhiShaderResourceBindingPrivate()
: ref(1)
{
}
QRhiShaderResourceBindingPrivate(const QRhiShaderResourceBindingPrivate *other)
: ref(1),
binding(other->binding),
stage(other->stage),
type(other->type),
u(other->u)
{
}
static QRhiShaderResourceBindingPrivate *get(QRhiShaderResourceBinding *s) { return s->d; }
static const QRhiShaderResourceBindingPrivate *get(const QRhiShaderResourceBinding *s) { return s->d; }
QAtomicInt ref;
int binding;
QRhiShaderResourceBinding::StageFlags stage;
QRhiShaderResourceBinding::Type type;
struct UniformBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
bool hasDynamicOffset;
};
struct SampledTextureData {
QRhiTexture *tex;
QRhiSampler *sampler;
};
struct StorageImageData {
QRhiTexture *tex;
int level;
};
struct StorageBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
};
union {
UniformBufferData ubuf;
SampledTextureData stex;
StorageImageData simage;
StorageBufferData sbuf;
} u;
};
template<typename T>
struct QRhiBatchedBindings
{
@ -544,28 +503,32 @@ public:
const UsageState &state);
struct Buffer {
QRhiBuffer *buf;
int slot;
BufferAccess access;
BufferStage stage;
UsageState stateAtPassBegin;
};
const QVector<Buffer> *buffers() const { return &m_buffers; }
using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator;
BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); }
BufferIterator cendBuffers() const { return m_buffers.cend(); }
struct Texture {
QRhiTexture *tex;
TextureAccess access;
TextureStage stage;
UsageState stateAtPassBegin;
};
const QVector<Texture> *textures() const { return &m_textures; }
using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator;
TextureIterator cbeginTextures() const { return m_textures.cbegin(); }
TextureIterator cendTextures() const { return m_textures.cend(); }
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
private:
QVector<Buffer> m_buffers;
QVector<Texture> m_textures;
QHash<QRhiBuffer *, Buffer> m_buffers;
QHash<QRhiTexture *, Texture> m_textures;
};
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE);

View File

@ -36,7 +36,7 @@
#include "qrhid3d11_p_p.h"
#include "qshader_p.h"
#include "cs_tdr.h"
#include "cs_tdr_p.h"
#include <QWindow>
#include <QOperatingSystemVersion>
#include <qmath.h>
@ -598,7 +598,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
bool hasDynamicOffsetInSrb = false;
bool srbUpdate = false;
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -1746,7 +1746,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
srbD->csUAVs.clear();
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -3082,11 +3082,11 @@ bool QD3D11ShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
sortedBindings = m_bindings;
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
return a.data()->binding < b.data()->binding;
});
boundResourceData.resize(sortedBindings.count());
@ -3939,10 +3939,17 @@ bool QD3D11SwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
m_depthStencil->setPixelSize(pixelSize);
if (!m_depthStencil->build())
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
pixelSize.width(), pixelSize.height());
} else {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
}
}
currentFrameSlot = 0;
frameCount = 0;

View File

@ -199,7 +199,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
uint generation = 0;
// Keep track of the generation number of each referenced QRhi* to be able
@ -230,7 +230,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData;
QVarLengthArray<BoundResourceData, 8> boundResourceData;
QRhiBatchedBindings<ID3D11Buffer *> vsubufs;
QRhiBatchedBindings<UINT> vsubufoffsets;

View File

@ -39,6 +39,7 @@
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QtGui/private/qopenglextensions_p.h>
#include <QtGui/private/qopenglprogrambinarycache_p.h>
#include <qmath.h>
QT_BEGIN_NAMESPACE
@ -275,6 +276,8 @@ QT_BEGIN_NAMESPACE
#define GL_POINT_SPRITE 0x8861
#endif
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
/*!
Constructs a new QRhiGles2InitParams.
@ -583,7 +586,9 @@ QRhiBuffer *QRhiGles2::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlag
int QRhiGles2::ubufAlignment() const
{
return 256;
// No real uniform buffers are used so no need to pretend there is any
// alignment requirement.
return 1;
}
bool QRhiGles2::isYUpInFramebuffer() const
@ -863,7 +868,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
bool hasDynamicOffsetInSrb = false;
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
// no BufUniformRead / AccessUniform because no real uniform buffers are used
@ -1004,8 +1009,12 @@ void QRhiGles2::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::Viewport;
const std::array<float, 4> r = viewport.viewport();
cmd.args.viewport.x = qMax(0.0f, r[0]);
cmd.args.viewport.y = qMax(0.0f, r[1]);
// A negative width or height is an error. A negative x or y is not.
if (r[2] < 0.0f || r[3] < 0.0f)
return;
cmd.args.viewport.x = r[0];
cmd.args.viewport.y = r[1];
cmd.args.viewport.w = r[2];
cmd.args.viewport.h = r[3];
cmd.args.viewport.d0 = viewport.minDepth();
@ -1021,8 +1030,12 @@ void QRhiGles2::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::Scissor;
const std::array<int, 4> r = scissor.scissor();
cmd.args.scissor.x = qMax(0, r[0]);
cmd.args.scissor.y = qMax(0, r[1]);
// A negative width or height is an error. A negative x or y is not.
if (r[2] < 0 || r[3] < 0)
return;
cmd.args.scissor.x = r[0];
cmd.args.scissor.y = r[1];
cmd.args.scissor.w = r[2];
cmd.args.scissor.h = r[3];
cbD->commands.append(cmd);
@ -2173,7 +2186,6 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
{
GLbitfield barriers = 0;
QRhiPassResourceTracker &tracker(cbD->passResTrackers[cmd.args.barriersForPass.trackerIndex]);
const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
// we only care about after-write, not any other accesses, and
// cannot tell if something was written in a shader several passes
// ago: now the previously written resource may be used with an
@ -2181,17 +2193,16 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
// barrier in theory. Hence setting all barrier bits whenever
// something previously written is used for the first time in a
// subsequent pass.
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(b.stateAtPassBegin.access);
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
if (accessBeforePass == QGles2Buffer::AccessStorageWrite
|| accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
{
barriers |= GL_ALL_BARRIER_BITS;
}
}
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
for (const QRhiPassResourceTracker::Texture &t : *textures) {
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(t.stateAtPassBegin.access);
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
if (accessBeforePass == QGles2Texture::AccessStorageWrite
|| accessBeforePass == QGles2Texture::AccessStorageReadWrite)
{
@ -2250,6 +2261,7 @@ void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps)
}
} else {
f->glDisable(GL_BLEND);
f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
if (psD->m_depthTest)
f->glEnable(GL_DEPTH_TEST);
@ -2292,7 +2304,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
int texUnit = 0;
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -2698,8 +2710,7 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
}
}
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage,
QShaderDescription *desc, int *glslVersionUsed)
QByteArray QRhiGles2::shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion)
{
const QShader bakedShader = shaderStage.shader();
QVector<int> versionsToTry;
@ -2718,8 +2729,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
QShaderVersion ver(v, QShaderVersion::GlslEs);
source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
if (glslVersionUsed)
*glslVersionUsed = v;
if (glslVersion)
*glslVersion = v;
break;
}
}
@ -2748,8 +2759,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
for (int v : versionsToTry) {
source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
if (glslVersionUsed)
*glslVersionUsed = v;
if (glslVersion)
*glslVersion = v;
break;
}
}
@ -2757,8 +2768,15 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
if (source.isEmpty()) {
qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
<< ") in baked shader" << bakedShader;
return false;
}
return source;
}
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion)
{
const QByteArray source = shaderSource(shaderStage, glslVersion);
if (source.isEmpty())
return false;
GLuint shader;
auto cacheIt = m_shaderCache.constFind(shaderStage);
@ -2795,7 +2813,6 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
f->glAttachShader(program, shader);
*desc = bakedShader.description();
return true;
}
@ -2850,6 +2867,68 @@ void QRhiGles2::gatherSamplers(GLuint program, const QShaderDescription::InOutVa
}
}
bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const
{
static QOpenGLProgramBinarySupportCheckWrapper checker;
return checker.get(ctx)->isSupported();
}
static QOpenGLProgramBinaryCache qrhi_programBinaryCache;
static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
{
switch (type) {
case QRhiShaderStage::Vertex:
return QShader::VertexStage;
case QRhiShaderStage::Fragment:
return QShader::FragmentStage;
case QRhiShaderStage::Compute:
return QShader::ComputeStage;
default:
Q_UNREACHABLE();
return QShader::VertexStage;
}
}
QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
GLuint program, QByteArray *cacheKey)
{
QRhiGles2::DiskCacheResult result = QRhiGles2::DiskCacheMiss;
QByteArray diskCacheKey;
if (isProgramBinaryDiskCacheEnabled()) {
QOpenGLProgramBinaryCache::ProgramDesc binaryProgram;
for (int i = 0; i < stageCount; ++i) {
const QRhiShaderStage &stage(stages[i]);
const QByteArray source = shaderSource(stage, nullptr);
if (source.isEmpty())
return QRhiGles2::DiskCacheError;
binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(toShaderStage(stage.type()), source));
}
diskCacheKey = binaryProgram.cacheKey();
if (qrhi_programBinaryCache.load(diskCacheKey, program)) {
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
program, diskCacheKey.constData());
result = QRhiGles2::DiskCacheHit;
}
}
if (cacheKey)
*cacheKey = diskCacheKey;
return result;
}
void QRhiGles2::trySaveToDiskCache(GLuint program, const QByteArray &cacheKey)
{
if (isProgramBinaryDiskCacheEnabled()) {
qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
program, cacheKey.constData());
qrhi_programBinaryCache.save(cacheKey, program);
}
}
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
: QRhiBuffer(rhi, type, usage, size)
{
@ -3536,17 +3615,29 @@ bool QGles2GraphicsPipeline::build()
program = rhiD->f->glCreateProgram();
QByteArray diskCacheKey;
QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(m_shaderStages.constData(),
m_shaderStages.count(),
program,
&diskCacheKey);
if (diskCacheResult == QRhiGles2::DiskCacheError)
return false;
const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
QShaderDescription vsDesc;
QShaderDescription fsDesc;
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
if (isVertex) {
if (!rhiD->compileShader(program, shaderStage, &vsDesc, nullptr))
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
vsDesc = shaderStage.shader().description();
} else if (isFragment) {
if (!rhiD->compileShader(program, shaderStage, &fsDesc, nullptr))
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
fsDesc = shaderStage.shader().description();
}
}
@ -3555,9 +3646,12 @@ bool QGles2GraphicsPipeline::build()
rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), name.constData());
}
if (!rhiD->linkProgram(program))
if (needsCompile && !rhiD->linkProgram(program))
return false;
if (needsCompile)
rhiD->trySaveToDiskCache(program, diskCacheKey);
for (const QShaderDescription::UniformBlock &ub : vsDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
@ -3618,11 +3712,24 @@ bool QGles2ComputePipeline::build()
program = rhiD->f->glCreateProgram();
QShaderDescription csDesc;
if (!rhiD->compileShader(program, m_shaderStage, &csDesc, nullptr))
QByteArray diskCacheKey;
QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(&m_shaderStage, 1, program, &diskCacheKey);
if (diskCacheResult == QRhiGles2::DiskCacheError)
return false;
if (!rhiD->linkProgram(program))
const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
if (needsCompile && !rhiD->compileShader(program, m_shaderStage, nullptr))
return false;
csDesc = m_shaderStage.shader().description();
if (needsCompile && !rhiD->linkProgram(program))
return false;
if (needsCompile)
rhiD->trySaveToDiskCache(program, diskCacheKey);
for (const QShaderDescription::UniformBlock &ub : csDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
for (const QShaderDescription::InOutVariable &v : csDesc.combinedImageSamplers())
@ -3696,6 +3803,13 @@ bool QGles2SwapChain::buildOrResize()
m_currentPixelSize = surfacePixelSize();
pixelSize = m_currentPixelSize;
if (m_depthStencil && m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)
&& m_depthStencil->pixelSize() != pixelSize)
{
m_depthStencil->setPixelSize(pixelSize);
m_depthStencil->build();
}
rt.d.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc);
rt.d.pixelSize = pixelSize;
rt.d.dpr = float(m_window->devicePixelRatio());

View File

@ -692,13 +692,23 @@ public:
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
int effectiveSampleCount(int sampleCount) const;
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage,
QShaderDescription *desc, int *glslVersionUsed);
QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
bool linkProgram(GLuint program);
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst);
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
QVector<QGles2SamplerDescription> *dst);
bool isProgramBinaryDiskCacheEnabled() const;
enum DiskCacheResult {
DiskCacheHit,
DiskCacheMiss,
DiskCacheError
};
DiskCacheResult tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
GLuint program, QByteArray *cacheKey);
void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey);
QOpenGLContext *ctx = nullptr;
bool importedContext = false;

View File

@ -656,7 +656,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
} res[KNOWN_STAGES];
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
@ -838,8 +838,15 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
[cbD->d->currentRenderPassEncoder setRenderPipelineState: psD->d->ps];
[cbD->d->currentRenderPassEncoder setDepthStencilState: psD->d->ds];
if (cbD->currentCullMode == -1 || psD->d->cullMode != uint(cbD->currentCullMode)) {
[cbD->d->currentRenderPassEncoder setCullMode: psD->d->cullMode];
cbD->currentCullMode = int(psD->d->cullMode);
}
if (cbD->currentFrontFaceWinding == -1 || psD->d->winding != uint(cbD->currentFrontFaceWinding)) {
[cbD->d->currentRenderPassEncoder setFrontFacingWinding: psD->d->winding];
cbD->currentFrontFaceWinding = int(psD->d->winding);
}
}
psD->lastActiveFrameSlot = currentFrameSlot;
@ -868,7 +875,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
// do buffer writes, figure out if we need to rebind, and mark as in-use
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QMetalShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -1029,44 +1036,11 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
}
}
QSize safeOutputSize(QRhiMetal *rhiD, QMetalCommandBuffer *cbD)
{
QSize size = cbD->currentTarget->pixelSize();
// So now we have the issue that the texture (drawable) size may have
// changed again since swapchain buildOrResize() was called. This can
// happen for example when interactively resizing the window a lot in one
// go, and command buffer building happens on a dedicated thread (f.ex.
// using the threaded render loop of Qt Quick).
//
// This is only an issue when running in debug mode with XCode because Metal
// validation will fail when setting viewport or scissor with the real size
// being smaller than what we think it is. So query the drawable size right
// here, in debug mode at least.
//
// In addition, we have to take the smaller of the two widths and heights
// to be safe, apparently. In some cases validation seems to think that the
// "render pass width" (or height) is the old(?) value.
#ifdef QT_DEBUG
if (cbD->currentTarget->resourceType() == QRhiResource::RenderTarget) {
Q_ASSERT(rhiD->currentSwapChain);
const QSize otherSize = rhiD->currentSwapChain->surfacePixelSize();
size.setWidth(qMin(size.width(), otherSize.width()));
size.setHeight(qMin(size.height(), otherSize.height()));
}
#else
Q_UNUSED(rhiD);
#endif
return size;
}
void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
{
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
const QSize outputSize = safeOutputSize(this, cbD);
const QSize outputSize = cbD->currentTarget->pixelSize();
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
float x, y, w, h;
@ -1098,7 +1072,7 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
const QSize outputSize = safeOutputSize(this, cbD);
const QSize outputSize = cbD->currentTarget->pixelSize();
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
int x, y, w, h;
@ -2794,21 +2768,21 @@ bool QMetalShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
sortedBindings = m_bindings;
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
return a.data()->binding < b.data()->binding;
});
if (!sortedBindings.isEmpty())
maxBinding = QRhiShaderResourceBindingPrivate::get(&sortedBindings.last())->binding;
maxBinding = sortedBindings.last().data()->binding;
else
maxBinding = -1;
boundResourceData.resize(sortedBindings.count());
for (int i = 0, ie = sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = sortedBindings.at(i).data();
QMetalShaderResourceBindings::BoundResourceData &bd(boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -3450,6 +3424,10 @@ void QMetalCommandBuffer::resetPerPassCachedState()
currentSrbGeneration = 0;
currentResSlot = -1;
currentIndexBuffer = nullptr;
currentIndexOffset = 0;
currentIndexFormat = QRhiCommandBuffer::IndexUInt16;
currentCullMode = -1;
currentFrontFaceWinding = -1;
d->currentFirstVertexBinding = -1;
d->currentVertexInputsBuffers.clear();
@ -3518,20 +3496,8 @@ QRhiRenderTarget *QMetalSwapChain::currentFrameRenderTarget()
QSize QMetalSwapChain::surfacePixelSize()
{
// may be called before build, must not access other than m_*
NSView *v = (NSView *) m_window->winId();
if (v) {
CAMetalLayer *layer = (CAMetalLayer *) [v layer];
if (layer) {
CGSize size = layer.bounds.size;
size.width *= layer.contentsScale;
size.height *= layer.contentsScale;
layer.drawableSize = size;
return QSize(int(size.width), int(size.height));
}
}
return QSize();
Q_ASSERT(m_window);
return m_window->size() * m_window->devicePixelRatio();
}
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
@ -3582,8 +3548,9 @@ bool QMetalSwapChain::buildOrResize()
return false;
}
NSView *v = (NSView *) window->winId();
d->layer = (CAMetalLayer *) [v layer];
NSView *view = reinterpret_cast<NSView *>(window->winId());
Q_ASSERT(view);
d->layer = static_cast<CAMetalLayer *>(view.layer);
Q_ASSERT(d->layer);
chooseFormats();
@ -3612,7 +3579,15 @@ bool QMetalSwapChain::buildOrResize()
d->layer.opaque = YES;
}
m_currentPixelSize = surfacePixelSize();
// Now set the layer's drawableSize which will stay set to the same value
// until the next buildOrResize(), thus ensuring atomicity with regards to
// the drawable size in frames.
CGSize layerSize = d->layer.bounds.size;
layerSize.width *= d->layer.contentsScale;
layerSize.height *= d->layer.contentsScale;
d->layer.drawableSize = layerSize;
m_currentPixelSize = QSizeF::fromCGSize(layerSize).toSize();
pixelSize = m_currentPixelSize;
[d->layer setDevice: rhiD->d->dev];
@ -3633,10 +3608,17 @@ bool QMetalSwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
m_depthStencil->setPixelSize(pixelSize);
if (!m_depthStencil->build())
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
pixelSize.width(), pixelSize.height());
} else {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
}
}
rtWrapper.d->pixelSize = pixelSize;
rtWrapper.d->dpr = float(window->devicePixelRatio());

View File

@ -188,7 +188,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int maxBinding = -1;
struct BoundUniformBufferData {
@ -217,7 +217,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData;
QVarLengthArray<BoundResourceData, 8> boundResourceData;
uint generation = 0;
friend class QRhiMetal;
@ -271,8 +271,11 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer
ComputePass
};
// per-pass (render or compute command encoder) persistent state
PassType recordingPass;
QRhiRenderTarget *currentTarget;
// per-pass (render or compute command encoder) volatile (cached) state
QRhiGraphicsPipeline *currentGraphicsPipeline;
QRhiComputePipeline *currentComputePipeline;
uint currentPipelineGeneration;
@ -283,6 +286,8 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer
QRhiBuffer *currentIndexBuffer;
quint32 currentIndexOffset;
QRhiCommandBuffer::IndexFormat currentIndexFormat;
int currentCullMode;
int currentFrontFaceWinding;
const QRhiNativeHandles *nativeHandles();
void resetState();

View File

@ -2313,7 +2313,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) {
srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count());
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]);
VkWriteDescriptorSet writeInfo;
@ -3556,12 +3556,11 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
if (tracker.isEmpty())
return;
const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b.buf);
VkAccessFlags access = toVkAccess(b.access);
VkPipelineStageFlags stage = toVkPipelineStage(b.stage);
QVkBuffer::UsageState s = toVkBufferUsageState(b.stateAtPassBegin);
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key());
VkAccessFlags access = toVkAccess(it->access);
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
QVkBuffer::UsageState s = toVkBufferUsageState(it->stateAtPassBegin);
if (!s.stage)
continue;
if (s.access == access && s.stage == stage) {
@ -3575,7 +3574,7 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufMemBarrier.srcAccessMask = s.access;
bufMemBarrier.dstAccessMask = access;
bufMemBarrier.buffer = bufD->buffers[b.slot];
bufMemBarrier.buffer = bufD->buffers[it->slot];
bufMemBarrier.size = VK_WHOLE_SIZE;
df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
0, nullptr,
@ -3583,13 +3582,12 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
0, nullptr);
}
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
for (const QRhiPassResourceTracker::Texture &t : *textures) {
QVkTexture *texD = QRHI_RES(QVkTexture, t.tex);
VkImageLayout layout = toVkLayout(t.access);
VkAccessFlags access = toVkAccess(t.access);
VkPipelineStageFlags stage = toVkPipelineStage(t.stage);
QVkTexture::UsageState s = toVkTextureUsageState(t.stateAtPassBegin);
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
QVkTexture *texD = QRHI_RES(QVkTexture, it.key());
VkImageLayout layout = toVkLayout(it->access);
VkAccessFlags access = toVkAccess(it->access);
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
QVkTexture::UsageState s = toVkTextureUsageState(it->stateAtPassBegin);
if (s.access == access && s.stage == stage && s.layout == layout) {
if (!accessIsWrite(access))
continue;
@ -3870,7 +3868,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
bool hasDynamicOffsetInSrb = false;
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
if (QRHI_RES(QVkBuffer, b->u.ubuf.buf)->m_type == QRhiBuffer::Dynamic)
@ -3889,7 +3887,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
// Do host writes and mark referenced shader resources as in-use.
// Also prepare to ensure the descriptor set we are going to bind refers to up-to-date Vk objects.
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[descSetIdx][i]);
QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]);
switch (b->type) {
@ -4022,7 +4020,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
// and neither srb nor dynamicOffsets has any such ordering
// requirement.
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
uint32_t offset = 0;
for (int i = 0; i < dynamicOffsetCount; ++i) {
@ -4750,7 +4748,7 @@ static inline void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphic
dst->compareOp = toVkCompareOp(src.compareOp);
}
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBindingPrivate *b)
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
{
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -5697,16 +5695,17 @@ bool QVkShaderResourceBindings::build()
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
descSets[i] = VK_NULL_HANDLE;
sortedBindings = m_bindings;
sortedBindings.clear();
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
return a.data()->binding < b.data()->binding;
});
QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
for (const QRhiShaderResourceBinding &binding : qAsConst(sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
VkDescriptorSetLayoutBinding vkbinding;
memset(&vkbinding, 0, sizeof(vkbinding));
vkbinding.binding = uint32_t(b->binding);
@ -6315,10 +6314,17 @@ bool QVkSwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
m_depthStencil->setPixelSize(pixelSize);
if (!m_depthStencil->build())
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
pixelSize.width(), pixelSize.height());
} else {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
}
}
if (!m_renderPassDesc)
qWarning("QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");

View File

@ -232,7 +232,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int poolIndex = -1;
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
@ -268,7 +268,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
friend class QRhiVulkan;
};

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@ -2096,10 +2096,11 @@ uint qHash(const QFont &font, uint seed) noexcept
*/
bool QFont::fromString(const QString &descrip)
{
const auto l = descrip.splitRef(QLatin1Char(','));
int count = l.count();
if (!count || (count > 2 && count < 9) || count > 11) {
const QStringRef sr = QStringRef(&descrip).trimmed();
const auto l = sr.split(QLatin1Char(','));
const int count = l.count();
if (!count || (count > 2 && count < 9) || count > 11 ||
l.first().isEmpty()) {
qWarning("QFont::fromString: Invalid description '%s'",
descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
return false;

View File

@ -647,18 +647,40 @@ void QVulkanWindowPrivate::init()
#endif
qCDebug(lcGuiVk, "Using queue families: graphics = %u present = %u", gfxQueueFamilyIdx, presQueueFamilyIdx);
VkDeviceQueueCreateInfo queueInfo[2];
QVector<VkDeviceQueueCreateInfo> queueInfo;
queueInfo.reserve(2);
const float prio[] = { 0 };
memset(queueInfo, 0, sizeof(queueInfo));
queueInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo[0].queueFamilyIndex = gfxQueueFamilyIdx;
queueInfo[0].queueCount = 1;
queueInfo[0].pQueuePriorities = prio;
VkDeviceQueueCreateInfo addQueueInfo;
memset(&addQueueInfo, 0, sizeof(addQueueInfo));
addQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
addQueueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
addQueueInfo.queueCount = 1;
addQueueInfo.pQueuePriorities = prio;
queueInfo.append(addQueueInfo);
if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
queueInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo[1].queueFamilyIndex = presQueueFamilyIdx;
queueInfo[1].queueCount = 1;
queueInfo[1].pQueuePriorities = prio;
addQueueInfo.queueFamilyIndex = presQueueFamilyIdx;
addQueueInfo.queueCount = 1;
addQueueInfo.pQueuePriorities = prio;
queueInfo.append(addQueueInfo);
}
if (queueCreateInfoModifier) {
queueCreateInfoModifier(queueFamilyProps.constData(), queueCount, queueInfo);
bool foundGfxQueue = false;
bool foundPresQueue = false;
for (const VkDeviceQueueCreateInfo& createInfo : qAsConst(queueInfo)) {
foundGfxQueue |= createInfo.queueFamilyIndex == gfxQueueFamilyIdx;
foundPresQueue |= createInfo.queueFamilyIndex == presQueueFamilyIdx;
}
if (!foundGfxQueue) {
qWarning("QVulkanWindow: Graphics queue missing after call to queueCreateInfoModifier");
status = StatusFail;
return;
}
if (!foundPresQueue) {
qWarning("QVulkanWindow: Present queue missing after call to queueCreateInfoModifier");
status = StatusFail;
return;
}
}
// Filter out unsupported extensions in order to keep symmetry
@ -676,8 +698,8 @@ void QVulkanWindowPrivate::init()
VkDeviceCreateInfo devInfo;
memset(&devInfo, 0, sizeof(devInfo));
devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
devInfo.queueCreateInfoCount = gfxQueueFamilyIdx == presQueueFamilyIdx ? 1 : 2;
devInfo.pQueueCreateInfos = queueInfo;
devInfo.queueCreateInfoCount = queueInfo.size();
devInfo.pQueueCreateInfos = queueInfo.constData();
devInfo.enabledExtensionCount = devExts.count();
devInfo.ppEnabledExtensionNames = devExts.constData();
@ -1545,6 +1567,52 @@ bool QVulkanWindow::event(QEvent *e)
return QWindow::event(e);
}
/*!
\typedef QVulkanWindow::QueueCreateInfoModifier
A function function that is called during graphics initialization to add
additAional queues that should be created.
Set if the renderer needs additional queues besides the default graphics
queue (e.g. a transfer queue).
The provided queue family properties can be used to select the indices for
the additional queues.
The renderer can subsequently request the actual queue in initResources().
Note when requesting additional graphics queues: Qt itself always requests
a graphics queue, you'll need to search queueCreateInfo for the appropriate
entry and manipulate it to obtain the additional queue.
\sa setQueueCreateInfoModifier()
*/
/*!
Return a previously set queue create info modification function.
\sa setQueueCreateInfoModifier()
\since 5.15
*/
QVulkanWindow::QueueCreateInfoModifier QVulkanWindow::queueCreateInfoModifier() const
{
Q_D(const QVulkanWindow);
return d->queueCreateInfoModifier;
}
/*!
Set a queue create info modification function.
\sa queueCreateInfoModifier()
\since 5.15
*/
void QVulkanWindow::setQueueCreateInfoModifier(QueueCreateInfoModifier modifier)
{
Q_D(QVulkanWindow);
d->queueCreateInfoModifier = modifier;
}
/*!
Returns true if this window has successfully initialized all Vulkan
resources, including the swapchain.

View File

@ -103,6 +103,12 @@ public:
QVector<int> supportedSampleCounts();
void setSampleCount(int sampleCount);
typedef std::function<void(const VkQueueFamilyProperties *,
uint32_t,
QVector<VkDeviceQueueCreateInfo> &)> QueueCreateInfoModifier;
QueueCreateInfoModifier queueCreateInfoModifier() const;
void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier);
bool isValid() const;
virtual QVulkanWindowRenderer *createRenderer();

View File

@ -102,6 +102,7 @@ public:
QHash<VkPhysicalDevice, QVulkanInfoVector<QVulkanExtension> > supportedDevExtensions;
QVector<VkFormat> requestedColorFormats;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
QVulkanWindow::QueueCreateInfoModifier queueCreateInfoModifier;
VkDevice dev = VK_NULL_HANDLE;
QVulkanDeviceFunctions *devFuncs;

View File

@ -624,11 +624,10 @@ QList<QSslCipher> QSslConfiguration::supportedCiphers()
Returns this connection's CA certificate database. The CA certificate
database is used by the socket during the handshake phase to
validate the peer's certificate. It can be modified prior to the
handshake with setCaCertificates(), or with \l{QSslSocket}'s
\l{QSslSocket::}{addCaCertificate()} and
\l{QSslSocket::}{addCaCertificates()}.
handshake with setCaCertificates(), or with addCaCertificate() and
addCaCertificates().
\sa setCaCertificates()
\sa setCaCertificates(), addCaCertificate(), addCaCertificates()
*/
QList<QSslCertificate> QSslConfiguration::caCertificates() const
{
@ -645,7 +644,7 @@ QList<QSslCertificate> QSslConfiguration::caCertificates() const
that is not available (as is commonly the case on iOS), the default database
is empty.
\sa caCertificates()
\sa caCertificates(), addCaCertificates(), addCaCertificate()
*/
void QSslConfiguration::setCaCertificates(const QList<QSslCertificate> &certificates)
{
@ -653,6 +652,72 @@ void QSslConfiguration::setCaCertificates(const QList<QSslCertificate> &certific
d->allowRootCertOnDemandLoading = false;
}
/*!
Searches all files in the \a path for certificates encoded in the
specified \a format and adds them to this socket's CA certificate
database. \a path must be a file or a pattern matching one or more
files, as specified by \a syntax. Returns \c true if one or more
certificates are added to the socket's CA certificate database;
otherwise returns \c false.
The CA certificate database is used by the socket during the
handshake phase to validate the peer's certificate.
For more precise control, use addCaCertificate().
\sa addCaCertificate(), QSslCertificate::fromPath()
*/
bool QSslConfiguration::addCaCertificates(const QString &path, QSsl::EncodingFormat format,
QRegExp::PatternSyntax syntax)
{
QList<QSslCertificate> certs = QSslCertificate::fromPath(path, format, syntax);
if (certs.isEmpty())
return false;
d->caCertificates += certs;
return true;
}
/*!
\since 5.15
Adds \a certificate to this configuration's CA certificate database.
The certificate database must be set prior to the SSL handshake.
The CA certificate database is used by the socket during the
handshake phase to validate the peer's certificate.
\note The default configuration uses the system CA certificate database. If
that is not available (as is commonly the case on iOS), the default database
is empty.
\sa caCertificates(), setCaCertificates(), addCaCertificates()
*/
void QSslConfiguration::addCaCertificate(const QSslCertificate &certificate)
{
d->caCertificates += certificate;
d->allowRootCertOnDemandLoading = false;
}
/*!
\since 5.15
Adds \a certificates to this configuration's CA certificate database.
The certificate database must be set prior to the SSL handshake.
The CA certificate database is used by the socket during the
handshake phase to validate the peer's certificate.
\note The default configuration uses the system CA certificate database. If
that is not available (as is commonly the case on iOS), the default database
is empty.
\sa caCertificates(), setCaCertificates(), addCaCertificate()
*/
void QSslConfiguration::addCaCertificates(const QList<QSslCertificate> &certificates)
{
d->caCertificates += certificates;
d->allowRootCertOnDemandLoading = false;
}
/*!
\since 5.5
@ -661,7 +726,8 @@ void QSslConfiguration::setCaCertificates(const QList<QSslCertificate> &certific
returned by this function is used to initialize the database
returned by caCertificates() on the default QSslConfiguration.
\sa caCertificates(), setCaCertificates(), defaultConfiguration()
\sa caCertificates(), setCaCertificates(), defaultConfiguration(),
addCaCertificate(), addCaCertificates()
*/
QList<QSslCertificate> QSslConfiguration::systemCaCertificates()
{

View File

@ -131,6 +131,11 @@ public:
// Certificate Authority (CA) settings
QList<QSslCertificate> caCertificates() const;
void setCaCertificates(const QList<QSslCertificate> &certificates);
bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
QRegExp::PatternSyntax syntax = QRegExp::FixedString);
void addCaCertificate(const QSslCertificate &certificate);
void addCaCertificates(const QList<QSslCertificate> &certificates);
static QList<QSslCertificate> systemCaCertificates();
void setSslOption(QSsl::SslOption option, bool on);

View File

@ -139,10 +139,21 @@
before the handshake phase with setLocalCertificate() and
setPrivateKey().
\li The CA certificate database can be extended and customized with
addCaCertificate(), addCaCertificates(), addDefaultCaCertificate(),
addDefaultCaCertificates(), and QSslConfiguration::defaultConfiguration().setCaCertificates().
QSslConfiguration::addCaCertificate(),
QSslConfiguration::addCaCertificates().
\endlist
To extend the list of \e default CA certificates used by the SSL sockets
during the SSL handshake you must update the default configuration, as
in the snippet below:
\code
QList<QSslCertificate> certificates = getCertificates();
QSslConfiguration configuration = QSslConfiguration::defaultConfiguration();
configuration.addCaCertificates(certificates);
QSslConfiguration::setDefaultConfiguration(configuration);
\endcode
\note If available, root certificates on Unix (excluding \macos) will be
loaded on demand from the standard certificate directories. If you do not
want to load root certificates on demand, you need to call either
@ -1384,6 +1395,10 @@ QList<QSslCipher> QSslSocket::supportedCiphers()
#endif // #if QT_DEPRECATED_SINCE(5, 5)
/*!
\deprecated
Use QSslConfiguration::addCaCertificates() instead.
Searches all files in the \a path for certificates encoded in the
specified \a format and adds them to this socket's CA certificate
database. \a path must be a file or a pattern matching one or more
@ -1411,6 +1426,10 @@ bool QSslSocket::addCaCertificates(const QString &path, QSsl::EncodingFormat for
}
/*!
\deprecated
Use QSslConfiguration::addCaCertificate() instead.
Adds the \a certificate to this socket's CA certificate database.
The CA certificate database is used by the socket during the
handshake phase to validate the peer's certificate.
@ -1427,6 +1446,10 @@ void QSslSocket::addCaCertificate(const QSslCertificate &certificate)
}
/*!
\deprecated
Use QSslConfiguration::addCaCertificates() instead.
Adds the \a certificates to this socket's CA certificate database.
The CA certificate database is used by the socket during the
handshake phase to validate the peer's certificate.
@ -1489,6 +1512,10 @@ QList<QSslCertificate> QSslSocket::caCertificates() const
#endif // #if QT_DEPRECATED_SINCE(5, 5)
/*!
\deprecated
Use QSslConfiguration::addCaCertificates() on the default QSslConfiguration instead.
Searches all files in the \a path for certificates with the
specified \a encoding and adds them to the default CA certificate
database. \a path can be an explicit file, or it can contain
@ -1498,8 +1525,8 @@ QList<QSslCertificate> QSslSocket::caCertificates() const
Each SSL socket's CA certificate database is initialized to the
default CA certificate database.
\sa QSslConfiguration::caCertificates(), addCaCertificates(),
addDefaultCaCertificate()
\sa QSslConfiguration::caCertificates(), QSslConfiguration::addCaCertificates(),
QSslConfiguration::addDefaultCaCertificate()
*/
bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat encoding,
QRegExp::PatternSyntax syntax)
@ -1508,11 +1535,15 @@ bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFor
}
/*!
\deprecated
Use QSslConfiguration::addCaCertificate() on the default QSslConfiguration instead.
Adds \a certificate to the default CA certificate database. Each
SSL socket's CA certificate database is initialized to the default
CA certificate database.
\sa QSslConfiguration::caCertificates(), addCaCertificates()
\sa QSslConfiguration::caCertificates(), QSslConfiguration::addCaCertificates()
*/
void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate)
{
@ -1520,11 +1551,15 @@ void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate)
}
/*!
\deprecated
Use QSslConfiguration::addCaCertificates() on the default QSslConfiguration instead.
Adds \a certificates to the default CA certificate database. Each
SSL socket's CA certificate database is initialized to the default
CA certificate database.
\sa QSslConfiguration::caCertificates(), addCaCertificates()
\sa QSslConfiguration::caCertificates(), QSslConfiguration::addCaCertificates()
*/
void QSslSocket::addDefaultCaCertificates(const QList<QSslCertificate> &certificates)
{

View File

@ -164,18 +164,22 @@ public:
#endif // QT_DEPRECATED_SINCE(5, 5)
// CA settings.
bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
#if QT_DEPRECATED_SINCE(5, 15)
QT_DEPRECATED_X("Use QSslConfiguration::addCaCertificates()") bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
QRegExp::PatternSyntax syntax = QRegExp::FixedString);
void addCaCertificate(const QSslCertificate &certificate);
void addCaCertificates(const QList<QSslCertificate> &certificates);
QT_DEPRECATED_X("Use QSslConfiguration::addCaCertificate()") void addCaCertificate(const QSslCertificate &certificate);
QT_DEPRECATED_X("Use QSslConfiguration::addCaCertificates()") void addCaCertificates(const QList<QSslCertificate> &certificates);
#endif // QT_DEPRECATED_SINCE(5, 15)
#if QT_DEPRECATED_SINCE(5, 5)
QT_DEPRECATED_X("Use QSslConfiguration::setCaCertificates()") void setCaCertificates(const QList<QSslCertificate> &certificates);
QT_DEPRECATED_X("Use QSslConfiguration::caCertificates()") QList<QSslCertificate> caCertificates() const;
#endif // QT_DEPRECATED_SINCE(5, 5)
static bool addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
#if QT_DEPRECATED_SINCE(5, 15)
QT_DEPRECATED static bool addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
QRegExp::PatternSyntax syntax = QRegExp::FixedString);
static void addDefaultCaCertificate(const QSslCertificate &certificate);
static void addDefaultCaCertificates(const QList<QSslCertificate> &certificates);
QT_DEPRECATED static void addDefaultCaCertificate(const QSslCertificate &certificate);
QT_DEPRECATED static void addDefaultCaCertificates(const QList<QSslCertificate> &certificates);
#endif // QT_DEPRECATED_SINCE(5, 15)
#if QT_DEPRECATED_SINCE(5, 5)
QT_DEPRECATED static void setDefaultCaCertificates(const QList<QSslCertificate> &certificates);
QT_DEPRECATED static QList<QSslCertificate> defaultCaCertificates();

View File

@ -1110,17 +1110,33 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
glyph_buffer.reset(new uchar[glyph_buffer_size]);
if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
Q_ASSERT(format == Format_Mono);
uchar *src = slot->bitmap.buffer;
uchar *dst = glyph_buffer.data();
int h = slot->bitmap.rows;
// Some fonts return bitmaps even when we requested something else:
if (format == Format_Mono) {
int bytes = ((info.width + 7) & ~7) >> 3;
while (h--) {
memcpy (dst, src, bytes);
dst += pitch;
src += slot->bitmap.pitch;
}
} else if (format == Format_A8) {
while (h--) {
for (int x = 0; x < int{info.width}; x++)
dst[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
dst += pitch;
src += slot->bitmap.pitch;
}
} else {
while (h--) {
uint *dd = reinterpret_cast<uint *>(dst);
for (int x = 0; x < int{info.width}; x++)
dd[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffffff : 0x00000000);
dst += pitch;
src += slot->bitmap.pitch;
}
}
} else if (slot->bitmap.pixel_mode == 7 /*FT_PIXEL_MODE_BGRA*/) {
Q_ASSERT(format == Format_ARGB);
uchar *src = slot->bitmap.buffer;

View File

@ -467,6 +467,14 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
if (fallbackList.isEmpty())
return fallbackList;
// .Apple Symbols Fallback will be at the beginning of the list and we will
// detect that this has glyphs for Arabic and other writing systems.
// Since it is a symbol font, it should be the last resort, so that
// the proper fonts for these writing systems are preferred.
int symbolIndex = fallbackList.indexOf(QLatin1String(".Apple Symbols Fallback"));
if (symbolIndex >= 0)
fallbackList.move(symbolIndex, fallbackList.size() - 1);
#if defined(Q_OS_MACOS)
// Since we are only returning a list of default fonts for the current language, we do not
// cover all Unicode completely. This was especially an issue for some of the common script
@ -481,6 +489,15 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
fallbackList.append(QStringLiteral("Apple Symbols"));
#endif
// Since iOS 13, the cascade list may contain meta-fonts which have not been
// populated to the database, such as ".AppleJapaneseFont". It is important that we
// include this in the fallback list, in order to get fallback support for all
// languages
for (const QString &fallback : fallbackList) {
if (!QPlatformFontDatabase::isFamilyPopulated(fallback))
const_cast<QCoreTextFontDatabase *>(this)->populateFamily(fallback);
}
extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &);
fallbackList = qt_sort_families_by_writing_system(script, fallbackList);

View File

@ -465,7 +465,8 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
return QStringList(QLatin1String("android"));
}
return QStringList(QLatin1String("fusion"));
case DialogButtonBoxLayout:
return QVariant(QPlatformDialogHelper::AndroidLayout);
case MouseDoubleClickDistance:
{
int minimumDistance = qEnvironmentVariableIntValue("QT_ANDROID_MINIMUM_MOUSE_DOUBLE_CLICK_DISTANCE");
@ -489,8 +490,6 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
Q_FALLTHROUGH();
}
case DialogButtonBoxLayout:
return QVariant(QPlatformDialogHelper::AndroidLayout);
default:
return QPlatformTheme::themeHint(hint);
}

View File

@ -881,7 +881,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
return;
}
int serial = serialNumber.load();
int serial = serialNumber.loadRelaxed();
if (!threadData->canWait || (serial != lastSerial)) {
lastSerial = serial;
QCoreApplication::sendPostedEvents();

View File

@ -43,9 +43,7 @@
- (void)initDrawing
{
self.wantsLayer = [self layerExplicitlyRequested]
|| [self shouldUseMetalLayer]
|| [self layerEnabledByMacOS];
[self updateLayerBacking];
// Enable high-DPI OpenGL for retina displays. Enabling has the side
// effect that Cocoa will start calling glViewport(0, 0, width, height),
@ -71,22 +69,13 @@
return YES;
}
- (void)drawRect:(NSRect)dirtyRect
// ----------------------- Layer setup -----------------------
- (void)updateLayerBacking
{
Q_UNUSED(dirtyRect);
if (!m_platformWindow)
return;
QRegion exposedRegion;
const NSRect *dirtyRects;
NSInteger numDirtyRects;
[self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
for (int i = 0; i < numDirtyRects; ++i)
exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
m_platformWindow->handleExposeEvent(exposedRegion);
self.wantsLayer = [self layerEnabledByMacOS]
|| [self layerExplicitlyRequested]
|| [self shouldUseMetalLayer];
}
- (BOOL)layerEnabledByMacOS
@ -123,40 +112,81 @@
return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
}
/*
This method is called by AppKit when layer-backing is requested by
setting wantsLayer too YES (via -[NSView _updateLayerBackedness]),
or in cases where AppKit itself decides that a view should be
layer-backed.
Note however that some code paths in AppKit will not go via this
method for creating the backing layer, and will instead create the
layer manually, and just call setLayer. An example of this is when
an NSOpenGLContext is attached to a view, in which case AppKit will
create a new layer in NSOpenGLContextSetLayerOnViewIfNecessary.
For this reason we leave the implementation of this override as
minimal as possible, only focusing on creating the appropriate
layer type, and then leave it up to setLayer to do the work of
making sure the layer is set up correctly.
*/
- (CALayer *)makeBackingLayer
{
if ([self shouldUseMetalLayer]) {
// Check if Metal is supported. If it isn't then it's most likely
// too late at this point and the QWindow will be non-functional,
// but we can at least print a warning.
if (![MTLCreateSystemDefaultDevice() autorelease]) {
qWarning() << "QWindow initialization error: Metal is not supported";
return [super makeBackingLayer];
if ([MTLCreateSystemDefaultDevice() autorelease]) {
return [CAMetalLayer layer];
} else {
qCWarning(lcQpaDrawing) << "Failed to create QWindow::MetalSurface."
<< "Metal is not supported by any of the GPUs in this system.";
}
CAMetalLayer *layer = [CAMetalLayer layer];
// Set the contentsScale for the layer. This is normally done in
// viewDidChangeBackingProperties, however on startup that function
// is called before the layer is created here. The layer's drawableSize
// is updated from layoutSublayersOfLayer as usual.
layer.contentsScale = self.window.backingScaleFactor;
return layer;
}
return [super makeBackingLayer];
}
/*
This method is called by AppKit whenever the view is asked to change
its layer, which can happen both as a result of enabling layer-backing,
or when a layer is set explicitly. The latter can happen both when a
view is layer-hosting, or when AppKit internals are switching out the
layer-backed view, as described above for makeBackingLayer.
*/
- (void)setLayer:(CALayer *)layer
{
qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
qCDebug(lcQpaDrawing) << "Making" << self
<< (self.wantsLayer ? "layer-backed" : "layer-hosted")
<< "with" << layer << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
[super setLayer:layer];
if (layer.delegate && layer.delegate != self) {
qCWarning(lcQpaDrawing) << "Layer already has delegate" << layer.delegate
<< "This delegate is responsible for all view updates for" << self;
} else {
layer.delegate = self;
}
[super setLayer:layer];
// When adding a view to a view hierarchy the backing properties will change
// which results in updating the contents scale, but in case of switching the
// layer on a view that's already in a view hierarchy we need to manually ensure
// the scale is up to date.
if (self.superview)
[self updateLayerContentsScale];
if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
// If the view claims to be opaque we expect it to fill the entire
// layer with content, in which case we want to detect any areas
// where it doesn't.
layer.backgroundColor = NSColor.magentaColor.CGColor;
}
}
// ----------------------- Layer updates -----------------------
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
{
// We need to set this explicitly since the super implementation
@ -164,17 +194,95 @@
return NSViewLayerContentsRedrawDuringViewResize;
}
#if 0 // Disabled until we enable lazy backingstore resizing
- (NSViewLayerContentsPlacement)layerContentsPlacement
{
// Always place the layer at top left without any automatic scaling,
// so that we can re-use larger layers when resizing a window down.
// Always place the layer at top left without any automatic scaling.
// This will highlight situations where we're missing content for the
// layer by not responding to the displayLayer: request synchronously.
// It also allows us to re-use larger layers when resizing a window down.
return NSViewLayerContentsPlacementTopLeft;
}
#endif
- (void)viewDidChangeBackingProperties
{
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
if (self.layer)
[self updateLayerContentsScale];
// Ideally we would plumb this situation through QPA in a way that lets
// clients invalidate their own caches, recreate QBackingStore, etc.
// For now we trigger an expose, and let QCocoaBackingStore deal with
// buffer invalidation internally.
[self setNeedsDisplay:YES];
}
- (void)updateLayerContentsScale
{
// We expect clients to fill the layer with retina aware content,
// based on the devicePixelRatio of the QWindow, so we set the
// layer's content scale to match that. By going via devicePixelRatio
// instead of applying the NSWindow's backingScaleFactor, we also take
// into account OpenGL views with wantsBestResolutionOpenGLSurface set
// to NO. In this case the window will have a backingScaleFactor of 2,
// but the QWindow will have a devicePixelRatio of 1.
auto devicePixelRatio = m_platformWindow->devicePixelRatio();
qCDebug(lcQpaDrawing) << "Updating" << self.layer << "content scale to" << devicePixelRatio;
self.layer.contentsScale = devicePixelRatio;
}
/*
This method is called by AppKit to determine whether it should update
the contentScale of the layer to match the window backing scale.
We always return NO since we're updating the contents scale manually.
*/
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window
{
Q_UNUSED(layer); Q_UNUSED(scale); Q_UNUSED(window);
return NO;
}
// ----------------------- Draw callbacks -----------------------
/*
This method is called by AppKit for the non-layer case, where we are
drawing into the NSWindow's surface.
*/
- (void)drawRect:(NSRect)dirtyBoundingRect
{
Q_ASSERT_X(!self.layer, "QNSView",
"The drawRect code path should not be hit when we are layer backed");
if (!m_platformWindow)
return;
QRegion exposedRegion;
const NSRect *dirtyRects;
NSInteger numDirtyRects;
[self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
for (int i = 0; i < numDirtyRects; ++i)
exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
if (exposedRegion.isEmpty())
exposedRegion = QRectF::fromCGRect(dirtyBoundingRect).toRect();
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
m_platformWindow->handleExposeEvent(exposedRegion);
}
/*
This method is called by AppKit when we are layer-backed, where
we are drawing into the layer.
*/
- (void)displayLayer:(CALayer *)layer
{
Q_ASSERT_X(self.layer && layer == self.layer, "QNSView",
"The displayLayer code path should only be hit for our own layer");
if (!m_platformWindow)
return;
if (!NSThread.isMainThread) {
// Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads,
// which we shouldn't do. This may result in AppKit (wrongly) triggering a display on
@ -184,29 +292,8 @@
return;
}
Q_ASSERT(layer == self.layer);
if (!m_platformWindow)
return;
qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
// FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
}
- (void)viewDidChangeBackingProperties
{
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
if (self.layer)
self.layer.contentsScale = self.window.backingScaleFactor;
// Ideally we would plumb this situation through QPA in a way that lets
// clients invalidate their own caches, recreate QBackingStore, etc.
// For now we trigger an expose, and let QCocoaBackingStore deal with
// buffer invalidation internally.
[self setNeedsDisplay:YES];
}
@end

View File

@ -891,13 +891,6 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current()
result.profile = QSurfaceFormat::CoreProfile;
else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
result.profile = QSurfaceFormat::CompatibilityProfile;
if (result.version < 0x0400)
return result;
// v4.0 onwards
value = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value);
if (value == LOSE_CONTEXT_ON_RESET_ARB)
result.options |= QSurfaceFormat::ResetNotification;
return result;
}
@ -975,6 +968,7 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
*/
#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
#define ROBUSTNESS_EXTENSION "GL_ARB_robustness"
QOpenGLStaticContext::QOpenGLStaticContext() :
vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)),
@ -995,9 +989,31 @@ QOpenGLStaticContext::QOpenGLStaticContext() :
wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))))
{
if (defaultFormat.version < 0x0300) {
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
extensions |= SampleBuffers;
if (extensionNames.startsWith(ROBUSTNESS_EXTENSION " ")
|| extensionNames.indexOf(" " ROBUSTNESS_EXTENSION " ") != -1)
extensions |= Robustness;
} else {
typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
auto glGetStringi = reinterpret_cast<glGetStringi_t>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
if (glGetStringi) {
GLint n = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (GLint i = 0; i < n; ++i) {
const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
if (p) {
if (!strcmp(p, SAMPLE_BUFFER_EXTENSION))
extensions |= SampleBuffers;
else if (!strcmp(p, ROBUSTNESS_EXTENSION))
extensions |= Robustness;
}
}
}
}
}
QByteArray QOpenGLStaticContext::getGlString(unsigned int which)
@ -1236,27 +1252,11 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval)
*obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt();
bool hasRobustness = false;
if (m_obtainedFormat.majorVersion() < 3) {
const char *exts = reinterpret_cast<const char *>(QOpenGLStaticContext::opengl32.glGetString(GL_EXTENSIONS));
hasRobustness = exts && strstr(exts, "GL_ARB_robustness");
} else {
typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
auto glGetStringi = reinterpret_cast<glGetStringi_t>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
if (glGetStringi) {
GLint n = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (GLint i = 0; i < n; ++i) {
const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
if (p && !strcmp(p, "GL_ARB_robustness")) {
hasRobustness = true;
break;
}
}
}
}
if (hasRobustness) {
if (testFlag(m_staticContext->extensions, QOpenGLStaticContext::Robustness)) {
GLint value = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value);
if (value == LOSE_CONTEXT_ON_RESET_ARB)
m_obtainedFormat.setOption(QSurfaceFormat::ResetNotification);
m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB")));
}

View File

@ -142,7 +142,8 @@ public:
enum Extensions
{
SampleBuffers = 0x1,
sRGBCapableFramebuffer = 0x2
sRGBCapableFramebuffer = 0x2,
Robustness = 0x4,
};
typedef bool

View File

@ -47,7 +47,6 @@
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qstandardpaths.h>
#include <QtCore/qlibrary.h>
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qhash.h>
@ -58,8 +57,6 @@
#include <QtCore/qt_windows.h>
#include <private/qsystemlibrary_p.h>
#include <d3d9.h>
#include <d3d10.h>
#include <dxgi.h>
QT_BEGIN_NAMESPACE
@ -83,50 +80,27 @@ static GpuDescription adapterIdentifierToGpuDescription(const D3DADAPTER_IDENTIF
return result;
}
class QGraphicsAdapterInfo
class QDirect3D9Handle
{
public:
Q_DISABLE_COPY_MOVE(QGraphicsAdapterInfo)
Q_DISABLE_COPY_MOVE(QDirect3D9Handle)
QGraphicsAdapterInfo();
~QGraphicsAdapterInfo();
QDirect3D9Handle();
~QDirect3D9Handle();
bool isValid() const;
bool isValid() const { return m_direct3D9 != nullptr; }
UINT adapterCount() const;
UINT adapterCount() const { return m_direct3D9 ? m_direct3D9->GetAdapterCount() : 0u; }
bool retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const;
private:
QSystemLibrary m_dxgilib;
IDXGIFactory1 *m_dxgiFactory1 = nullptr;
QSystemLibrary m_d3d9lib;
IDirect3D9 *m_direct3D9 = nullptr;
/* This is a value from the DXGI_ADAPTER_FLAG enum.
* However, it's not available in dxgi.h from MinGW,
* so define it here in any case. */
enum { DXGI_ADAPTER_FLAG_SOFTWARE = 2 };
UINT adapterCountDXGI() const;
bool retrieveAdapterIdentifierDXGI(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const;
UINT adapterCountD3D9() const;
bool retrieveAdapterIdentifierD3D9(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const;
};
QGraphicsAdapterInfo::QGraphicsAdapterInfo() :
m_dxgilib(QStringLiteral("dxgi")),
QDirect3D9Handle::QDirect3D9Handle() :
m_d3d9lib(QStringLiteral("d3d9"))
{
using PtrCreateDXGIFactory1 = HRESULT (WINAPI *)(REFIID, void**);
if (m_dxgilib.load()) {
if (auto createDXGIFactory1 = (PtrCreateDXGIFactory1)m_dxgilib.resolve("CreateDXGIFactory1"))
createDXGIFactory1(IID_PPV_ARGS(&m_dxgiFactory1));
}
if (!m_dxgiFactory1) {
using PtrDirect3DCreate9 = IDirect3D9 *(WINAPI *)(UINT);
if (m_d3d9lib.load()) {
@ -134,208 +108,24 @@ QGraphicsAdapterInfo::QGraphicsAdapterInfo() :
m_direct3D9 = direct3DCreate9(D3D_SDK_VERSION);
}
}
}
QGraphicsAdapterInfo::~QGraphicsAdapterInfo()
QDirect3D9Handle::~QDirect3D9Handle()
{
if (m_dxgiFactory1)
m_dxgiFactory1->Release();
if (m_direct3D9)
m_direct3D9->Release();
}
bool QGraphicsAdapterInfo::isValid() const
bool QDirect3D9Handle::retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const
{
return m_dxgiFactory1 != nullptr || m_direct3D9 != nullptr;
}
UINT QGraphicsAdapterInfo::adapterCount() const
{
if (m_dxgiFactory1)
return adapterCountDXGI();
if (m_direct3D9)
return adapterCountD3D9();
return 0;
}
bool QGraphicsAdapterInfo::retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const
{
if (m_dxgiFactory1)
return retrieveAdapterIdentifierDXGI(n, adapterIdentifier);
if (m_direct3D9)
return retrieveAdapterIdentifierD3D9(n, adapterIdentifier);
return false;
}
UINT QGraphicsAdapterInfo::adapterCountDXGI() const
{
/* DXGI doesn't have an adapterCount(), instead we have to call EnumAdapters1()
* until DXGI_ERROR_NOT_FOUND is returned. */
UINT n = 0;
IDXGIAdapter1 *adapter;
while (SUCCEEDED(m_dxgiFactory1->EnumAdapters1(n, &adapter))) {
adapter->Release();
++n;
}
return n;
}
// Detect whether we are running under 64-bit Windows.
static bool isWow64Process()
{
typedef BOOL (WINAPI *IsWow64ProcessPtr)(HANDLE hProcess, PBOOL Wow64Process);
IsWow64ProcessPtr IsWow64Process = (IsWow64ProcessPtr)QLibrary::resolve(
QStringLiteral("kernel32.dll"), "IsWow64Process");
if (IsWow64Process) {
BOOL IsWow64 = FALSE;
if (IsWow64Process(GetCurrentProcess(), &IsWow64))
return IsWow64;
}
return false;
}
// Read a string value from registry
static QString regGetString(HKEY key, const wchar_t* valueName)
{
QVarLengthArray<wchar_t, MAX_PATH> buf (MAX_PATH);
LRESULT res;
DWORD bufSize = buf.size() * sizeof(wchar_t);
res = RegGetValue(key, nullptr, valueName,
RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ, nullptr,
buf.data(), &bufSize);
if (res == ERROR_MORE_DATA) {
buf.resize(bufSize / sizeof(wchar_t));
bufSize = buf.size() * sizeof(wchar_t);
res = RegGetValue(key, nullptr, valueName,
RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ, nullptr,
buf.data(), &bufSize);
}
/* In case of REG_MULTI_SZ, this returns just the first string,
* but that is sufficient for our purposes. */
if (res == ERROR_SUCCESS)
return QString::fromWCharArray(buf.data());
return QString();
}
// Read driver name given a DeviceKey
static QString retrieveDriverName(const wchar_t *driverKey)
{
/* Kernel-style prefix, maps to HKLM
* (see https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/registry-key-object-routines) */
static const wchar_t prefixMappingHKLM[] = L"\\Registry\\Machine\\";
const size_t prefixMappingHKLMLen = wcslen(prefixMappingHKLM);
if (wcsnicmp(driverKey, prefixMappingHKLM, prefixMappingHKLMLen) != 0)
return QString();
driverKey += prefixMappingHKLMLen;
QString driverPath;
HKEY key;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, driverKey, 0, KEY_READ | KEY_WOW64_64KEY, &key) == ERROR_SUCCESS) {
const wchar_t *valueName =
isWow64Process() ? L"UserModeDriverNameWow" : L"UserModeDriverName";
driverPath = regGetString(key, valueName);
RegCloseKey(key);
}
if (!driverPath.isEmpty()) {
int fileNameSep = driverPath.lastIndexOf(QLatin1Char('\\'));
if (fileNameSep >= 0)
driverPath = driverPath.mid(fileNameSep + 1);
return driverPath;
}
return QString();
}
// Retrieve driver name for a display device from registry.
static QString driverNameForDevice(const wchar_t *displayDevice)
{
QString driverName;
DISPLAY_DEVICE dd;
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
for (int dev = 0; EnumDisplayDevices(nullptr, dev, &dd, 0); ++dev) {
if (wcsicmp(displayDevice, dd.DeviceName) == 0) {
// DeviceKey is documented as "internal", but it's a registry key in kernel format
driverName = retrieveDriverName(dd.DeviceKey);
break;
}
}
if (driverName.isEmpty()) {
/* Fall back to driver name from EnumDisplaySettings.
* This is only a fallback as on Windows 10 this just returns an device-independent
* name. OTOH, it's possible to recognize RDP connections from the driver name. */
DEVMODE devMode;
if (EnumDisplaySettings(displayDevice, ENUM_CURRENT_SETTINGS, &devMode))
driverName = QString::fromWCharArray(devMode.dmDeviceName);
}
return driverName;
}
bool QGraphicsAdapterInfo::retrieveAdapterIdentifierDXGI(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const
{
IDXGIAdapter1 *adapter;
if (FAILED(m_dxgiFactory1->EnumAdapters1(n, &adapter)))
return false;
bool result = false;
DXGI_ADAPTER_DESC1 adapterDesc;
if (SUCCEEDED(adapter->GetDesc1(&adapterDesc))) {
if ((adapterDesc.VendorId != 0) && (adapterDesc.DeviceId != 0) // Don't use adapter description of Software Devices
&& ((adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0)) {
memset(adapterIdentifier, 0, sizeof(*adapterIdentifier));
WideCharToMultiByte(1252, 0, adapterDesc.Description, -1,
adapterIdentifier->Description,
sizeof(adapterIdentifier->Description), nullptr, nullptr);
adapterIdentifier->Description[sizeof(adapterIdentifier->Description) - 1] = 0;
adapterIdentifier->VendorId = adapterDesc.VendorId;
adapterIdentifier->DeviceId = adapterDesc.DeviceId;
adapterIdentifier->SubSysId = adapterDesc.SubSysId;
adapterIdentifier->Revision = adapterDesc.Revision;
LARGE_INTEGER umdVersion;
if (SUCCEEDED(adapter->CheckInterfaceSupport(__uuidof(ID3D10Device), &umdVersion))) {
adapterIdentifier->DriverVersion = umdVersion;
result = true;
}
/* DXGI doesn't expose the driver name, but we can get it from the registry.
* But we need a device name to follow. */
IDXGIOutput *output = nullptr;
if (SUCCEEDED(adapter->EnumOutputs (0, &output))) {
DXGI_OUTPUT_DESC outputDesc;
if (SUCCEEDED(output->GetDesc (&outputDesc))) {
QString driverName = driverNameForDevice(outputDesc.DeviceName);
qstrncpy(adapterIdentifier->Driver, driverName.toLatin1().constData(),
sizeof(adapterIdentifier->Driver));
}
output->Release();
}
}
}
adapter->Release();
return result;
}
UINT QGraphicsAdapterInfo::adapterCountD3D9() const
{
return m_direct3D9->GetAdapterCount();
}
bool QGraphicsAdapterInfo::retrieveAdapterIdentifierD3D9(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const
{
return SUCCEEDED(m_direct3D9->GetAdapterIdentifier(n, 0, adapterIdentifier));
return m_direct3D9
&& SUCCEEDED(m_direct3D9->GetAdapterIdentifier(n, 0, adapterIdentifier));
}
GpuDescription GpuDescription::detect()
{
GpuDescription result;
QGraphicsAdapterInfo adapterInfo;
if (!adapterInfo.isValid())
QDirect3D9Handle direct3D9;
if (!direct3D9.isValid())
return result;
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
@ -346,7 +136,7 @@ GpuDescription GpuDescription::detect()
// and D3D uses by default. Therefore querying any additional adapters is
// futile and not useful for our purposes in general, except for
// identifying a few special cases later on.
if (adapterInfo.retrieveAdapterIdentifier(0, &adapterIdentifier)) {
if (direct3D9.retrieveAdapterIdentifier(0, &adapterIdentifier)) {
result = adapterIdentifierToGpuDescription(adapterIdentifier);
isAMD = result.vendorId == VENDOR_ID_AMD;
}
@ -355,9 +145,9 @@ GpuDescription GpuDescription::detect()
// when starting apps on a screen connected to the Intel card) by looking
// for a default AMD adapter and an additional non-AMD one.
if (isAMD) {
const UINT adapterCount = adapterInfo.adapterCount();
const UINT adapterCount = direct3D9.adapterCount();
for (UINT adp = 1; adp < adapterCount; ++adp) {
if (adapterInfo.retrieveAdapterIdentifier(adp, &adapterIdentifier)
if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier)
&& adapterIdentifier.VendorId != VENDOR_ID_AMD) {
// Bingo. Now figure out the display for the AMD card.
DISPLAY_DEVICE dd;
@ -382,11 +172,11 @@ GpuDescription GpuDescription::detect()
QVector<GpuDescription> GpuDescription::detectAll()
{
QVector<GpuDescription> result;
QGraphicsAdapterInfo adapterInfo;
if (const UINT adapterCount = adapterInfo.adapterCount()) {
QDirect3D9Handle direct3D9;
if (const UINT adapterCount = direct3D9.adapterCount()) {
for (UINT adp = 0; adp < adapterCount; ++adp) {
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
if (adapterInfo.retrieveAdapterIdentifier(adp, &adapterIdentifier))
if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier))
result.append(adapterIdentifierToGpuDescription(adapterIdentifier));
}
}

View File

@ -2697,12 +2697,18 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
return true;
}
if (localPos.y() < 0) {
const int topResizeBarPos = -frameMargins().top();
if (localPos.y() >= topResizeBarPos)
// We want to return HTCAPTION/true only over the outer sizing frame, not the entire title bar,
// otherwise the title bar buttons (close, etc.) become unresponsive on Windows 7 (QTBUG-78262).
// However, neither frameMargins() nor GetSystemMetrics(SM_CYSIZEFRAME), etc., give the correct
// sizing frame height in all Windows versions/scales. This empirical constant seems to work, though.
const int sizingHeight = 9;
const int topResizeBarPos = sizingHeight - frameMargins().top();
if (localPos.y() < topResizeBarPos) {
*result = HTCAPTION; // Extend caption over top resize bar, let's user move the window.
return true;
}
}
}
if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) {
*result = HTBORDER; // Unspecified border, no resize cursor.
return true;

View File

@ -12,8 +12,6 @@ LIBS += -lshlwapi -lwtsapi32
QMAKE_USE_PRIVATE += \
advapi32 \
d3d9/nolink \
d3d11/nolink \
dxgi/nolink \
ole32 \
shell32 \
user32 \

View File

@ -79,7 +79,7 @@ QSqlDatabase db = QSqlDatabase::addDatabase("MYDRIVER");
//! [3]
...
db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myaccessfile.mdb");
db.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};FIL={MS Access};DBQ=myaccessfile.mdb");
if (db.open()) {
// success!
}

View File

@ -59,6 +59,7 @@
#include <QtCore/qtemporarydir.h>
#include <QtCore/qthread.h>
#include <QtCore/private/qlocking_p.h>
#include <QtCore/private/qwaitcondition_p.h>
#include <QtCore/qtestsupport_core.h>
@ -1017,15 +1018,15 @@ class WatchDog : public QThread
ThreadEnd,
};
bool waitFor(std::unique_lock<std::mutex> &m, Expectation e) {
auto expectation = [this, e] { return expecting != e; };
bool waitFor(std::unique_lock<QtPrivate::mutex> &m, Expectation e) {
auto expectationChanged = [this, e] { return expecting != e; };
switch (e) {
case TestFunctionEnd:
return waitCondition.wait_for(m, defaultTimeout(), expectation);
return waitCondition.wait_for(m, defaultTimeout(), expectationChanged);
case ThreadStart:
case ThreadEnd:
case TestFunctionStart:
waitCondition.wait(m, expectation);
waitCondition.wait(m, expectationChanged);
return true;
}
Q_UNREACHABLE();
@ -1035,7 +1036,7 @@ class WatchDog : public QThread
public:
WatchDog()
{
std::unique_lock<std::mutex> locker(mutex);
auto locker = qt_unique_lock(mutex);
expecting = ThreadStart;
start();
waitFor(locker, ThreadStart);
@ -1062,7 +1063,7 @@ public:
}
void run() override {
std::unique_lock<std::mutex> locker(mutex);
auto locker = qt_unique_lock(mutex);
expecting = TestFunctionStart;
waitCondition.notify_all();
while (true) {
@ -1082,8 +1083,8 @@ public:
}
private:
std::mutex mutex;
std::condition_variable waitCondition;
QtPrivate::mutex mutex;
QtPrivate::condition_variable waitCondition;
Expectation expecting;
};
@ -2804,8 +2805,11 @@ template <> Q_TESTLIB_EXPORT char *QTest::toString<char>(const char &t)
*/
char *QTest::toString(const char *str)
{
if (!str)
return nullptr;
if (!str) {
char *msg = new char[1];
*msg = '\0';
return msg;
}
char *msg = new char[strlen(str) + 1];
return qstrcpy(msg, str);
}

View File

@ -55,10 +55,14 @@
#if QT_CONFIG(lineedit)
#include "qlineedit.h"
#endif
#include <qpointer.h>
#include "qpainter.h"
#include "qwindow.h"
#include "qpushbutton.h"
#include "qset.h"
#if QT_CONFIG(shortcut)
# include "qshortcut.h"
#endif
#include "qstyle.h"
#include "qvarlengtharray.h"
#if defined(Q_OS_MACX)
@ -232,31 +236,24 @@ void QWizardField::findProperty(const QWizardDefaultProperty *properties, int pr
class QWizardLayoutInfo
{
public:
inline QWizardLayoutInfo()
: topLevelMarginLeft(-1), topLevelMarginRight(-1), topLevelMarginTop(-1),
topLevelMarginBottom(-1), childMarginLeft(-1), childMarginRight(-1),
childMarginTop(-1), childMarginBottom(-1), hspacing(-1), vspacing(-1),
wizStyle(QWizard::ClassicStyle), header(false), watermark(false), title(false),
subTitle(false), extension(false), sideWidget(false) {}
int topLevelMarginLeft;
int topLevelMarginRight;
int topLevelMarginTop;
int topLevelMarginBottom;
int childMarginLeft;
int childMarginRight;
int childMarginTop;
int childMarginBottom;
int hspacing;
int vspacing;
int buttonSpacing;
QWizard::WizardStyle wizStyle;
bool header;
bool watermark;
bool title;
bool subTitle;
bool extension;
bool sideWidget;
int topLevelMarginLeft = -1;
int topLevelMarginRight = -1;
int topLevelMarginTop = -1;
int topLevelMarginBottom = -1;
int childMarginLeft = -1;
int childMarginRight = -1;
int childMarginTop = -1;
int childMarginBottom = -1;
int hspacing = -1;
int vspacing = -1;
int buttonSpacing = -1;
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
bool header = false;
bool watermark = false;
bool title = false;
bool subTitle = false;
bool extension = false;
bool sideWidget = false;
bool operator==(const QWizardLayoutInfo &other);
inline bool operator!=(const QWizardLayoutInfo &other) { return !operator==(other); }
@ -486,21 +483,18 @@ class QWizardPagePrivate : public QWidgetPrivate
public:
enum TriState { Tri_Unknown = -1, Tri_False, Tri_True };
inline QWizardPagePrivate()
: wizard(0), completeState(Tri_Unknown), explicitlyFinal(false), commit(false) {}
bool cachedIsComplete() const;
void _q_maybeEmitCompleteChanged();
void _q_updateCachedCompleteState();
QWizard *wizard;
QWizard *wizard = nullptr;
QString title;
QString subTitle;
QPixmap pixmaps[QWizard::NPixmaps];
QVector<QWizardField> pendingFields;
mutable TriState completeState;
bool explicitlyFinal;
bool commit;
mutable TriState completeState = Tri_Unknown;
bool explicitlyFinal = false;
bool commit = false;
bool initialized = false;
QMap<int, QString> buttonCustomTexts;
};
@ -556,42 +550,6 @@ public:
Forward
};
inline QWizardPrivate()
: start(-1)
, startSetByUser(false)
, current(-1)
, canContinue(false)
, canFinish(false)
, disableUpdatesCount(0)
, wizStyle(QWizard::ClassicStyle)
, opts(0)
, buttonsHaveCustomLayout(false)
, titleFmt(Qt::AutoText)
, subTitleFmt(Qt::AutoText)
, placeholderWidget1(0)
, placeholderWidget2(0)
, headerWidget(0)
, watermarkLabel(0)
, sideWidget(0)
, pageFrame(0)
, titleLabel(0)
, subTitleLabel(0)
, bottomRuler(0)
#if QT_CONFIG(style_windowsvista)
, vistaHelper(0)
, vistaInitPending(true)
, vistaState(QVistaHelper::Dirty)
, vistaStateChanged(false)
, inHandleAeroStyleChange(false)
#endif
, minimumWidth(0)
, minimumHeight(0)
, maximumWidth(QWIDGETSIZE_MAX)
, maximumHeight(QWIDGETSIZE_MAX)
{
std::fill(btns, btns + QWizard::NButtons, static_cast<QAbstractButton *>(0));
}
void init();
void reset();
void cleanupPagesNotInHistory();
@ -631,21 +589,21 @@ public:
QMap<QString, int> fieldIndexMap;
QVector<QWizardDefaultProperty> defaultPropertyTable;
QList<int> history;
int start;
bool startSetByUser;
int current;
bool canContinue;
bool canFinish;
int start = -1;
bool startSetByUser = false;
int current = -1;
bool canContinue = false;
bool canFinish = false;
QWizardLayoutInfo layoutInfo;
int disableUpdatesCount;
int disableUpdatesCount = 0;
QWizard::WizardStyle wizStyle;
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
QWizard::WizardOptions opts;
QMap<int, QString> buttonCustomTexts;
bool buttonsHaveCustomLayout;
bool buttonsHaveCustomLayout = false;
QList<QWizard::WizardButton> buttonsCustomLayout;
Qt::TextFormat titleFmt;
Qt::TextFormat subTitleFmt;
Qt::TextFormat titleFmt = Qt::AutoText;
Qt::TextFormat subTitleFmt = Qt::AutoText;
mutable QPixmap defaultPixmaps[QWizard::NPixmaps];
union {
@ -660,32 +618,35 @@ public:
} btn;
mutable QAbstractButton *btns[QWizard::NButtons];
};
QWizardAntiFlickerWidget *antiFlickerWidget;
QWidget *placeholderWidget1;
QWidget *placeholderWidget2;
QWizardHeader *headerWidget;
QWatermarkLabel *watermarkLabel;
QWidget *sideWidget;
QFrame *pageFrame;
QLabel *titleLabel;
QLabel *subTitleLabel;
QWizardRuler *bottomRuler;
QWizardAntiFlickerWidget *antiFlickerWidget = nullptr;
QWidget *placeholderWidget1 = nullptr;
QWidget *placeholderWidget2 = nullptr;
QWizardHeader *headerWidget = nullptr;
QWatermarkLabel *watermarkLabel = nullptr;
QWidget *sideWidget = nullptr;
QFrame *pageFrame = nullptr;
QLabel *titleLabel = nullptr;
QLabel *subTitleLabel = nullptr;
QWizardRuler *bottomRuler = nullptr;
QVBoxLayout *pageVBoxLayout;
QHBoxLayout *buttonLayout;
QGridLayout *mainLayout;
QVBoxLayout *pageVBoxLayout = nullptr;
QHBoxLayout *buttonLayout = nullptr;
QGridLayout *mainLayout = nullptr;
#if QT_CONFIG(style_windowsvista)
QVistaHelper *vistaHelper;
bool vistaInitPending;
QVistaHelper::VistaState vistaState;
bool vistaStateChanged;
bool inHandleAeroStyleChange;
QVistaHelper *vistaHelper = nullptr;
# if QT_CONFIG(shortcut)
QPointer<QShortcut> vistaNextShortcut;
# endif
int minimumWidth;
int minimumHeight;
int maximumWidth;
int maximumHeight;
bool vistaInitPending = true;
QVistaHelper::VistaState vistaState = QVistaHelper::Dirty;
bool vistaStateChanged = false;
bool inHandleAeroStyleChange = false;
#endif
int minimumWidth = 0;
int minimumHeight = 0;
int maximumWidth = QWIDGETSIZE_MAX;
int maximumHeight = QWIDGETSIZE_MAX;
};
static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
@ -720,6 +681,8 @@ void QWizardPrivate::init()
{
Q_Q(QWizard);
std::fill(btns, btns + QWizard::NButtons, nullptr);
antiFlickerWidget = new QWizardAntiFlickerWidget(q, this);
wizStyle = QWizard::WizardStyle(q->style()->styleHint(QStyle::SH_WizardStyle, 0, q));
if (wizStyle == QWizard::MacStyle) {
@ -1461,10 +1424,17 @@ void QWizardPrivate::updateButtonTexts()
// Vista: Add shortcut for 'next'. Note: native dialogs use ALT-Right
// even in RTL mode, so do the same, even if it might be counter-intuitive.
// The shortcut for 'back' is set in class QVistaBackButton.
#if QT_CONFIG(shortcut)
if (btns[QWizard::NextButton] && isVistaThemeEnabled())
btns[QWizard::NextButton]->setShortcut(QKeySequence(Qt::ALT | Qt::Key_Right));
#endif
#if QT_CONFIG(shortcut) && QT_CONFIG(style_windowsvista)
if (btns[QWizard::NextButton] && isVistaThemeEnabled()) {
if (vistaNextShortcut.isNull()) {
vistaNextShortcut =
new QShortcut(QKeySequence(Qt::ALT | Qt::Key_Right),
btns[QWizard::NextButton], SLOT(animateClick()));
}
} else {
delete vistaNextShortcut;
}
#endif // shortcut && style_windowsvista
}
void QWizardPrivate::updateButtonLayout()

Some files were not shown because too many files have changed in this diff Show More