Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: Ideaa64d583746f1ce8265997131fb1ce3a9acbcf
This commit is contained in:
commit
4c8814a341
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
@ -144,7 +138,7 @@ void TriangleWindow::render()
|
||||
m_program->bind();
|
||||
|
||||
QMatrix4x4 matrix;
|
||||
matrix.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f);
|
||||
matrix.perspective(60.0f, 4.0f / 3.0f, 0.1f, 100.0f);
|
||||
matrix.translate(0, 0, -2);
|
||||
matrix.rotate(100.0f * m_frame / screen()->refreshRate(), 0, 1, 0);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
delete m_texImageTmp;
|
||||
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;
|
||||
}
|
||||
delete m_texImageProcessed;
|
||||
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;
|
||||
}
|
||||
delete m_shaderDisplay;
|
||||
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;
|
||||
}
|
||||
delete m_shaderComputeV;
|
||||
m_shaderComputeV = new QOpenGLShaderProgram;
|
||||
m_shaderComputeV->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceV));
|
||||
m_shaderComputeV->link();
|
||||
|
||||
if (m_shaderComputeH) {
|
||||
delete m_shaderComputeH;
|
||||
m_shaderComputeH = 0;
|
||||
}
|
||||
delete m_shaderComputeH;
|
||||
m_shaderComputeH = new QOpenGLShaderProgram;
|
||||
m_shaderComputeH->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceH));
|
||||
m_shaderComputeH->link();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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]
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include <qmath.h>
|
||||
|
||||
Logo::Logo()
|
||||
: m_count(0)
|
||||
{
|
||||
m_data.resize(2500 * 6);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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."));
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
delete m_program;
|
||||
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;
|
||||
}
|
||||
delete m_vao;
|
||||
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();
|
||||
|
@ -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
|
||||
|
@ -57,15 +57,13 @@ 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;
|
||||
delete cache;
|
||||
cache = new QImage(qRound(radius * 2 + 2), qRound(radius * 2 + 2), QImage::Format_ARGB32_Premultiplied);
|
||||
cache->fill(0x00000000);
|
||||
QPainter p(cache);
|
||||
@ -80,8 +78,7 @@ void Bubble::updateCache()
|
||||
|
||||
Bubble::~Bubble()
|
||||
{
|
||||
if (cache)
|
||||
delete cache;
|
||||
delete cache;
|
||||
}
|
||||
|
||||
void Bubble::updateBrush()
|
||||
|
@ -80,7 +80,7 @@ private:
|
||||
qreal radius;
|
||||
QColor innerColor;
|
||||
QColor outerColor;
|
||||
QImage *cache;
|
||||
QImage *cache = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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)))
|
||||
|
@ -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)))
|
||||
|
@ -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)))
|
||||
|
@ -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)))
|
||||
|
41
mkspecs/devices/linux-imx8-g++/qmake.conf
Normal file
41
mkspecs/devices/linux-imx8-g++/qmake.conf
Normal 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)
|
40
mkspecs/devices/linux-imx8-g++/qplatformdefs.h
Normal file
40
mkspecs/devices/linux-imx8-g++/qplatformdefs.h
Normal 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"
|
@ -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
|
||||
}
|
||||
|
||||
|
7
mkspecs/features/mac/no_warn_empty_obj_files.prf
Normal file
7
mkspecs/features/mac/no_warn_empty_obj_files.prf
Normal 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
|
@ -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 \
|
||||
|
@ -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
|
||||
|
42
src/3rdparty/sqlite/patches/0001-Fix-CVE-2019-16168-in-SQLite.patch
vendored
Normal file
42
src/3rdparty/sqlite/patches/0001-Fix-CVE-2019-16168-in-SQLite.patch
vendored
Normal 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)
|
||||
|
4
src/3rdparty/sqlite/qt_attribution.json
vendored
4
src/3rdparty/sqlite/qt_attribution.json
vendored
@ -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."
|
||||
}
|
||||
|
7134
src/3rdparty/sqlite/sqlite3.c
vendored
7134
src/3rdparty/sqlite/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
53
src/3rdparty/sqlite/sqlite3.h
vendored
53
src/3rdparty/sqlite/sqlite3.h
vendored
@ -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
|
||||
|
@ -416,7 +416,7 @@ public:
|
||||
LoadArchiveMemberHint = 0x04
|
||||
};
|
||||
Q_DECLARE_FLAGS(LoadHints, LoadHint)
|
||||
Q_FLAG(LoadHints)
|
||||
Q_FLAG(LoadHint)
|
||||
...
|
||||
}
|
||||
//! [39]
|
||||
|
@ -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)
|
||||
|
@ -107,10 +107,51 @@ QT_BEGIN_NAMESPACE
|
||||
*/
|
||||
|
||||
/*!
|
||||
\internal
|
||||
Implements qFpClassify() for qfloat16.
|
||||
*/
|
||||
\internal
|
||||
\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
|
||||
|
@ -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,12 +2206,36 @@ 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();
|
||||
const qint16 major = osv.wServicePackMajor;
|
||||
if (major) {
|
||||
QString sp = QStringLiteral(" SP ") + QString::number(major);
|
||||
QString sp = QStringLiteral("SP ") + QString::number(major);
|
||||
const qint16 minor = osv.wServicePackMinor;
|
||||
if (minor)
|
||||
sp += QLatin1Char('.') + QString::number(minor);
|
||||
@ -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 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 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('.')
|
||||
+ QString::number(version.minorVersion());
|
||||
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)
|
||||
|
@ -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.
|
||||
|
@ -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)())
|
||||
#define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
# define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
|
||||
#endif
|
||||
#define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
153
src/corelib/thread/qwaitcondition_p.h
Normal file
153
src/corelib/thread/qwaitcondition_p.h
Normal 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 */
|
@ -6,6 +6,7 @@ HEADERS += \
|
||||
thread/qrunnable.h \
|
||||
thread/qthread.h \
|
||||
thread/qthreadstorage.h \
|
||||
thread/qwaitcondition_p.h \
|
||||
thread/qwaitcondition.h
|
||||
|
||||
SOURCES += \
|
||||
|
@ -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:
|
||||
|
||||
/*!
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,9 +3939,16 @@ bool QD3D11SwapChain::buildOrResize()
|
||||
m_depthStencil->sampleCount(), m_sampleCount);
|
||||
}
|
||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
||||
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_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;
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
[cbD->d->currentRenderPassEncoder setCullMode: psD->d->cullMode];
|
||||
[cbD->d->currentRenderPassEncoder setFrontFacingWinding: psD->d->winding];
|
||||
|
||||
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,9 +3608,16 @@ bool QMetalSwapChain::buildOrResize()
|
||||
m_depthStencil->sampleCount(), m_sampleCount);
|
||||
}
|
||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
||||
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());
|
||||
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;
|
||||
|
@ -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();
|
||||
|
@ -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,9 +6314,16 @@ bool QVkSwapChain::buildOrResize()
|
||||
m_depthStencil->sampleCount(), m_sampleCount);
|
||||
}
|
||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
||||
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_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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -1110,16 +1110,32 @@ 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;
|
||||
|
||||
int bytes = ((info.width + 7) & ~7) >> 3;
|
||||
while (h--) {
|
||||
memcpy (dst, src, bytes);
|
||||
dst += pitch;
|
||||
src += slot->bitmap.pitch;
|
||||
// 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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
||||
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];
|
||||
layer.delegate = self;
|
||||
|
||||
// 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
|
||||
|
@ -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 (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|
||||
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
|
||||
extensions |= SampleBuffers;
|
||||
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")));
|
||||
}
|
||||
|
@ -142,7 +142,8 @@ public:
|
||||
enum Extensions
|
||||
{
|
||||
SampleBuffers = 0x1,
|
||||
sRGBCapableFramebuffer = 0x2
|
||||
sRGBCapableFramebuffer = 0x2,
|
||||
Robustness = 0x4,
|
||||
};
|
||||
|
||||
typedef bool
|
||||
|
@ -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,259 +80,52 @@ 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**);
|
||||
using PtrDirect3DCreate9 = IDirect3D9 *(WINAPI *)(UINT);
|
||||
|
||||
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()) {
|
||||
if (auto direct3DCreate9 = (PtrDirect3DCreate9)m_d3d9lib.resolve("Direct3DCreate9"))
|
||||
m_direct3D9 = direct3DCreate9(D3D_SDK_VERSION);
|
||||
}
|
||||
if (m_d3d9lib.load()) {
|
||||
if (auto direct3DCreate9 = (PtrDirect3DCreate9)m_d3d9lib.resolve("Direct3DCreate9"))
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -2697,10 +2697,16 @@ 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;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) {
|
||||
|
@ -12,8 +12,6 @@ LIBS += -lshlwapi -lwtsapi32
|
||||
QMAKE_USE_PRIVATE += \
|
||||
advapi32 \
|
||||
d3d9/nolink \
|
||||
d3d11/nolink \
|
||||
dxgi/nolink \
|
||||
ole32 \
|
||||
shell32 \
|
||||
user32 \
|
||||
|
@ -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!
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
bool vistaInitPending = true;
|
||||
QVistaHelper::VistaState vistaState = QVistaHelper::Dirty;
|
||||
bool vistaStateChanged = false;
|
||||
bool inHandleAeroStyleChange = false;
|
||||
#endif
|
||||
int minimumWidth;
|
||||
int minimumHeight;
|
||||
int maximumWidth;
|
||||
int maximumHeight;
|
||||
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
Loading…
Reference in New Issue
Block a user